Commit 2e8ecb9db0bcc19e1cc8bb51e9252fe6a86a9863
Committed by
Linus Torvalds
1 parent
430d275a39
Exists in
master
and in
7 other branches
add CONFIG_VT_UNICODE
As of now, the kernel defaults to non-unicode and XLATE for the keyboard. We've been changing this in Fedora, but that requires patching the defaults in the kernel. The attached introduces CONFIG_VT_UNICODE, which sets the console in unicode mode by default on boot, including both the virtual terminal and the keyboard driver. Signed-off-by: Bill Nottingham <notting@redhat.com> Cc: Samuel Thibault <samuel.thibault@ens-lyon.org> Cc: Dmitry Torokhov <dtor@mail.ru> Cc: Jiri Kosina <jkosina@suse.cz> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 6 changed files with 27 additions and 5 deletions Inline Diff
drivers/char/Kconfig
1 | # | 1 | # |
2 | # Character device configuration | 2 | # Character device configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "Character devices" | 5 | menu "Character devices" |
6 | 6 | ||
7 | config VT | 7 | config VT |
8 | bool "Virtual terminal" if EMBEDDED | 8 | bool "Virtual terminal" if EMBEDDED |
9 | depends on !S390 | 9 | depends on !S390 |
10 | select INPUT | 10 | select INPUT |
11 | default y if !VIOCONS | 11 | default y if !VIOCONS |
12 | ---help--- | 12 | ---help--- |
13 | If you say Y here, you will get support for terminal devices with | 13 | If you say Y here, you will get support for terminal devices with |
14 | display and keyboard devices. These are called "virtual" because you | 14 | display and keyboard devices. These are called "virtual" because you |
15 | can run several virtual terminals (also called virtual consoles) on | 15 | can run several virtual terminals (also called virtual consoles) on |
16 | one physical terminal. This is rather useful, for example one | 16 | one physical terminal. This is rather useful, for example one |
17 | virtual terminal can collect system messages and warnings, another | 17 | virtual terminal can collect system messages and warnings, another |
18 | one can be used for a text-mode user session, and a third could run | 18 | one can be used for a text-mode user session, and a third could run |
19 | an X session, all in parallel. Switching between virtual terminals | 19 | an X session, all in parallel. Switching between virtual terminals |
20 | is done with certain key combinations, usually Alt-<function key>. | 20 | is done with certain key combinations, usually Alt-<function key>. |
21 | 21 | ||
22 | The setterm command ("man setterm") can be used to change the | 22 | The setterm command ("man setterm") can be used to change the |
23 | properties (such as colors or beeping) of a virtual terminal. The | 23 | properties (such as colors or beeping) of a virtual terminal. The |
24 | man page console_codes(4) ("man console_codes") contains the special | 24 | man page console_codes(4) ("man console_codes") contains the special |
25 | character sequences that can be used to change those properties | 25 | character sequences that can be used to change those properties |
26 | directly. The fonts used on virtual terminals can be changed with | 26 | directly. The fonts used on virtual terminals can be changed with |
27 | the setfont ("man setfont") command and the key bindings are defined | 27 | the setfont ("man setfont") command and the key bindings are defined |
28 | with the loadkeys ("man loadkeys") command. | 28 | with the loadkeys ("man loadkeys") command. |
29 | 29 | ||
30 | You need at least one virtual terminal device in order to make use | 30 | You need at least one virtual terminal device in order to make use |
31 | of your keyboard and monitor. Therefore, only people configuring an | 31 | of your keyboard and monitor. Therefore, only people configuring an |
32 | embedded system would want to say N here in order to save some | 32 | embedded system would want to say N here in order to save some |
33 | memory; the only way to log into such a system is then via a serial | 33 | memory; the only way to log into such a system is then via a serial |
34 | or network connection. | 34 | or network connection. |
35 | 35 | ||
36 | If unsure, say Y, or else you won't be able to do much with your new | 36 | If unsure, say Y, or else you won't be able to do much with your new |
37 | shiny Linux system :-) | 37 | shiny Linux system :-) |
38 | 38 | ||
39 | config VT_UNICODE | ||
40 | bool "Virtual console is Unicode by default" | ||
41 | depends on VT | ||
42 | default n | ||
43 | ---help--- | ||
44 | If you say Y here, the virtual terminal will be in UTF-8 by default, | ||
45 | and the keyboard will run in unicode mode. | ||
46 | |||
47 | If you say N here, the virtual terminal will not be in UTF-8 by | ||
48 | default, and the keyboard will run in XLATE mode. | ||
49 | |||
50 | This can also be changed by passing 'default_utf8=<0|1>' on the | ||
51 | kernel command line. | ||
52 | |||
53 | Historically, the kernel has defaulted to non-UTF8 and XLATE mode. | ||
54 | If unsure, say N here. | ||
55 | |||
39 | config VT_CONSOLE | 56 | config VT_CONSOLE |
40 | bool "Support for console on virtual terminal" if EMBEDDED | 57 | bool "Support for console on virtual terminal" if EMBEDDED |
41 | depends on VT | 58 | depends on VT |
42 | default y | 59 | default y |
43 | ---help--- | 60 | ---help--- |
44 | The system console is the device which receives all kernel messages | 61 | The system console is the device which receives all kernel messages |
45 | and warnings and which allows logins in single user mode. If you | 62 | and warnings and which allows logins in single user mode. If you |
46 | answer Y here, a virtual terminal (the device used to interact with | 63 | answer Y here, a virtual terminal (the device used to interact with |
47 | a physical terminal) can be used as system console. This is the most | 64 | a physical terminal) can be used as system console. This is the most |
48 | common mode of operations, so you should say Y here unless you want | 65 | common mode of operations, so you should say Y here unless you want |
49 | the kernel messages be output only to a serial port (in which case | 66 | the kernel messages be output only to a serial port (in which case |
50 | you should say Y to "Console on serial port", below). | 67 | you should say Y to "Console on serial port", below). |
51 | 68 | ||
52 | If you do say Y here, by default the currently visible virtual | 69 | If you do say Y here, by default the currently visible virtual |
53 | terminal (/dev/tty0) will be used as system console. You can change | 70 | terminal (/dev/tty0) will be used as system console. You can change |
54 | that with a kernel command line option such as "console=tty3" which | 71 | that with a kernel command line option such as "console=tty3" which |
55 | would use the third virtual terminal as system console. (Try "man | 72 | would use the third virtual terminal as system console. (Try "man |
56 | bootparam" or see the documentation of your boot loader (lilo or | 73 | bootparam" or see the documentation of your boot loader (lilo or |
57 | loadlin) about how to pass options to the kernel at boot time.) | 74 | loadlin) about how to pass options to the kernel at boot time.) |
58 | 75 | ||
59 | If unsure, say Y. | 76 | If unsure, say Y. |
60 | 77 | ||
61 | config HW_CONSOLE | 78 | config HW_CONSOLE |
62 | bool | 79 | bool |
63 | depends on VT && !S390 && !UML | 80 | depends on VT && !S390 && !UML |
64 | default y | 81 | default y |
65 | 82 | ||
66 | config VT_HW_CONSOLE_BINDING | 83 | config VT_HW_CONSOLE_BINDING |
67 | bool "Support for binding and unbinding console drivers" | 84 | bool "Support for binding and unbinding console drivers" |
68 | depends on HW_CONSOLE | 85 | depends on HW_CONSOLE |
69 | default n | 86 | default n |
70 | ---help--- | 87 | ---help--- |
71 | The virtual terminal is the device that interacts with the physical | 88 | The virtual terminal is the device that interacts with the physical |
72 | terminal through console drivers. On these systems, at least one | 89 | terminal through console drivers. On these systems, at least one |
73 | console driver is loaded. In other configurations, additional console | 90 | console driver is loaded. In other configurations, additional console |
74 | drivers may be enabled, such as the framebuffer console. If more than | 91 | drivers may be enabled, such as the framebuffer console. If more than |
75 | 1 console driver is enabled, setting this to 'y' will allow you to | 92 | 1 console driver is enabled, setting this to 'y' will allow you to |
76 | select the console driver that will serve as the backend for the | 93 | select the console driver that will serve as the backend for the |
77 | virtual terminals. | 94 | virtual terminals. |
78 | 95 | ||
79 | See <file:Documentation/console/console.txt> for more | 96 | See <file:Documentation/console/console.txt> for more |
80 | information. For framebuffer console users, please refer to | 97 | information. For framebuffer console users, please refer to |
81 | <file:Documentation/fb/fbcon.txt>. | 98 | <file:Documentation/fb/fbcon.txt>. |
82 | 99 | ||
83 | config SERIAL_NONSTANDARD | 100 | config SERIAL_NONSTANDARD |
84 | bool "Non-standard serial port support" | 101 | bool "Non-standard serial port support" |
85 | depends on HAS_IOMEM | 102 | depends on HAS_IOMEM |
86 | ---help--- | 103 | ---help--- |
87 | Say Y here if you have any non-standard serial boards -- boards | 104 | Say Y here if you have any non-standard serial boards -- boards |
88 | which aren't supported using the standard "dumb" serial driver. | 105 | which aren't supported using the standard "dumb" serial driver. |
89 | This includes intelligent serial boards such as Cyclades, | 106 | This includes intelligent serial boards such as Cyclades, |
90 | Digiboards, etc. These are usually used for systems that need many | 107 | Digiboards, etc. These are usually used for systems that need many |
91 | serial ports because they serve many terminals or dial-in | 108 | serial ports because they serve many terminals or dial-in |
92 | connections. | 109 | connections. |
93 | 110 | ||
94 | Note that the answer to this question won't directly affect the | 111 | Note that the answer to this question won't directly affect the |
95 | kernel: saying N will just cause the configurator to skip all | 112 | kernel: saying N will just cause the configurator to skip all |
96 | the questions about non-standard serial boards. | 113 | the questions about non-standard serial boards. |
97 | 114 | ||
98 | Most people can say N here. | 115 | Most people can say N here. |
99 | 116 | ||
100 | config COMPUTONE | 117 | config COMPUTONE |
101 | tristate "Computone IntelliPort Plus serial support" | 118 | tristate "Computone IntelliPort Plus serial support" |
102 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) | 119 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) |
103 | ---help--- | 120 | ---help--- |
104 | This driver supports the entire family of Intelliport II/Plus | 121 | This driver supports the entire family of Intelliport II/Plus |
105 | controllers with the exception of the MicroChannel controllers and | 122 | controllers with the exception of the MicroChannel controllers and |
106 | products previous to the Intelliport II. These are multiport cards, | 123 | products previous to the Intelliport II. These are multiport cards, |
107 | which give you many serial ports. You would need something like this | 124 | which give you many serial ports. You would need something like this |
108 | to connect more than two modems to your Linux box, for instance in | 125 | to connect more than two modems to your Linux box, for instance in |
109 | order to become a dial-in server. If you have a card like that, say | 126 | order to become a dial-in server. If you have a card like that, say |
110 | Y here and read <file:Documentation/computone.txt>. | 127 | Y here and read <file:Documentation/computone.txt>. |
111 | 128 | ||
112 | To compile this driver as modules, choose M here: the | 129 | To compile this driver as modules, choose M here: the |
113 | modules will be called ip2 and ip2main. | 130 | modules will be called ip2 and ip2main. |
114 | 131 | ||
115 | config ROCKETPORT | 132 | config ROCKETPORT |
116 | tristate "Comtrol RocketPort support" | 133 | tristate "Comtrol RocketPort support" |
117 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) | 134 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) |
118 | help | 135 | help |
119 | This driver supports Comtrol RocketPort and RocketModem PCI boards. | 136 | This driver supports Comtrol RocketPort and RocketModem PCI boards. |
120 | These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or | 137 | These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or |
121 | modems. For information about the RocketPort/RocketModem boards | 138 | modems. For information about the RocketPort/RocketModem boards |
122 | and this driver read <file:Documentation/rocket.txt>. | 139 | and this driver read <file:Documentation/rocket.txt>. |
123 | 140 | ||
124 | To compile this driver as a module, choose M here: the | 141 | To compile this driver as a module, choose M here: the |
125 | module will be called rocket. | 142 | module will be called rocket. |
126 | 143 | ||
127 | If you want to compile this driver into the kernel, say Y here. If | 144 | If you want to compile this driver into the kernel, say Y here. If |
128 | you don't have a Comtrol RocketPort/RocketModem card installed, say N. | 145 | you don't have a Comtrol RocketPort/RocketModem card installed, say N. |
129 | 146 | ||
130 | config CYCLADES | 147 | config CYCLADES |
131 | tristate "Cyclades async mux support" | 148 | tristate "Cyclades async mux support" |
132 | depends on SERIAL_NONSTANDARD && (PCI || ISA) | 149 | depends on SERIAL_NONSTANDARD && (PCI || ISA) |
133 | select FW_LOADER | 150 | select FW_LOADER |
134 | ---help--- | 151 | ---help--- |
135 | This driver supports Cyclades Z and Y multiserial boards. | 152 | This driver supports Cyclades Z and Y multiserial boards. |
136 | You would need something like this to connect more than two modems to | 153 | You would need something like this to connect more than two modems to |
137 | your Linux box, for instance in order to become a dial-in server. | 154 | your Linux box, for instance in order to become a dial-in server. |
138 | 155 | ||
139 | For information about the Cyclades-Z card, read | 156 | For information about the Cyclades-Z card, read |
140 | <file:drivers/char/README.cycladesZ>. | 157 | <file:drivers/char/README.cycladesZ>. |
141 | 158 | ||
142 | To compile this driver as a module, choose M here: the | 159 | To compile this driver as a module, choose M here: the |
143 | module will be called cyclades. | 160 | module will be called cyclades. |
144 | 161 | ||
145 | If you haven't heard about it, it's safe to say N. | 162 | If you haven't heard about it, it's safe to say N. |
146 | 163 | ||
147 | config CYZ_INTR | 164 | config CYZ_INTR |
148 | bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)" | 165 | bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)" |
149 | depends on EXPERIMENTAL && CYCLADES | 166 | depends on EXPERIMENTAL && CYCLADES |
150 | help | 167 | help |
151 | The Cyclades-Z family of multiport cards allows 2 (two) driver op | 168 | The Cyclades-Z family of multiport cards allows 2 (two) driver op |
152 | modes: polling and interrupt. In polling mode, the driver will check | 169 | modes: polling and interrupt. In polling mode, the driver will check |
153 | the status of the Cyclades-Z ports every certain amount of time | 170 | the status of the Cyclades-Z ports every certain amount of time |
154 | (which is called polling cycle and is configurable). In interrupt | 171 | (which is called polling cycle and is configurable). In interrupt |
155 | mode, it will use an interrupt line (IRQ) in order to check the | 172 | mode, it will use an interrupt line (IRQ) in order to check the |
156 | status of the Cyclades-Z ports. The default op mode is polling. If | 173 | status of the Cyclades-Z ports. The default op mode is polling. If |
157 | unsure, say N. | 174 | unsure, say N. |
158 | 175 | ||
159 | config DIGIEPCA | 176 | config DIGIEPCA |
160 | tristate "Digiboard Intelligent Async Support" | 177 | tristate "Digiboard Intelligent Async Support" |
161 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) | 178 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) |
162 | ---help--- | 179 | ---help--- |
163 | This is a driver for Digi International's Xx, Xeve, and Xem series | 180 | This is a driver for Digi International's Xx, Xeve, and Xem series |
164 | of cards which provide multiple serial ports. You would need | 181 | of cards which provide multiple serial ports. You would need |
165 | something like this to connect more than two modems to your Linux | 182 | something like this to connect more than two modems to your Linux |
166 | box, for instance in order to become a dial-in server. This driver | 183 | box, for instance in order to become a dial-in server. This driver |
167 | supports the original PC (ISA) boards as well as PCI, and EISA. If | 184 | supports the original PC (ISA) boards as well as PCI, and EISA. If |
168 | you have a card like this, say Y here and read the file | 185 | you have a card like this, say Y here and read the file |
169 | <file:Documentation/digiepca.txt>. | 186 | <file:Documentation/digiepca.txt>. |
170 | 187 | ||
171 | To compile this driver as a module, choose M here: the | 188 | To compile this driver as a module, choose M here: the |
172 | module will be called epca. | 189 | module will be called epca. |
173 | 190 | ||
174 | config ESPSERIAL | 191 | config ESPSERIAL |
175 | tristate "Hayes ESP serial port support" | 192 | tristate "Hayes ESP serial port support" |
176 | depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API | 193 | depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API |
177 | help | 194 | help |
178 | This is a driver which supports Hayes ESP serial ports. Both single | 195 | This is a driver which supports Hayes ESP serial ports. Both single |
179 | port cards and multiport cards are supported. Make sure to read | 196 | port cards and multiport cards are supported. Make sure to read |
180 | <file:Documentation/hayes-esp.txt>. | 197 | <file:Documentation/hayes-esp.txt>. |
181 | 198 | ||
182 | To compile this driver as a module, choose M here: the | 199 | To compile this driver as a module, choose M here: the |
183 | module will be called esp. | 200 | module will be called esp. |
184 | 201 | ||
185 | If unsure, say N. | 202 | If unsure, say N. |
186 | 203 | ||
187 | config MOXA_INTELLIO | 204 | config MOXA_INTELLIO |
188 | tristate "Moxa Intellio support" | 205 | tristate "Moxa Intellio support" |
189 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) | 206 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) |
190 | help | 207 | help |
191 | Say Y here if you have a Moxa Intellio multiport serial card. | 208 | Say Y here if you have a Moxa Intellio multiport serial card. |
192 | 209 | ||
193 | To compile this driver as a module, choose M here: the | 210 | To compile this driver as a module, choose M here: the |
194 | module will be called moxa. | 211 | module will be called moxa. |
195 | 212 | ||
196 | config MOXA_SMARTIO | 213 | config MOXA_SMARTIO |
197 | tristate "Moxa SmartIO support (OBSOLETE)" | 214 | tristate "Moxa SmartIO support (OBSOLETE)" |
198 | depends on SERIAL_NONSTANDARD | 215 | depends on SERIAL_NONSTANDARD |
199 | help | 216 | help |
200 | Say Y here if you have a Moxa SmartIO multiport serial card. | 217 | Say Y here if you have a Moxa SmartIO multiport serial card. |
201 | 218 | ||
202 | This driver can also be built as a module ( = code which can be | 219 | This driver can also be built as a module ( = code which can be |
203 | inserted in and removed from the running kernel whenever you want). | 220 | inserted in and removed from the running kernel whenever you want). |
204 | The module will be called mxser. If you want to do that, say M | 221 | The module will be called mxser. If you want to do that, say M |
205 | here. | 222 | here. |
206 | 223 | ||
207 | config MOXA_SMARTIO_NEW | 224 | config MOXA_SMARTIO_NEW |
208 | tristate "Moxa SmartIO support v. 2.0" | 225 | tristate "Moxa SmartIO support v. 2.0" |
209 | depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) | 226 | depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) |
210 | help | 227 | help |
211 | Say Y here if you have a Moxa SmartIO multiport serial card and/or | 228 | Say Y here if you have a Moxa SmartIO multiport serial card and/or |
212 | want to help develop a new version of this driver. | 229 | want to help develop a new version of this driver. |
213 | 230 | ||
214 | This is upgraded (1.9.1) driver from original Moxa drivers with | 231 | This is upgraded (1.9.1) driver from original Moxa drivers with |
215 | changes finally resulting in PCI probing. | 232 | changes finally resulting in PCI probing. |
216 | 233 | ||
217 | This driver can also be built as a module. The module will be called | 234 | This driver can also be built as a module. The module will be called |
218 | mxser_new. If you want to do that, say M here. | 235 | mxser_new. If you want to do that, say M here. |
219 | 236 | ||
220 | config ISI | 237 | config ISI |
221 | tristate "Multi-Tech multiport card support (EXPERIMENTAL)" | 238 | tristate "Multi-Tech multiport card support (EXPERIMENTAL)" |
222 | depends on SERIAL_NONSTANDARD && PCI | 239 | depends on SERIAL_NONSTANDARD && PCI |
223 | select FW_LOADER | 240 | select FW_LOADER |
224 | help | 241 | help |
225 | This is a driver for the Multi-Tech cards which provide several | 242 | This is a driver for the Multi-Tech cards which provide several |
226 | serial ports. The driver is experimental and can currently only be | 243 | serial ports. The driver is experimental and can currently only be |
227 | built as a module. The module will be called isicom. | 244 | built as a module. The module will be called isicom. |
228 | If you want to do that, choose M here. | 245 | If you want to do that, choose M here. |
229 | 246 | ||
230 | config SYNCLINK | 247 | config SYNCLINK |
231 | tristate "Microgate SyncLink card support" | 248 | tristate "Microgate SyncLink card support" |
232 | depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API | 249 | depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API |
233 | help | 250 | help |
234 | Provides support for the SyncLink ISA and PCI multiprotocol serial | 251 | Provides support for the SyncLink ISA and PCI multiprotocol serial |
235 | adapters. These adapters support asynchronous and HDLC bit | 252 | adapters. These adapters support asynchronous and HDLC bit |
236 | synchronous communication up to 10Mbps (PCI adapter). | 253 | synchronous communication up to 10Mbps (PCI adapter). |
237 | 254 | ||
238 | This driver can only be built as a module ( = code which can be | 255 | This driver can only be built as a module ( = code which can be |
239 | inserted in and removed from the running kernel whenever you want). | 256 | inserted in and removed from the running kernel whenever you want). |
240 | The module will be called synclink. If you want to do that, say M | 257 | The module will be called synclink. If you want to do that, say M |
241 | here. | 258 | here. |
242 | 259 | ||
243 | config SYNCLINKMP | 260 | config SYNCLINKMP |
244 | tristate "SyncLink Multiport support" | 261 | tristate "SyncLink Multiport support" |
245 | depends on SERIAL_NONSTANDARD && PCI | 262 | depends on SERIAL_NONSTANDARD && PCI |
246 | help | 263 | help |
247 | Enable support for the SyncLink Multiport (2 or 4 ports) | 264 | Enable support for the SyncLink Multiport (2 or 4 ports) |
248 | serial adapter, running asynchronous and HDLC communications up | 265 | serial adapter, running asynchronous and HDLC communications up |
249 | to 2.048Mbps. Each ports is independently selectable for | 266 | to 2.048Mbps. Each ports is independently selectable for |
250 | RS-232, V.35, RS-449, RS-530, and X.21 | 267 | RS-232, V.35, RS-449, RS-530, and X.21 |
251 | 268 | ||
252 | This driver may be built as a module ( = code which can be | 269 | This driver may be built as a module ( = code which can be |
253 | inserted in and removed from the running kernel whenever you want). | 270 | inserted in and removed from the running kernel whenever you want). |
254 | The module will be called synclinkmp. If you want to do that, say M | 271 | The module will be called synclinkmp. If you want to do that, say M |
255 | here. | 272 | here. |
256 | 273 | ||
257 | config SYNCLINK_GT | 274 | config SYNCLINK_GT |
258 | tristate "SyncLink GT/AC support" | 275 | tristate "SyncLink GT/AC support" |
259 | depends on SERIAL_NONSTANDARD && PCI | 276 | depends on SERIAL_NONSTANDARD && PCI |
260 | help | 277 | help |
261 | Support for SyncLink GT and SyncLink AC families of | 278 | Support for SyncLink GT and SyncLink AC families of |
262 | synchronous and asynchronous serial adapters | 279 | synchronous and asynchronous serial adapters |
263 | manufactured by Microgate Systems, Ltd. (www.microgate.com) | 280 | manufactured by Microgate Systems, Ltd. (www.microgate.com) |
264 | 281 | ||
265 | config N_HDLC | 282 | config N_HDLC |
266 | tristate "HDLC line discipline support" | 283 | tristate "HDLC line discipline support" |
267 | depends on SERIAL_NONSTANDARD | 284 | depends on SERIAL_NONSTANDARD |
268 | help | 285 | help |
269 | Allows synchronous HDLC communications with tty device drivers that | 286 | Allows synchronous HDLC communications with tty device drivers that |
270 | support synchronous HDLC such as the Microgate SyncLink adapter. | 287 | support synchronous HDLC such as the Microgate SyncLink adapter. |
271 | 288 | ||
272 | This driver can only be built as a module ( = code which can be | 289 | This driver can only be built as a module ( = code which can be |
273 | inserted in and removed from the running kernel whenever you want). | 290 | inserted in and removed from the running kernel whenever you want). |
274 | The module will be called n_hdlc. If you want to do that, say M | 291 | The module will be called n_hdlc. If you want to do that, say M |
275 | here. | 292 | here. |
276 | 293 | ||
277 | config RISCOM8 | 294 | config RISCOM8 |
278 | tristate "SDL RISCom/8 card support" | 295 | tristate "SDL RISCom/8 card support" |
279 | depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP | 296 | depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP |
280 | help | 297 | help |
281 | This is a driver for the SDL Communications RISCom/8 multiport card, | 298 | This is a driver for the SDL Communications RISCom/8 multiport card, |
282 | which gives you many serial ports. You would need something like | 299 | which gives you many serial ports. You would need something like |
283 | this to connect more than two modems to your Linux box, for instance | 300 | this to connect more than two modems to your Linux box, for instance |
284 | in order to become a dial-in server. If you have a card like that, | 301 | in order to become a dial-in server. If you have a card like that, |
285 | say Y here and read the file <file:Documentation/riscom8.txt>. | 302 | say Y here and read the file <file:Documentation/riscom8.txt>. |
286 | 303 | ||
287 | Also it's possible to say M here and compile this driver as kernel | 304 | Also it's possible to say M here and compile this driver as kernel |
288 | loadable module; the module will be called riscom8. | 305 | loadable module; the module will be called riscom8. |
289 | 306 | ||
290 | config SPECIALIX | 307 | config SPECIALIX |
291 | tristate "Specialix IO8+ card support" | 308 | tristate "Specialix IO8+ card support" |
292 | depends on SERIAL_NONSTANDARD | 309 | depends on SERIAL_NONSTANDARD |
293 | help | 310 | help |
294 | This is a driver for the Specialix IO8+ multiport card (both the | 311 | This is a driver for the Specialix IO8+ multiport card (both the |
295 | ISA and the PCI version) which gives you many serial ports. You | 312 | ISA and the PCI version) which gives you many serial ports. You |
296 | would need something like this to connect more than two modems to | 313 | would need something like this to connect more than two modems to |
297 | your Linux box, for instance in order to become a dial-in server. | 314 | your Linux box, for instance in order to become a dial-in server. |
298 | 315 | ||
299 | If you have a card like that, say Y here and read the file | 316 | If you have a card like that, say Y here and read the file |
300 | <file:Documentation/specialix.txt>. Also it's possible to say M here | 317 | <file:Documentation/specialix.txt>. Also it's possible to say M here |
301 | and compile this driver as kernel loadable module which will be | 318 | and compile this driver as kernel loadable module which will be |
302 | called specialix. | 319 | called specialix. |
303 | 320 | ||
304 | config SPECIALIX_RTSCTS | 321 | config SPECIALIX_RTSCTS |
305 | bool "Specialix DTR/RTS pin is RTS" | 322 | bool "Specialix DTR/RTS pin is RTS" |
306 | depends on SPECIALIX | 323 | depends on SPECIALIX |
307 | help | 324 | help |
308 | The Specialix IO8+ card can only support either RTS or DTR. If you | 325 | The Specialix IO8+ card can only support either RTS or DTR. If you |
309 | say N here, the driver will use the pin as "DTR" when the tty is in | 326 | say N here, the driver will use the pin as "DTR" when the tty is in |
310 | software handshake mode. If you say Y here or hardware handshake is | 327 | software handshake mode. If you say Y here or hardware handshake is |
311 | on, it will always be RTS. Read the file | 328 | on, it will always be RTS. Read the file |
312 | <file:Documentation/specialix.txt> for more information. | 329 | <file:Documentation/specialix.txt> for more information. |
313 | 330 | ||
314 | config SX | 331 | config SX |
315 | tristate "Specialix SX (and SI) card support" | 332 | tristate "Specialix SX (and SI) card support" |
316 | depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) | 333 | depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) |
317 | help | 334 | help |
318 | This is a driver for the SX and SI multiport serial cards. | 335 | This is a driver for the SX and SI multiport serial cards. |
319 | Please read the file <file:Documentation/sx.txt> for details. | 336 | Please read the file <file:Documentation/sx.txt> for details. |
320 | 337 | ||
321 | This driver can only be built as a module ( = code which can be | 338 | This driver can only be built as a module ( = code which can be |
322 | inserted in and removed from the running kernel whenever you want). | 339 | inserted in and removed from the running kernel whenever you want). |
323 | The module will be called sx. If you want to do that, say M here. | 340 | The module will be called sx. If you want to do that, say M here. |
324 | 341 | ||
325 | config RIO | 342 | config RIO |
326 | tristate "Specialix RIO system support" | 343 | tristate "Specialix RIO system support" |
327 | depends on SERIAL_NONSTANDARD | 344 | depends on SERIAL_NONSTANDARD |
328 | help | 345 | help |
329 | This is a driver for the Specialix RIO, a smart serial card which | 346 | This is a driver for the Specialix RIO, a smart serial card which |
330 | drives an outboard box that can support up to 128 ports. Product | 347 | drives an outboard box that can support up to 128 ports. Product |
331 | information is at <http://www.perle.com/support/documentation.html#multiport>. | 348 | information is at <http://www.perle.com/support/documentation.html#multiport>. |
332 | There are both ISA and PCI versions. | 349 | There are both ISA and PCI versions. |
333 | 350 | ||
334 | config RIO_OLDPCI | 351 | config RIO_OLDPCI |
335 | bool "Support really old RIO/PCI cards" | 352 | bool "Support really old RIO/PCI cards" |
336 | depends on RIO | 353 | depends on RIO |
337 | help | 354 | help |
338 | Older RIO PCI cards need some initialization-time configuration to | 355 | Older RIO PCI cards need some initialization-time configuration to |
339 | determine the IRQ and some control addresses. If you have a RIO and | 356 | determine the IRQ and some control addresses. If you have a RIO and |
340 | this doesn't seem to work, try setting this to Y. | 357 | this doesn't seem to work, try setting this to Y. |
341 | 358 | ||
342 | config STALDRV | 359 | config STALDRV |
343 | bool "Stallion multiport serial support" | 360 | bool "Stallion multiport serial support" |
344 | depends on SERIAL_NONSTANDARD | 361 | depends on SERIAL_NONSTANDARD |
345 | help | 362 | help |
346 | Stallion cards give you many serial ports. You would need something | 363 | Stallion cards give you many serial ports. You would need something |
347 | like this to connect more than two modems to your Linux box, for | 364 | like this to connect more than two modems to your Linux box, for |
348 | instance in order to become a dial-in server. If you say Y here, | 365 | instance in order to become a dial-in server. If you say Y here, |
349 | you will be asked for your specific card model in the next | 366 | you will be asked for your specific card model in the next |
350 | questions. Make sure to read <file:Documentation/stallion.txt> in | 367 | questions. Make sure to read <file:Documentation/stallion.txt> in |
351 | this case. If you have never heard about all this, it's safe to | 368 | this case. If you have never heard about all this, it's safe to |
352 | say N. | 369 | say N. |
353 | 370 | ||
354 | config STALLION | 371 | config STALLION |
355 | tristate "Stallion EasyIO or EC8/32 support" | 372 | tristate "Stallion EasyIO or EC8/32 support" |
356 | depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) | 373 | depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) |
357 | help | 374 | help |
358 | If you have an EasyIO or EasyConnection 8/32 multiport Stallion | 375 | If you have an EasyIO or EasyConnection 8/32 multiport Stallion |
359 | card, then this is for you; say Y. Make sure to read | 376 | card, then this is for you; say Y. Make sure to read |
360 | <file:Documentation/stallion.txt>. | 377 | <file:Documentation/stallion.txt>. |
361 | 378 | ||
362 | To compile this driver as a module, choose M here: the | 379 | To compile this driver as a module, choose M here: the |
363 | module will be called stallion. | 380 | module will be called stallion. |
364 | 381 | ||
365 | config ISTALLION | 382 | config ISTALLION |
366 | tristate "Stallion EC8/64, ONboard, Brumby support" | 383 | tristate "Stallion EC8/64, ONboard, Brumby support" |
367 | depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) | 384 | depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) |
368 | help | 385 | help |
369 | If you have an EasyConnection 8/64, ONboard, Brumby or Stallion | 386 | If you have an EasyConnection 8/64, ONboard, Brumby or Stallion |
370 | serial multiport card, say Y here. Make sure to read | 387 | serial multiport card, say Y here. Make sure to read |
371 | <file:Documentation/stallion.txt>. | 388 | <file:Documentation/stallion.txt>. |
372 | 389 | ||
373 | To compile this driver as a module, choose M here: the | 390 | To compile this driver as a module, choose M here: the |
374 | module will be called istallion. | 391 | module will be called istallion. |
375 | 392 | ||
376 | config A2232 | 393 | config A2232 |
377 | tristate "Commodore A2232 serial support (EXPERIMENTAL)" | 394 | tristate "Commodore A2232 serial support (EXPERIMENTAL)" |
378 | depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP | 395 | depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP |
379 | ---help--- | 396 | ---help--- |
380 | This option supports the 2232 7-port serial card shipped with the | 397 | This option supports the 2232 7-port serial card shipped with the |
381 | Amiga 2000 and other Zorro-bus machines, dating from 1989. At | 398 | Amiga 2000 and other Zorro-bus machines, dating from 1989. At |
382 | a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip | 399 | a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip |
383 | each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The | 400 | each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The |
384 | ports were connected with 8 pin DIN connectors on the card bracket, | 401 | ports were connected with 8 pin DIN connectors on the card bracket, |
385 | for which 8 pin to DB25 adapters were supplied. The card also had | 402 | for which 8 pin to DB25 adapters were supplied. The card also had |
386 | jumpers internally to toggle various pinning configurations. | 403 | jumpers internally to toggle various pinning configurations. |
387 | 404 | ||
388 | This driver can be built as a module; but then "generic_serial" | 405 | This driver can be built as a module; but then "generic_serial" |
389 | will also be built as a module. This has to be loaded before | 406 | will also be built as a module. This has to be loaded before |
390 | "ser_a2232". If you want to do this, answer M here. | 407 | "ser_a2232". If you want to do this, answer M here. |
391 | 408 | ||
392 | config SGI_SNSC | 409 | config SGI_SNSC |
393 | bool "SGI Altix system controller communication support" | 410 | bool "SGI Altix system controller communication support" |
394 | depends on (IA64_SGI_SN2 || IA64_GENERIC) | 411 | depends on (IA64_SGI_SN2 || IA64_GENERIC) |
395 | help | 412 | help |
396 | If you have an SGI Altix and you want to enable system | 413 | If you have an SGI Altix and you want to enable system |
397 | controller communication from user space (you want this!), | 414 | controller communication from user space (you want this!), |
398 | say Y. Otherwise, say N. | 415 | say Y. Otherwise, say N. |
399 | 416 | ||
400 | config SGI_TIOCX | 417 | config SGI_TIOCX |
401 | bool "SGI TIO CX driver support" | 418 | bool "SGI TIO CX driver support" |
402 | depends on (IA64_SGI_SN2 || IA64_GENERIC) | 419 | depends on (IA64_SGI_SN2 || IA64_GENERIC) |
403 | help | 420 | help |
404 | If you have an SGI Altix and you have fpga devices attached | 421 | If you have an SGI Altix and you have fpga devices attached |
405 | to your TIO, say Y here, otherwise say N. | 422 | to your TIO, say Y here, otherwise say N. |
406 | 423 | ||
407 | config SGI_MBCS | 424 | config SGI_MBCS |
408 | tristate "SGI FPGA Core Services driver support" | 425 | tristate "SGI FPGA Core Services driver support" |
409 | depends on SGI_TIOCX | 426 | depends on SGI_TIOCX |
410 | help | 427 | help |
411 | If you have an SGI Altix with an attached SABrick | 428 | If you have an SGI Altix with an attached SABrick |
412 | say Y or M here, otherwise say N. | 429 | say Y or M here, otherwise say N. |
413 | 430 | ||
414 | source "drivers/serial/Kconfig" | 431 | source "drivers/serial/Kconfig" |
415 | 432 | ||
416 | config UNIX98_PTYS | 433 | config UNIX98_PTYS |
417 | bool "Unix98 PTY support" if EMBEDDED | 434 | bool "Unix98 PTY support" if EMBEDDED |
418 | default y | 435 | default y |
419 | ---help--- | 436 | ---help--- |
420 | A pseudo terminal (PTY) is a software device consisting of two | 437 | A pseudo terminal (PTY) is a software device consisting of two |
421 | halves: a master and a slave. The slave device behaves identical to | 438 | halves: a master and a slave. The slave device behaves identical to |
422 | a physical terminal; the master device is used by a process to | 439 | a physical terminal; the master device is used by a process to |
423 | read data from and write data to the slave, thereby emulating a | 440 | read data from and write data to the slave, thereby emulating a |
424 | terminal. Typical programs for the master side are telnet servers | 441 | terminal. Typical programs for the master side are telnet servers |
425 | and xterms. | 442 | and xterms. |
426 | 443 | ||
427 | Linux has traditionally used the BSD-like names /dev/ptyxx for | 444 | Linux has traditionally used the BSD-like names /dev/ptyxx for |
428 | masters and /dev/ttyxx for slaves of pseudo terminals. This scheme | 445 | masters and /dev/ttyxx for slaves of pseudo terminals. This scheme |
429 | has a number of problems. The GNU C library glibc 2.1 and later, | 446 | has a number of problems. The GNU C library glibc 2.1 and later, |
430 | however, supports the Unix98 naming standard: in order to acquire a | 447 | however, supports the Unix98 naming standard: in order to acquire a |
431 | pseudo terminal, a process opens /dev/ptmx; the number of the pseudo | 448 | pseudo terminal, a process opens /dev/ptmx; the number of the pseudo |
432 | terminal is then made available to the process and the pseudo | 449 | terminal is then made available to the process and the pseudo |
433 | terminal slave can be accessed as /dev/pts/<number>. What was | 450 | terminal slave can be accessed as /dev/pts/<number>. What was |
434 | traditionally /dev/ttyp2 will then be /dev/pts/2, for example. | 451 | traditionally /dev/ttyp2 will then be /dev/pts/2, for example. |
435 | 452 | ||
436 | All modern Linux systems use the Unix98 ptys. Say Y unless | 453 | All modern Linux systems use the Unix98 ptys. Say Y unless |
437 | you're on an embedded system and want to conserve memory. | 454 | you're on an embedded system and want to conserve memory. |
438 | 455 | ||
439 | config LEGACY_PTYS | 456 | config LEGACY_PTYS |
440 | bool "Legacy (BSD) PTY support" | 457 | bool "Legacy (BSD) PTY support" |
441 | default y | 458 | default y |
442 | ---help--- | 459 | ---help--- |
443 | A pseudo terminal (PTY) is a software device consisting of two | 460 | A pseudo terminal (PTY) is a software device consisting of two |
444 | halves: a master and a slave. The slave device behaves identical to | 461 | halves: a master and a slave. The slave device behaves identical to |
445 | a physical terminal; the master device is used by a process to | 462 | a physical terminal; the master device is used by a process to |
446 | read data from and write data to the slave, thereby emulating a | 463 | read data from and write data to the slave, thereby emulating a |
447 | terminal. Typical programs for the master side are telnet servers | 464 | terminal. Typical programs for the master side are telnet servers |
448 | and xterms. | 465 | and xterms. |
449 | 466 | ||
450 | Linux has traditionally used the BSD-like names /dev/ptyxx | 467 | Linux has traditionally used the BSD-like names /dev/ptyxx |
451 | for masters and /dev/ttyxx for slaves of pseudo | 468 | for masters and /dev/ttyxx for slaves of pseudo |
452 | terminals. This scheme has a number of problems, including | 469 | terminals. This scheme has a number of problems, including |
453 | security. This option enables these legacy devices; on most | 470 | security. This option enables these legacy devices; on most |
454 | systems, it is safe to say N. | 471 | systems, it is safe to say N. |
455 | 472 | ||
456 | 473 | ||
457 | config LEGACY_PTY_COUNT | 474 | config LEGACY_PTY_COUNT |
458 | int "Maximum number of legacy PTY in use" | 475 | int "Maximum number of legacy PTY in use" |
459 | depends on LEGACY_PTYS | 476 | depends on LEGACY_PTYS |
460 | range 1 256 | 477 | range 1 256 |
461 | default "256" | 478 | default "256" |
462 | ---help--- | 479 | ---help--- |
463 | The maximum number of legacy PTYs that can be used at any one time. | 480 | The maximum number of legacy PTYs that can be used at any one time. |
464 | The default is 256, and should be more than enough. Embedded | 481 | The default is 256, and should be more than enough. Embedded |
465 | systems may want to reduce this to save memory. | 482 | systems may want to reduce this to save memory. |
466 | 483 | ||
467 | When not in use, each legacy PTY occupies 12 bytes on 32-bit | 484 | When not in use, each legacy PTY occupies 12 bytes on 32-bit |
468 | architectures and 24 bytes on 64-bit architectures. | 485 | architectures and 24 bytes on 64-bit architectures. |
469 | 486 | ||
470 | config BRIQ_PANEL | 487 | config BRIQ_PANEL |
471 | tristate 'Total Impact briQ front panel driver' | 488 | tristate 'Total Impact briQ front panel driver' |
472 | depends on PPC_CHRP | 489 | depends on PPC_CHRP |
473 | ---help--- | 490 | ---help--- |
474 | The briQ is a small footprint CHRP computer with a frontpanel VFD, a | 491 | The briQ is a small footprint CHRP computer with a frontpanel VFD, a |
475 | tristate led and two switches. It is the size of a CDROM drive. | 492 | tristate led and two switches. It is the size of a CDROM drive. |
476 | 493 | ||
477 | If you have such one and want anything showing on the VFD then you | 494 | If you have such one and want anything showing on the VFD then you |
478 | must answer Y here. | 495 | must answer Y here. |
479 | 496 | ||
480 | To compile this driver as a module, choose M here: the | 497 | To compile this driver as a module, choose M here: the |
481 | module will be called briq_panel. | 498 | module will be called briq_panel. |
482 | 499 | ||
483 | It's safe to say N here. | 500 | It's safe to say N here. |
484 | 501 | ||
485 | config PRINTER | 502 | config PRINTER |
486 | tristate "Parallel printer support" | 503 | tristate "Parallel printer support" |
487 | depends on PARPORT | 504 | depends on PARPORT |
488 | ---help--- | 505 | ---help--- |
489 | If you intend to attach a printer to the parallel port of your Linux | 506 | If you intend to attach a printer to the parallel port of your Linux |
490 | box (as opposed to using a serial printer; if the connector at the | 507 | box (as opposed to using a serial printer; if the connector at the |
491 | printer has 9 or 25 holes ["female"], then it's serial), say Y. | 508 | printer has 9 or 25 holes ["female"], then it's serial), say Y. |
492 | Also read the Printing-HOWTO, available from | 509 | Also read the Printing-HOWTO, available from |
493 | <http://www.tldp.org/docs.html#howto>. | 510 | <http://www.tldp.org/docs.html#howto>. |
494 | 511 | ||
495 | It is possible to share one parallel port among several devices | 512 | It is possible to share one parallel port among several devices |
496 | (e.g. printer and ZIP drive) and it is safe to compile the | 513 | (e.g. printer and ZIP drive) and it is safe to compile the |
497 | corresponding drivers into the kernel. | 514 | corresponding drivers into the kernel. |
498 | 515 | ||
499 | To compile this driver as a module, choose M here and read | 516 | To compile this driver as a module, choose M here and read |
500 | <file:Documentation/parport.txt>. The module will be called lp. | 517 | <file:Documentation/parport.txt>. The module will be called lp. |
501 | 518 | ||
502 | If you have several parallel ports, you can specify which ports to | 519 | If you have several parallel ports, you can specify which ports to |
503 | use with the "lp" kernel command line option. (Try "man bootparam" | 520 | use with the "lp" kernel command line option. (Try "man bootparam" |
504 | or see the documentation of your boot loader (lilo or loadlin) about | 521 | or see the documentation of your boot loader (lilo or loadlin) about |
505 | how to pass options to the kernel at boot time.) The syntax of the | 522 | how to pass options to the kernel at boot time.) The syntax of the |
506 | "lp" command line option can be found in <file:drivers/char/lp.c>. | 523 | "lp" command line option can be found in <file:drivers/char/lp.c>. |
507 | 524 | ||
508 | If you have more than 8 printers, you need to increase the LP_NO | 525 | If you have more than 8 printers, you need to increase the LP_NO |
509 | macro in lp.c and the PARPORT_MAX macro in parport.h. | 526 | macro in lp.c and the PARPORT_MAX macro in parport.h. |
510 | 527 | ||
511 | config LP_CONSOLE | 528 | config LP_CONSOLE |
512 | bool "Support for console on line printer" | 529 | bool "Support for console on line printer" |
513 | depends on PRINTER | 530 | depends on PRINTER |
514 | ---help--- | 531 | ---help--- |
515 | If you want kernel messages to be printed out as they occur, you | 532 | If you want kernel messages to be printed out as they occur, you |
516 | can have a console on the printer. This option adds support for | 533 | can have a console on the printer. This option adds support for |
517 | doing that; to actually get it to happen you need to pass the | 534 | doing that; to actually get it to happen you need to pass the |
518 | option "console=lp0" to the kernel at boot time. | 535 | option "console=lp0" to the kernel at boot time. |
519 | 536 | ||
520 | If the printer is out of paper (or off, or unplugged, or too | 537 | If the printer is out of paper (or off, or unplugged, or too |
521 | busy..) the kernel will stall until the printer is ready again. | 538 | busy..) the kernel will stall until the printer is ready again. |
522 | By defining CONSOLE_LP_STRICT to 0 (at your own risk) you | 539 | By defining CONSOLE_LP_STRICT to 0 (at your own risk) you |
523 | can make the kernel continue when this happens, | 540 | can make the kernel continue when this happens, |
524 | but it'll lose the kernel messages. | 541 | but it'll lose the kernel messages. |
525 | 542 | ||
526 | If unsure, say N. | 543 | If unsure, say N. |
527 | 544 | ||
528 | config PPDEV | 545 | config PPDEV |
529 | tristate "Support for user-space parallel port device drivers" | 546 | tristate "Support for user-space parallel port device drivers" |
530 | depends on PARPORT | 547 | depends on PARPORT |
531 | ---help--- | 548 | ---help--- |
532 | Saying Y to this adds support for /dev/parport device nodes. This | 549 | Saying Y to this adds support for /dev/parport device nodes. This |
533 | is needed for programs that want portable access to the parallel | 550 | is needed for programs that want portable access to the parallel |
534 | port, for instance deviceid (which displays Plug-and-Play device | 551 | port, for instance deviceid (which displays Plug-and-Play device |
535 | IDs). | 552 | IDs). |
536 | 553 | ||
537 | This is the parallel port equivalent of SCSI generic support (sg). | 554 | This is the parallel port equivalent of SCSI generic support (sg). |
538 | It is safe to say N to this -- it is not needed for normal printing | 555 | It is safe to say N to this -- it is not needed for normal printing |
539 | or parallel port CD-ROM/disk support. | 556 | or parallel port CD-ROM/disk support. |
540 | 557 | ||
541 | To compile this driver as a module, choose M here: the | 558 | To compile this driver as a module, choose M here: the |
542 | module will be called ppdev. | 559 | module will be called ppdev. |
543 | 560 | ||
544 | If unsure, say N. | 561 | If unsure, say N. |
545 | 562 | ||
546 | config TIPAR | 563 | config TIPAR |
547 | tristate "Texas Instruments parallel link cable support" | 564 | tristate "Texas Instruments parallel link cable support" |
548 | depends on PARPORT | 565 | depends on PARPORT |
549 | ---help--- | 566 | ---help--- |
550 | If you own a Texas Instruments graphing calculator and use a | 567 | If you own a Texas Instruments graphing calculator and use a |
551 | parallel link cable, then you might be interested in this driver. | 568 | parallel link cable, then you might be interested in this driver. |
552 | 569 | ||
553 | If you enable this driver, you will be able to communicate with | 570 | If you enable this driver, you will be able to communicate with |
554 | your calculator through a set of device nodes under /dev. The | 571 | your calculator through a set of device nodes under /dev. The |
555 | main advantage of this driver is that you don't have to be root | 572 | main advantage of this driver is that you don't have to be root |
556 | to use this precise link cable (depending on the permissions on | 573 | to use this precise link cable (depending on the permissions on |
557 | the device nodes, though). | 574 | the device nodes, though). |
558 | 575 | ||
559 | To compile this driver as a module, choose M here: the | 576 | To compile this driver as a module, choose M here: the |
560 | module will be called tipar. | 577 | module will be called tipar. |
561 | 578 | ||
562 | If you don't know what a parallel link cable is or what a Texas | 579 | If you don't know what a parallel link cable is or what a Texas |
563 | Instruments graphing calculator is, then you probably don't need this | 580 | Instruments graphing calculator is, then you probably don't need this |
564 | driver. | 581 | driver. |
565 | 582 | ||
566 | If unsure, say N. | 583 | If unsure, say N. |
567 | 584 | ||
568 | config HVC_DRIVER | 585 | config HVC_DRIVER |
569 | bool | 586 | bool |
570 | help | 587 | help |
571 | Users of pSeries machines that want to utilize the hvc console front-end | 588 | Users of pSeries machines that want to utilize the hvc console front-end |
572 | module for their backend console driver should select this option. | 589 | module for their backend console driver should select this option. |
573 | It will automatically be selected if one of the back-end console drivers | 590 | It will automatically be selected if one of the back-end console drivers |
574 | is selected. | 591 | is selected. |
575 | 592 | ||
576 | 593 | ||
577 | config HVC_CONSOLE | 594 | config HVC_CONSOLE |
578 | bool "pSeries Hypervisor Virtual Console support" | 595 | bool "pSeries Hypervisor Virtual Console support" |
579 | depends on PPC_PSERIES | 596 | depends on PPC_PSERIES |
580 | select HVC_DRIVER | 597 | select HVC_DRIVER |
581 | help | 598 | help |
582 | pSeries machines when partitioned support a hypervisor virtual | 599 | pSeries machines when partitioned support a hypervisor virtual |
583 | console. This driver allows each pSeries partition to have a console | 600 | console. This driver allows each pSeries partition to have a console |
584 | which is accessed via the HMC. | 601 | which is accessed via the HMC. |
585 | 602 | ||
586 | config HVC_ISERIES | 603 | config HVC_ISERIES |
587 | bool "iSeries Hypervisor Virtual Console support" | 604 | bool "iSeries Hypervisor Virtual Console support" |
588 | depends on PPC_ISERIES | 605 | depends on PPC_ISERIES |
589 | default y | 606 | default y |
590 | select HVC_DRIVER | 607 | select HVC_DRIVER |
591 | help | 608 | help |
592 | iSeries machines support a hypervisor virtual console. | 609 | iSeries machines support a hypervisor virtual console. |
593 | 610 | ||
594 | config HVC_RTAS | 611 | config HVC_RTAS |
595 | bool "IBM RTAS Console support" | 612 | bool "IBM RTAS Console support" |
596 | depends on PPC_RTAS | 613 | depends on PPC_RTAS |
597 | select HVC_DRIVER | 614 | select HVC_DRIVER |
598 | help | 615 | help |
599 | IBM Console device driver which makes use of RTAS | 616 | IBM Console device driver which makes use of RTAS |
600 | 617 | ||
601 | config HVC_BEAT | 618 | config HVC_BEAT |
602 | bool "Toshiba's Beat Hypervisor Console support" | 619 | bool "Toshiba's Beat Hypervisor Console support" |
603 | depends on PPC_CELLEB | 620 | depends on PPC_CELLEB |
604 | select HVC_DRIVER | 621 | select HVC_DRIVER |
605 | help | 622 | help |
606 | Toshiba's Cell Reference Set Beat Console device driver | 623 | Toshiba's Cell Reference Set Beat Console device driver |
607 | 624 | ||
608 | config HVC_XEN | 625 | config HVC_XEN |
609 | bool "Xen Hypervisor Console support" | 626 | bool "Xen Hypervisor Console support" |
610 | depends on XEN | 627 | depends on XEN |
611 | select HVC_DRIVER | 628 | select HVC_DRIVER |
612 | default y | 629 | default y |
613 | help | 630 | help |
614 | Xen virtual console device driver | 631 | Xen virtual console device driver |
615 | 632 | ||
616 | config HVCS | 633 | config HVCS |
617 | tristate "IBM Hypervisor Virtual Console Server support" | 634 | tristate "IBM Hypervisor Virtual Console Server support" |
618 | depends on PPC_PSERIES | 635 | depends on PPC_PSERIES |
619 | help | 636 | help |
620 | Partitionable IBM Power5 ppc64 machines allow hosting of | 637 | Partitionable IBM Power5 ppc64 machines allow hosting of |
621 | firmware virtual consoles from one Linux partition by | 638 | firmware virtual consoles from one Linux partition by |
622 | another Linux partition. This driver allows console data | 639 | another Linux partition. This driver allows console data |
623 | from Linux partitions to be accessed through TTY device | 640 | from Linux partitions to be accessed through TTY device |
624 | interfaces in the device tree of a Linux partition running | 641 | interfaces in the device tree of a Linux partition running |
625 | this driver. | 642 | this driver. |
626 | 643 | ||
627 | To compile this driver as a module, choose M here: the | 644 | To compile this driver as a module, choose M here: the |
628 | module will be called hvcs.ko. Additionally, this module | 645 | module will be called hvcs.ko. Additionally, this module |
629 | will depend on arch specific APIs exported from hvcserver.ko | 646 | will depend on arch specific APIs exported from hvcserver.ko |
630 | which will also be compiled when this driver is built as a | 647 | which will also be compiled when this driver is built as a |
631 | module. | 648 | module. |
632 | 649 | ||
633 | source "drivers/char/ipmi/Kconfig" | 650 | source "drivers/char/ipmi/Kconfig" |
634 | 651 | ||
635 | source "drivers/char/watchdog/Kconfig" | 652 | source "drivers/char/watchdog/Kconfig" |
636 | 653 | ||
637 | config DS1620 | 654 | config DS1620 |
638 | tristate "NetWinder thermometer support" | 655 | tristate "NetWinder thermometer support" |
639 | depends on ARCH_NETWINDER | 656 | depends on ARCH_NETWINDER |
640 | help | 657 | help |
641 | Say Y here to include support for the thermal management hardware | 658 | Say Y here to include support for the thermal management hardware |
642 | found in the NetWinder. This driver allows the user to control the | 659 | found in the NetWinder. This driver allows the user to control the |
643 | temperature set points and to read the current temperature. | 660 | temperature set points and to read the current temperature. |
644 | 661 | ||
645 | It is also possible to say M here to build it as a module (ds1620) | 662 | It is also possible to say M here to build it as a module (ds1620) |
646 | It is recommended to be used on a NetWinder, but it is not a | 663 | It is recommended to be used on a NetWinder, but it is not a |
647 | necessity. | 664 | necessity. |
648 | 665 | ||
649 | config NWBUTTON | 666 | config NWBUTTON |
650 | tristate "NetWinder Button" | 667 | tristate "NetWinder Button" |
651 | depends on ARCH_NETWINDER | 668 | depends on ARCH_NETWINDER |
652 | ---help--- | 669 | ---help--- |
653 | If you say Y here and create a character device node /dev/nwbutton | 670 | If you say Y here and create a character device node /dev/nwbutton |
654 | with major and minor numbers 10 and 158 ("man mknod"), then every | 671 | with major and minor numbers 10 and 158 ("man mknod"), then every |
655 | time the orange button is pressed a number of times, the number of | 672 | time the orange button is pressed a number of times, the number of |
656 | times the button was pressed will be written to that device. | 673 | times the button was pressed will be written to that device. |
657 | 674 | ||
658 | This is most useful for applications, as yet unwritten, which | 675 | This is most useful for applications, as yet unwritten, which |
659 | perform actions based on how many times the button is pressed in a | 676 | perform actions based on how many times the button is pressed in a |
660 | row. | 677 | row. |
661 | 678 | ||
662 | Do not hold the button down for too long, as the driver does not | 679 | Do not hold the button down for too long, as the driver does not |
663 | alter the behaviour of the hardware reset circuitry attached to the | 680 | alter the behaviour of the hardware reset circuitry attached to the |
664 | button; it will still execute a hard reset if the button is held | 681 | button; it will still execute a hard reset if the button is held |
665 | down for longer than approximately five seconds. | 682 | down for longer than approximately five seconds. |
666 | 683 | ||
667 | To compile this driver as a module, choose M here: the | 684 | To compile this driver as a module, choose M here: the |
668 | module will be called nwbutton. | 685 | module will be called nwbutton. |
669 | 686 | ||
670 | Most people will answer Y to this question and "Reboot Using Button" | 687 | Most people will answer Y to this question and "Reboot Using Button" |
671 | below to be able to initiate a system shutdown from the button. | 688 | below to be able to initiate a system shutdown from the button. |
672 | 689 | ||
673 | config NWBUTTON_REBOOT | 690 | config NWBUTTON_REBOOT |
674 | bool "Reboot Using Button" | 691 | bool "Reboot Using Button" |
675 | depends on NWBUTTON | 692 | depends on NWBUTTON |
676 | help | 693 | help |
677 | If you say Y here, then you will be able to initiate a system | 694 | If you say Y here, then you will be able to initiate a system |
678 | shutdown and reboot by pressing the orange button a number of times. | 695 | shutdown and reboot by pressing the orange button a number of times. |
679 | The number of presses to initiate the shutdown is two by default, | 696 | The number of presses to initiate the shutdown is two by default, |
680 | but this can be altered by modifying the value of NUM_PRESSES_REBOOT | 697 | but this can be altered by modifying the value of NUM_PRESSES_REBOOT |
681 | in nwbutton.h and recompiling the driver or, if you compile the | 698 | in nwbutton.h and recompiling the driver or, if you compile the |
682 | driver as a module, you can specify the number of presses at load | 699 | driver as a module, you can specify the number of presses at load |
683 | time with "insmod button reboot_count=<something>". | 700 | time with "insmod button reboot_count=<something>". |
684 | 701 | ||
685 | config NWFLASH | 702 | config NWFLASH |
686 | tristate "NetWinder flash support" | 703 | tristate "NetWinder flash support" |
687 | depends on ARCH_NETWINDER | 704 | depends on ARCH_NETWINDER |
688 | ---help--- | 705 | ---help--- |
689 | If you say Y here and create a character device /dev/flash with | 706 | If you say Y here and create a character device /dev/flash with |
690 | major 10 and minor 160 you can manipulate the flash ROM containing | 707 | major 10 and minor 160 you can manipulate the flash ROM containing |
691 | the NetWinder firmware. Be careful as accidentally overwriting the | 708 | the NetWinder firmware. Be careful as accidentally overwriting the |
692 | flash contents can render your computer unbootable. On no account | 709 | flash contents can render your computer unbootable. On no account |
693 | allow random users access to this device. :-) | 710 | allow random users access to this device. :-) |
694 | 711 | ||
695 | To compile this driver as a module, choose M here: the | 712 | To compile this driver as a module, choose M here: the |
696 | module will be called nwflash. | 713 | module will be called nwflash. |
697 | 714 | ||
698 | If you're not sure, say N. | 715 | If you're not sure, say N. |
699 | 716 | ||
700 | source "drivers/char/hw_random/Kconfig" | 717 | source "drivers/char/hw_random/Kconfig" |
701 | 718 | ||
702 | config NVRAM | 719 | config NVRAM |
703 | tristate "/dev/nvram support" | 720 | tristate "/dev/nvram support" |
704 | depends on ATARI || X86 || ARM || GENERIC_NVRAM | 721 | depends on ATARI || X86 || ARM || GENERIC_NVRAM |
705 | ---help--- | 722 | ---help--- |
706 | If you say Y here and create a character special file /dev/nvram | 723 | If you say Y here and create a character special file /dev/nvram |
707 | with major number 10 and minor number 144 using mknod ("man mknod"), | 724 | with major number 10 and minor number 144 using mknod ("man mknod"), |
708 | you get read and write access to the extra bytes of non-volatile | 725 | you get read and write access to the extra bytes of non-volatile |
709 | memory in the real time clock (RTC), which is contained in every PC | 726 | memory in the real time clock (RTC), which is contained in every PC |
710 | and most Ataris. The actual number of bytes varies, depending on the | 727 | and most Ataris. The actual number of bytes varies, depending on the |
711 | nvram in the system, but is usually 114 (128-14 for the RTC). | 728 | nvram in the system, but is usually 114 (128-14 for the RTC). |
712 | 729 | ||
713 | This memory is conventionally called "CMOS RAM" on PCs and "NVRAM" | 730 | This memory is conventionally called "CMOS RAM" on PCs and "NVRAM" |
714 | on Ataris. /dev/nvram may be used to view settings there, or to | 731 | on Ataris. /dev/nvram may be used to view settings there, or to |
715 | change them (with some utility). It could also be used to frequently | 732 | change them (with some utility). It could also be used to frequently |
716 | save a few bits of very important data that may not be lost over | 733 | save a few bits of very important data that may not be lost over |
717 | power-off and for which writing to disk is too insecure. Note | 734 | power-off and for which writing to disk is too insecure. Note |
718 | however that most NVRAM space in a PC belongs to the BIOS and you | 735 | however that most NVRAM space in a PC belongs to the BIOS and you |
719 | should NEVER idly tamper with it. See Ralf Brown's interrupt list | 736 | should NEVER idly tamper with it. See Ralf Brown's interrupt list |
720 | for a guide to the use of CMOS bytes by your BIOS. | 737 | for a guide to the use of CMOS bytes by your BIOS. |
721 | 738 | ||
722 | On Atari machines, /dev/nvram is always configured and does not need | 739 | On Atari machines, /dev/nvram is always configured and does not need |
723 | to be selected. | 740 | to be selected. |
724 | 741 | ||
725 | To compile this driver as a module, choose M here: the | 742 | To compile this driver as a module, choose M here: the |
726 | module will be called nvram. | 743 | module will be called nvram. |
727 | 744 | ||
728 | config RTC | 745 | config RTC |
729 | tristate "Enhanced Real Time Clock Support" | 746 | tristate "Enhanced Real Time Clock Support" |
730 | depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 | 747 | depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 |
731 | ---help--- | 748 | ---help--- |
732 | If you say Y here and create a character special file /dev/rtc with | 749 | If you say Y here and create a character special file /dev/rtc with |
733 | major number 10 and minor number 135 using mknod ("man mknod"), you | 750 | major number 10 and minor number 135 using mknod ("man mknod"), you |
734 | will get access to the real time clock (or hardware clock) built | 751 | will get access to the real time clock (or hardware clock) built |
735 | into your computer. | 752 | into your computer. |
736 | 753 | ||
737 | Every PC has such a clock built in. It can be used to generate | 754 | Every PC has such a clock built in. It can be used to generate |
738 | signals from as low as 1Hz up to 8192Hz, and can also be used | 755 | signals from as low as 1Hz up to 8192Hz, and can also be used |
739 | as a 24 hour alarm. It reports status information via the file | 756 | as a 24 hour alarm. It reports status information via the file |
740 | /proc/driver/rtc and its behaviour is set by various ioctls on | 757 | /proc/driver/rtc and its behaviour is set by various ioctls on |
741 | /dev/rtc. | 758 | /dev/rtc. |
742 | 759 | ||
743 | If you run Linux on a multiprocessor machine and said Y to | 760 | If you run Linux on a multiprocessor machine and said Y to |
744 | "Symmetric Multi Processing" above, you should say Y here to read | 761 | "Symmetric Multi Processing" above, you should say Y here to read |
745 | and set the RTC in an SMP compatible fashion. | 762 | and set the RTC in an SMP compatible fashion. |
746 | 763 | ||
747 | If you think you have a use for such a device (such as periodic data | 764 | If you think you have a use for such a device (such as periodic data |
748 | sampling), then say Y here, and read <file:Documentation/rtc.txt> | 765 | sampling), then say Y here, and read <file:Documentation/rtc.txt> |
749 | for details. | 766 | for details. |
750 | 767 | ||
751 | To compile this driver as a module, choose M here: the | 768 | To compile this driver as a module, choose M here: the |
752 | module will be called rtc. | 769 | module will be called rtc. |
753 | 770 | ||
754 | config JS_RTC | 771 | config JS_RTC |
755 | tristate "Enhanced Real Time Clock Support" | 772 | tristate "Enhanced Real Time Clock Support" |
756 | depends on SPARC32 && PCI | 773 | depends on SPARC32 && PCI |
757 | ---help--- | 774 | ---help--- |
758 | If you say Y here and create a character special file /dev/rtc with | 775 | If you say Y here and create a character special file /dev/rtc with |
759 | major number 10 and minor number 135 using mknod ("man mknod"), you | 776 | major number 10 and minor number 135 using mknod ("man mknod"), you |
760 | will get access to the real time clock (or hardware clock) built | 777 | will get access to the real time clock (or hardware clock) built |
761 | into your computer. | 778 | into your computer. |
762 | 779 | ||
763 | Every PC has such a clock built in. It can be used to generate | 780 | Every PC has such a clock built in. It can be used to generate |
764 | signals from as low as 1Hz up to 8192Hz, and can also be used | 781 | signals from as low as 1Hz up to 8192Hz, and can also be used |
765 | as a 24 hour alarm. It reports status information via the file | 782 | as a 24 hour alarm. It reports status information via the file |
766 | /proc/driver/rtc and its behaviour is set by various ioctls on | 783 | /proc/driver/rtc and its behaviour is set by various ioctls on |
767 | /dev/rtc. | 784 | /dev/rtc. |
768 | 785 | ||
769 | If you think you have a use for such a device (such as periodic data | 786 | If you think you have a use for such a device (such as periodic data |
770 | sampling), then say Y here, and read <file:Documentation/rtc.txt> | 787 | sampling), then say Y here, and read <file:Documentation/rtc.txt> |
771 | for details. | 788 | for details. |
772 | 789 | ||
773 | To compile this driver as a module, choose M here: the | 790 | To compile this driver as a module, choose M here: the |
774 | module will be called js-rtc. | 791 | module will be called js-rtc. |
775 | 792 | ||
776 | config SGI_DS1286 | 793 | config SGI_DS1286 |
777 | tristate "SGI DS1286 RTC support" | 794 | tristate "SGI DS1286 RTC support" |
778 | depends on SGI_IP22 | 795 | depends on SGI_IP22 |
779 | help | 796 | help |
780 | If you say Y here and create a character special file /dev/rtc with | 797 | If you say Y here and create a character special file /dev/rtc with |
781 | major number 10 and minor number 135 using mknod ("man mknod"), you | 798 | major number 10 and minor number 135 using mknod ("man mknod"), you |
782 | will get access to the real time clock built into your computer. | 799 | will get access to the real time clock built into your computer. |
783 | Every SGI has such a clock built in. It reports status information | 800 | Every SGI has such a clock built in. It reports status information |
784 | via the file /proc/rtc and its behaviour is set by various ioctls on | 801 | via the file /proc/rtc and its behaviour is set by various ioctls on |
785 | /dev/rtc. | 802 | /dev/rtc. |
786 | 803 | ||
787 | config SGI_IP27_RTC | 804 | config SGI_IP27_RTC |
788 | bool "SGI M48T35 RTC support" | 805 | bool "SGI M48T35 RTC support" |
789 | depends on SGI_IP27 | 806 | depends on SGI_IP27 |
790 | help | 807 | help |
791 | If you say Y here and create a character special file /dev/rtc with | 808 | If you say Y here and create a character special file /dev/rtc with |
792 | major number 10 and minor number 135 using mknod ("man mknod"), you | 809 | major number 10 and minor number 135 using mknod ("man mknod"), you |
793 | will get access to the real time clock built into your computer. | 810 | will get access to the real time clock built into your computer. |
794 | Every SGI has such a clock built in. It reports status information | 811 | Every SGI has such a clock built in. It reports status information |
795 | via the file /proc/rtc and its behaviour is set by various ioctls on | 812 | via the file /proc/rtc and its behaviour is set by various ioctls on |
796 | /dev/rtc. | 813 | /dev/rtc. |
797 | 814 | ||
798 | config GEN_RTC | 815 | config GEN_RTC |
799 | tristate "Generic /dev/rtc emulation" | 816 | tristate "Generic /dev/rtc emulation" |
800 | depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH | 817 | depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH |
801 | ---help--- | 818 | ---help--- |
802 | If you say Y here and create a character special file /dev/rtc with | 819 | If you say Y here and create a character special file /dev/rtc with |
803 | major number 10 and minor number 135 using mknod ("man mknod"), you | 820 | major number 10 and minor number 135 using mknod ("man mknod"), you |
804 | will get access to the real time clock (or hardware clock) built | 821 | will get access to the real time clock (or hardware clock) built |
805 | into your computer. | 822 | into your computer. |
806 | 823 | ||
807 | It reports status information via the file /proc/driver/rtc and its | 824 | It reports status information via the file /proc/driver/rtc and its |
808 | behaviour is set by various ioctls on /dev/rtc. If you enable the | 825 | behaviour is set by various ioctls on /dev/rtc. If you enable the |
809 | "extended RTC operation" below it will also provide an emulation | 826 | "extended RTC operation" below it will also provide an emulation |
810 | for RTC_UIE which is required by some programs and may improve | 827 | for RTC_UIE which is required by some programs and may improve |
811 | precision in some cases. | 828 | precision in some cases. |
812 | 829 | ||
813 | To compile this driver as a module, choose M here: the | 830 | To compile this driver as a module, choose M here: the |
814 | module will be called genrtc. | 831 | module will be called genrtc. |
815 | 832 | ||
816 | config GEN_RTC_X | 833 | config GEN_RTC_X |
817 | bool "Extended RTC operation" | 834 | bool "Extended RTC operation" |
818 | depends on GEN_RTC | 835 | depends on GEN_RTC |
819 | help | 836 | help |
820 | Provides an emulation for RTC_UIE which is required by some programs | 837 | Provides an emulation for RTC_UIE which is required by some programs |
821 | and may improve precision of the generic RTC support in some cases. | 838 | and may improve precision of the generic RTC support in some cases. |
822 | 839 | ||
823 | config EFI_RTC | 840 | config EFI_RTC |
824 | bool "EFI Real Time Clock Services" | 841 | bool "EFI Real Time Clock Services" |
825 | depends on IA64 | 842 | depends on IA64 |
826 | 843 | ||
827 | config DS1302 | 844 | config DS1302 |
828 | tristate "DS1302 RTC support" | 845 | tristate "DS1302 RTC support" |
829 | depends on M32R && (PLAT_M32700UT || PLAT_OPSPUT) | 846 | depends on M32R && (PLAT_M32700UT || PLAT_OPSPUT) |
830 | help | 847 | help |
831 | If you say Y here and create a character special file /dev/rtc with | 848 | If you say Y here and create a character special file /dev/rtc with |
832 | major number 121 and minor number 0 using mknod ("man mknod"), you | 849 | major number 121 and minor number 0 using mknod ("man mknod"), you |
833 | will get access to the real time clock (or hardware clock) built | 850 | will get access to the real time clock (or hardware clock) built |
834 | into your computer. | 851 | into your computer. |
835 | 852 | ||
836 | config COBALT_LCD | 853 | config COBALT_LCD |
837 | bool "Support for Cobalt LCD" | 854 | bool "Support for Cobalt LCD" |
838 | depends on MIPS_COBALT | 855 | depends on MIPS_COBALT |
839 | help | 856 | help |
840 | This option enables support for the LCD display and buttons found | 857 | This option enables support for the LCD display and buttons found |
841 | on Cobalt systems through a misc device. | 858 | on Cobalt systems through a misc device. |
842 | 859 | ||
843 | config DTLK | 860 | config DTLK |
844 | tristate "Double Talk PC internal speech card support" | 861 | tristate "Double Talk PC internal speech card support" |
845 | depends on ISA | 862 | depends on ISA |
846 | help | 863 | help |
847 | This driver is for the DoubleTalk PC, a speech synthesizer | 864 | This driver is for the DoubleTalk PC, a speech synthesizer |
848 | manufactured by RC Systems (<http://www.rcsys.com/>). It is also | 865 | manufactured by RC Systems (<http://www.rcsys.com/>). It is also |
849 | called the `internal DoubleTalk'. | 866 | called the `internal DoubleTalk'. |
850 | 867 | ||
851 | To compile this driver as a module, choose M here: the | 868 | To compile this driver as a module, choose M here: the |
852 | module will be called dtlk. | 869 | module will be called dtlk. |
853 | 870 | ||
854 | config R3964 | 871 | config R3964 |
855 | tristate "Siemens R3964 line discipline" | 872 | tristate "Siemens R3964 line discipline" |
856 | ---help--- | 873 | ---help--- |
857 | This driver allows synchronous communication with devices using the | 874 | This driver allows synchronous communication with devices using the |
858 | Siemens R3964 packet protocol. Unless you are dealing with special | 875 | Siemens R3964 packet protocol. Unless you are dealing with special |
859 | hardware like PLCs, you are unlikely to need this. | 876 | hardware like PLCs, you are unlikely to need this. |
860 | 877 | ||
861 | To compile this driver as a module, choose M here: the | 878 | To compile this driver as a module, choose M here: the |
862 | module will be called n_r3964. | 879 | module will be called n_r3964. |
863 | 880 | ||
864 | If unsure, say N. | 881 | If unsure, say N. |
865 | 882 | ||
866 | config APPLICOM | 883 | config APPLICOM |
867 | tristate "Applicom intelligent fieldbus card support" | 884 | tristate "Applicom intelligent fieldbus card support" |
868 | depends on PCI | 885 | depends on PCI |
869 | ---help--- | 886 | ---help--- |
870 | This driver provides the kernel-side support for the intelligent | 887 | This driver provides the kernel-side support for the intelligent |
871 | fieldbus cards made by Applicom International. More information | 888 | fieldbus cards made by Applicom International. More information |
872 | about these cards can be found on the WWW at the address | 889 | about these cards can be found on the WWW at the address |
873 | <http://www.applicom-int.com/>, or by email from David Woodhouse | 890 | <http://www.applicom-int.com/>, or by email from David Woodhouse |
874 | <dwmw2@infradead.org>. | 891 | <dwmw2@infradead.org>. |
875 | 892 | ||
876 | To compile this driver as a module, choose M here: the | 893 | To compile this driver as a module, choose M here: the |
877 | module will be called applicom. | 894 | module will be called applicom. |
878 | 895 | ||
879 | If unsure, say N. | 896 | If unsure, say N. |
880 | 897 | ||
881 | config SONYPI | 898 | config SONYPI |
882 | tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)" | 899 | tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)" |
883 | depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT | 900 | depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT |
884 | ---help--- | 901 | ---help--- |
885 | This driver enables access to the Sony Programmable I/O Control | 902 | This driver enables access to the Sony Programmable I/O Control |
886 | Device which can be found in many (all ?) Sony Vaio laptops. | 903 | Device which can be found in many (all ?) Sony Vaio laptops. |
887 | 904 | ||
888 | If you have one of those laptops, read | 905 | If you have one of those laptops, read |
889 | <file:Documentation/sonypi.txt>, and say Y or M here. | 906 | <file:Documentation/sonypi.txt>, and say Y or M here. |
890 | 907 | ||
891 | To compile this driver as a module, choose M here: the | 908 | To compile this driver as a module, choose M here: the |
892 | module will be called sonypi. | 909 | module will be called sonypi. |
893 | 910 | ||
894 | config GPIO_TB0219 | 911 | config GPIO_TB0219 |
895 | tristate "TANBAC TB0219 GPIO support" | 912 | tristate "TANBAC TB0219 GPIO support" |
896 | depends on TANBAC_TB022X | 913 | depends on TANBAC_TB022X |
897 | select GPIO_VR41XX | 914 | select GPIO_VR41XX |
898 | 915 | ||
899 | source "drivers/char/pcmcia/Kconfig" | 916 | source "drivers/char/pcmcia/Kconfig" |
900 | 917 | ||
901 | config MWAVE | 918 | config MWAVE |
902 | tristate "ACP Modem (Mwave) support" | 919 | tristate "ACP Modem (Mwave) support" |
903 | depends on X86 | 920 | depends on X86 |
904 | select SERIAL_8250 | 921 | select SERIAL_8250 |
905 | ---help--- | 922 | ---help--- |
906 | The ACP modem (Mwave) for Linux is a WinModem. It is composed of a | 923 | The ACP modem (Mwave) for Linux is a WinModem. It is composed of a |
907 | kernel driver and a user level application. Together these components | 924 | kernel driver and a user level application. Together these components |
908 | support direct attachment to public switched telephone networks (PSTNs) | 925 | support direct attachment to public switched telephone networks (PSTNs) |
909 | and support selected world wide countries. | 926 | and support selected world wide countries. |
910 | 927 | ||
911 | This version of the ACP Modem driver supports the IBM Thinkpad 600E, | 928 | This version of the ACP Modem driver supports the IBM Thinkpad 600E, |
912 | 600, and 770 that include on board ACP modem hardware. | 929 | 600, and 770 that include on board ACP modem hardware. |
913 | 930 | ||
914 | The modem also supports the standard communications port interface | 931 | The modem also supports the standard communications port interface |
915 | (ttySx) and is compatible with the Hayes AT Command Set. | 932 | (ttySx) and is compatible with the Hayes AT Command Set. |
916 | 933 | ||
917 | The user level application needed to use this driver can be found at | 934 | The user level application needed to use this driver can be found at |
918 | the IBM Linux Technology Center (LTC) web site: | 935 | the IBM Linux Technology Center (LTC) web site: |
919 | <http://www.ibm.com/linux/ltc/>. | 936 | <http://www.ibm.com/linux/ltc/>. |
920 | 937 | ||
921 | If you own one of the above IBM Thinkpads which has the Mwave chipset | 938 | If you own one of the above IBM Thinkpads which has the Mwave chipset |
922 | in it, say Y. | 939 | in it, say Y. |
923 | 940 | ||
924 | To compile this driver as a module, choose M here: the | 941 | To compile this driver as a module, choose M here: the |
925 | module will be called mwave. | 942 | module will be called mwave. |
926 | 943 | ||
927 | config SCx200_GPIO | 944 | config SCx200_GPIO |
928 | tristate "NatSemi SCx200 GPIO Support" | 945 | tristate "NatSemi SCx200 GPIO Support" |
929 | depends on SCx200 | 946 | depends on SCx200 |
930 | select NSC_GPIO | 947 | select NSC_GPIO |
931 | help | 948 | help |
932 | Give userspace access to the GPIO pins on the National | 949 | Give userspace access to the GPIO pins on the National |
933 | Semiconductor SCx200 processors. | 950 | Semiconductor SCx200 processors. |
934 | 951 | ||
935 | If compiled as a module, it will be called scx200_gpio. | 952 | If compiled as a module, it will be called scx200_gpio. |
936 | 953 | ||
937 | config PC8736x_GPIO | 954 | config PC8736x_GPIO |
938 | tristate "NatSemi PC8736x GPIO Support" | 955 | tristate "NatSemi PC8736x GPIO Support" |
939 | depends on X86 | 956 | depends on X86 |
940 | default SCx200_GPIO # mostly N | 957 | default SCx200_GPIO # mostly N |
941 | select NSC_GPIO # needed for support routines | 958 | select NSC_GPIO # needed for support routines |
942 | help | 959 | help |
943 | Give userspace access to the GPIO pins on the National | 960 | Give userspace access to the GPIO pins on the National |
944 | Semiconductor PC-8736x (x=[03456]) SuperIO chip. The chip | 961 | Semiconductor PC-8736x (x=[03456]) SuperIO chip. The chip |
945 | has multiple functional units, inc several managed by | 962 | has multiple functional units, inc several managed by |
946 | hwmon/pc87360 driver. Tested with PC-87366 | 963 | hwmon/pc87360 driver. Tested with PC-87366 |
947 | 964 | ||
948 | If compiled as a module, it will be called pc8736x_gpio. | 965 | If compiled as a module, it will be called pc8736x_gpio. |
949 | 966 | ||
950 | config NSC_GPIO | 967 | config NSC_GPIO |
951 | tristate "NatSemi Base GPIO Support" | 968 | tristate "NatSemi Base GPIO Support" |
952 | depends on X86_32 | 969 | depends on X86_32 |
953 | # selected by SCx200_GPIO and PC8736x_GPIO | 970 | # selected by SCx200_GPIO and PC8736x_GPIO |
954 | # what about 2 selectors differing: m != y | 971 | # what about 2 selectors differing: m != y |
955 | help | 972 | help |
956 | Common support used (and needed) by scx200_gpio and | 973 | Common support used (and needed) by scx200_gpio and |
957 | pc8736x_gpio drivers. If those drivers are built as | 974 | pc8736x_gpio drivers. If those drivers are built as |
958 | modules, this one will be too, named nsc_gpio | 975 | modules, this one will be too, named nsc_gpio |
959 | 976 | ||
960 | config CS5535_GPIO | 977 | config CS5535_GPIO |
961 | tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" | 978 | tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" |
962 | depends on X86_32 | 979 | depends on X86_32 |
963 | help | 980 | help |
964 | Give userspace access to the GPIO pins on the AMD CS5535 and | 981 | Give userspace access to the GPIO pins on the AMD CS5535 and |
965 | CS5536 Geode companion devices. | 982 | CS5536 Geode companion devices. |
966 | 983 | ||
967 | If compiled as a module, it will be called cs5535_gpio. | 984 | If compiled as a module, it will be called cs5535_gpio. |
968 | 985 | ||
969 | config GPIO_VR41XX | 986 | config GPIO_VR41XX |
970 | tristate "NEC VR4100 series General-purpose I/O Unit support" | 987 | tristate "NEC VR4100 series General-purpose I/O Unit support" |
971 | depends on CPU_VR41XX | 988 | depends on CPU_VR41XX |
972 | 989 | ||
973 | config RAW_DRIVER | 990 | config RAW_DRIVER |
974 | tristate "RAW driver (/dev/raw/rawN)" | 991 | tristate "RAW driver (/dev/raw/rawN)" |
975 | depends on BLOCK | 992 | depends on BLOCK |
976 | help | 993 | help |
977 | The raw driver permits block devices to be bound to /dev/raw/rawN. | 994 | The raw driver permits block devices to be bound to /dev/raw/rawN. |
978 | Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. | 995 | Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. |
979 | See the raw(8) manpage for more details. | 996 | See the raw(8) manpage for more details. |
980 | 997 | ||
981 | Applications should preferably open the device (eg /dev/hda1) | 998 | Applications should preferably open the device (eg /dev/hda1) |
982 | with the O_DIRECT flag. | 999 | with the O_DIRECT flag. |
983 | 1000 | ||
984 | config MAX_RAW_DEVS | 1001 | config MAX_RAW_DEVS |
985 | int "Maximum number of RAW devices to support (1-8192)" | 1002 | int "Maximum number of RAW devices to support (1-8192)" |
986 | depends on RAW_DRIVER | 1003 | depends on RAW_DRIVER |
987 | default "256" | 1004 | default "256" |
988 | help | 1005 | help |
989 | The maximum number of RAW devices that are supported. | 1006 | The maximum number of RAW devices that are supported. |
990 | Default is 256. Increase this number in case you need lots of | 1007 | Default is 256. Increase this number in case you need lots of |
991 | raw devices. | 1008 | raw devices. |
992 | 1009 | ||
993 | config HPET | 1010 | config HPET |
994 | bool "HPET - High Precision Event Timer" if (X86 || IA64) | 1011 | bool "HPET - High Precision Event Timer" if (X86 || IA64) |
995 | default n | 1012 | default n |
996 | depends on ACPI | 1013 | depends on ACPI |
997 | help | 1014 | help |
998 | If you say Y here, you will have a miscdevice named "/dev/hpet/". Each | 1015 | If you say Y here, you will have a miscdevice named "/dev/hpet/". Each |
999 | open selects one of the timers supported by the HPET. The timers are | 1016 | open selects one of the timers supported by the HPET. The timers are |
1000 | non-periodic and/or periodic. | 1017 | non-periodic and/or periodic. |
1001 | 1018 | ||
1002 | config HPET_RTC_IRQ | 1019 | config HPET_RTC_IRQ |
1003 | bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC | 1020 | bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC |
1004 | default n | 1021 | default n |
1005 | depends on HPET | 1022 | depends on HPET |
1006 | help | 1023 | help |
1007 | If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It | 1024 | If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It |
1008 | is assumed the platform called hpet_alloc with the RTC IRQ values for | 1025 | is assumed the platform called hpet_alloc with the RTC IRQ values for |
1009 | the HPET timers. | 1026 | the HPET timers. |
1010 | 1027 | ||
1011 | config HPET_MMAP | 1028 | config HPET_MMAP |
1012 | bool "Allow mmap of HPET" | 1029 | bool "Allow mmap of HPET" |
1013 | default y | 1030 | default y |
1014 | depends on HPET | 1031 | depends on HPET |
1015 | help | 1032 | help |
1016 | If you say Y here, user applications will be able to mmap | 1033 | If you say Y here, user applications will be able to mmap |
1017 | the HPET registers. | 1034 | the HPET registers. |
1018 | 1035 | ||
1019 | In some hardware implementations, the page containing HPET | 1036 | In some hardware implementations, the page containing HPET |
1020 | registers may also contain other things that shouldn't be | 1037 | registers may also contain other things that shouldn't be |
1021 | exposed to the user. If this applies to your hardware, | 1038 | exposed to the user. If this applies to your hardware, |
1022 | say N here. | 1039 | say N here. |
1023 | 1040 | ||
1024 | config HANGCHECK_TIMER | 1041 | config HANGCHECK_TIMER |
1025 | tristate "Hangcheck timer" | 1042 | tristate "Hangcheck timer" |
1026 | depends on X86 || IA64 || PPC64 || S390 | 1043 | depends on X86 || IA64 || PPC64 || S390 |
1027 | help | 1044 | help |
1028 | The hangcheck-timer module detects when the system has gone | 1045 | The hangcheck-timer module detects when the system has gone |
1029 | out to lunch past a certain margin. It can reboot the system | 1046 | out to lunch past a certain margin. It can reboot the system |
1030 | or merely print a warning. | 1047 | or merely print a warning. |
1031 | 1048 | ||
1032 | config MMTIMER | 1049 | config MMTIMER |
1033 | tristate "MMTIMER Memory mapped RTC for SGI Altix" | 1050 | tristate "MMTIMER Memory mapped RTC for SGI Altix" |
1034 | depends on IA64_GENERIC || IA64_SGI_SN2 | 1051 | depends on IA64_GENERIC || IA64_SGI_SN2 |
1035 | default y | 1052 | default y |
1036 | help | 1053 | help |
1037 | The mmtimer device allows direct userspace access to the | 1054 | The mmtimer device allows direct userspace access to the |
1038 | Altix system timer. | 1055 | Altix system timer. |
1039 | 1056 | ||
1040 | source "drivers/char/tpm/Kconfig" | 1057 | source "drivers/char/tpm/Kconfig" |
1041 | 1058 | ||
1042 | config TELCLOCK | 1059 | config TELCLOCK |
1043 | tristate "Telecom clock driver for ATCA SBC" | 1060 | tristate "Telecom clock driver for ATCA SBC" |
1044 | depends on EXPERIMENTAL && X86 | 1061 | depends on EXPERIMENTAL && X86 |
1045 | default n | 1062 | default n |
1046 | help | 1063 | help |
1047 | The telecom clock device is specific to the MPCBL0010 and MPCBL0050 | 1064 | The telecom clock device is specific to the MPCBL0010 and MPCBL0050 |
1048 | ATCA computers and allows direct userspace access to the | 1065 | ATCA computers and allows direct userspace access to the |
1049 | configuration of the telecom clock configuration settings. This | 1066 | configuration of the telecom clock configuration settings. This |
1050 | device is used for hardware synchronization across the ATCA backplane | 1067 | device is used for hardware synchronization across the ATCA backplane |
1051 | fabric. Upon loading, the driver exports a sysfs directory, | 1068 | fabric. Upon loading, the driver exports a sysfs directory, |
1052 | /sys/devices/platform/telco_clock, with a number of files for | 1069 | /sys/devices/platform/telco_clock, with a number of files for |
1053 | controlling the behavior of this hardware. | 1070 | controlling the behavior of this hardware. |
1054 | 1071 | ||
1055 | config DEVPORT | 1072 | config DEVPORT |
1056 | bool | 1073 | bool |
1057 | depends on !M68K | 1074 | depends on !M68K |
1058 | depends on ISA || PCI | 1075 | depends on ISA || PCI |
1059 | default y | 1076 | default y |
1060 | 1077 | ||
1061 | source "drivers/s390/char/Kconfig" | 1078 | source "drivers/s390/char/Kconfig" |
1062 | 1079 | ||
1063 | endmenu | 1080 | endmenu |
1064 | 1081 | ||
1065 | 1082 |
drivers/char/keyboard.c
1 | /* | 1 | /* |
2 | * linux/drivers/char/keyboard.c | 2 | * linux/drivers/char/keyboard.c |
3 | * | 3 | * |
4 | * Written for linux by Johan Myreen as a translation from | 4 | * Written for linux by Johan Myreen as a translation from |
5 | * the assembly version by Linus (with diacriticals added) | 5 | * the assembly version by Linus (with diacriticals added) |
6 | * | 6 | * |
7 | * Some additional features added by Christoph Niemann (ChN), March 1993 | 7 | * Some additional features added by Christoph Niemann (ChN), March 1993 |
8 | * | 8 | * |
9 | * Loadable keymaps by Risto Kankkunen, May 1993 | 9 | * Loadable keymaps by Risto Kankkunen, May 1993 |
10 | * | 10 | * |
11 | * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 | 11 | * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 |
12 | * Added decr/incr_console, dynamic keymaps, Unicode support, | 12 | * Added decr/incr_console, dynamic keymaps, Unicode support, |
13 | * dynamic function/string keys, led setting, Sept 1994 | 13 | * dynamic function/string keys, led setting, Sept 1994 |
14 | * `Sticky' modifier keys, 951006. | 14 | * `Sticky' modifier keys, 951006. |
15 | * | 15 | * |
16 | * 11-11-96: SAK should now work in the raw mode (Martin Mares) | 16 | * 11-11-96: SAK should now work in the raw mode (Martin Mares) |
17 | * | 17 | * |
18 | * Modified to provide 'generic' keyboard support by Hamish Macdonald | 18 | * Modified to provide 'generic' keyboard support by Hamish Macdonald |
19 | * Merge with the m68k keyboard driver and split-off of the PC low-level | 19 | * Merge with the m68k keyboard driver and split-off of the PC low-level |
20 | * parts by Geert Uytterhoeven, May 1997 | 20 | * parts by Geert Uytterhoeven, May 1997 |
21 | * | 21 | * |
22 | * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) | 22 | * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) |
23 | * 30-07-98: Dead keys redone, aeb@cwi.nl. | 23 | * 30-07-98: Dead keys redone, aeb@cwi.nl. |
24 | * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) | 24 | * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/consolemap.h> | 27 | #include <linux/consolemap.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | #include <linux/tty.h> | 30 | #include <linux/tty.h> |
31 | #include <linux/tty_flip.h> | 31 | #include <linux/tty_flip.h> |
32 | #include <linux/mm.h> | 32 | #include <linux/mm.h> |
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/irq.h> | 36 | #include <linux/irq.h> |
37 | 37 | ||
38 | #include <linux/kbd_kern.h> | 38 | #include <linux/kbd_kern.h> |
39 | #include <linux/kbd_diacr.h> | 39 | #include <linux/kbd_diacr.h> |
40 | #include <linux/vt_kern.h> | 40 | #include <linux/vt_kern.h> |
41 | #include <linux/consolemap.h> | 41 | #include <linux/consolemap.h> |
42 | #include <linux/sysrq.h> | 42 | #include <linux/sysrq.h> |
43 | #include <linux/input.h> | 43 | #include <linux/input.h> |
44 | #include <linux/reboot.h> | 44 | #include <linux/reboot.h> |
45 | 45 | ||
46 | extern void ctrl_alt_del(void); | 46 | extern void ctrl_alt_del(void); |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Exported functions/variables | 49 | * Exported functions/variables |
50 | */ | 50 | */ |
51 | 51 | ||
52 | #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) | 52 | #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. | 55 | * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. |
56 | * This seems a good reason to start with NumLock off. On HIL keyboards | 56 | * This seems a good reason to start with NumLock off. On HIL keyboards |
57 | * of PARISC machines however there is no NumLock key and everyone expects the keypad | 57 | * of PARISC machines however there is no NumLock key and everyone expects the keypad |
58 | * to be used for numbers. | 58 | * to be used for numbers. |
59 | */ | 59 | */ |
60 | 60 | ||
61 | #if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) | 61 | #if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) |
62 | #define KBD_DEFLEDS (1 << VC_NUMLOCK) | 62 | #define KBD_DEFLEDS (1 << VC_NUMLOCK) |
63 | #else | 63 | #else |
64 | #define KBD_DEFLEDS 0 | 64 | #define KBD_DEFLEDS 0 |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | #define KBD_DEFLOCK 0 | 67 | #define KBD_DEFLOCK 0 |
68 | 68 | ||
69 | void compute_shiftstate(void); | 69 | void compute_shiftstate(void); |
70 | 70 | ||
71 | /* | 71 | /* |
72 | * Handler Tables. | 72 | * Handler Tables. |
73 | */ | 73 | */ |
74 | 74 | ||
75 | #define K_HANDLERS\ | 75 | #define K_HANDLERS\ |
76 | k_self, k_fn, k_spec, k_pad,\ | 76 | k_self, k_fn, k_spec, k_pad,\ |
77 | k_dead, k_cons, k_cur, k_shift,\ | 77 | k_dead, k_cons, k_cur, k_shift,\ |
78 | k_meta, k_ascii, k_lock, k_lowercase,\ | 78 | k_meta, k_ascii, k_lock, k_lowercase,\ |
79 | k_slock, k_dead2, k_brl, k_ignore | 79 | k_slock, k_dead2, k_brl, k_ignore |
80 | 80 | ||
81 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, | 81 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, |
82 | char up_flag); | 82 | char up_flag); |
83 | static k_handler_fn K_HANDLERS; | 83 | static k_handler_fn K_HANDLERS; |
84 | static k_handler_fn *k_handler[16] = { K_HANDLERS }; | 84 | static k_handler_fn *k_handler[16] = { K_HANDLERS }; |
85 | 85 | ||
86 | #define FN_HANDLERS\ | 86 | #define FN_HANDLERS\ |
87 | fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ | 87 | fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ |
88 | fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ | 88 | fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ |
89 | fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ | 89 | fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ |
90 | fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ | 90 | fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ |
91 | fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num | 91 | fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num |
92 | 92 | ||
93 | typedef void (fn_handler_fn)(struct vc_data *vc); | 93 | typedef void (fn_handler_fn)(struct vc_data *vc); |
94 | static fn_handler_fn FN_HANDLERS; | 94 | static fn_handler_fn FN_HANDLERS; |
95 | static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; | 95 | static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; |
96 | 96 | ||
97 | /* | 97 | /* |
98 | * Variables exported for vt_ioctl.c | 98 | * Variables exported for vt_ioctl.c |
99 | */ | 99 | */ |
100 | 100 | ||
101 | /* maximum values each key_handler can handle */ | 101 | /* maximum values each key_handler can handle */ |
102 | const int max_vals[] = { | 102 | const int max_vals[] = { |
103 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, | 103 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, |
104 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, | 104 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, |
105 | 255, NR_LOCK - 1, 255, NR_BRL - 1 | 105 | 255, NR_LOCK - 1, 255, NR_BRL - 1 |
106 | }; | 106 | }; |
107 | 107 | ||
108 | const int NR_TYPES = ARRAY_SIZE(max_vals); | 108 | const int NR_TYPES = ARRAY_SIZE(max_vals); |
109 | 109 | ||
110 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; | 110 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; |
111 | static struct kbd_struct *kbd = kbd_table; | 111 | static struct kbd_struct *kbd = kbd_table; |
112 | 112 | ||
113 | struct vt_spawn_console vt_spawn_con = { | 113 | struct vt_spawn_console vt_spawn_con = { |
114 | .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), | 114 | .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), |
115 | .pid = NULL, | 115 | .pid = NULL, |
116 | .sig = 0, | 116 | .sig = 0, |
117 | }; | 117 | }; |
118 | 118 | ||
119 | /* | 119 | /* |
120 | * Variables exported for vt.c | 120 | * Variables exported for vt.c |
121 | */ | 121 | */ |
122 | 122 | ||
123 | int shift_state = 0; | 123 | int shift_state = 0; |
124 | 124 | ||
125 | /* | 125 | /* |
126 | * Internal Data. | 126 | * Internal Data. |
127 | */ | 127 | */ |
128 | 128 | ||
129 | static struct input_handler kbd_handler; | 129 | static struct input_handler kbd_handler; |
130 | static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ | 130 | static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ |
131 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ | 131 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ |
132 | static int dead_key_next; | 132 | static int dead_key_next; |
133 | static int npadch = -1; /* -1 or number assembled on pad */ | 133 | static int npadch = -1; /* -1 or number assembled on pad */ |
134 | static unsigned int diacr; | 134 | static unsigned int diacr; |
135 | static char rep; /* flag telling character repeat */ | 135 | static char rep; /* flag telling character repeat */ |
136 | 136 | ||
137 | static unsigned char ledstate = 0xff; /* undefined */ | 137 | static unsigned char ledstate = 0xff; /* undefined */ |
138 | static unsigned char ledioctl; | 138 | static unsigned char ledioctl; |
139 | 139 | ||
140 | static struct ledptr { | 140 | static struct ledptr { |
141 | unsigned int *addr; | 141 | unsigned int *addr; |
142 | unsigned int mask; | 142 | unsigned int mask; |
143 | unsigned char valid:1; | 143 | unsigned char valid:1; |
144 | } ledptrs[3]; | 144 | } ledptrs[3]; |
145 | 145 | ||
146 | /* Simple translation table for the SysRq keys */ | 146 | /* Simple translation table for the SysRq keys */ |
147 | 147 | ||
148 | #ifdef CONFIG_MAGIC_SYSRQ | 148 | #ifdef CONFIG_MAGIC_SYSRQ |
149 | unsigned char kbd_sysrq_xlate[KEY_MAX + 1] = | 149 | unsigned char kbd_sysrq_xlate[KEY_MAX + 1] = |
150 | "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ | 150 | "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ |
151 | "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ | 151 | "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ |
152 | "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ | 152 | "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ |
153 | "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ | 153 | "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ |
154 | "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ | 154 | "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ |
155 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ | 155 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ |
156 | "\r\000/"; /* 0x60 - 0x6f */ | 156 | "\r\000/"; /* 0x60 - 0x6f */ |
157 | static int sysrq_down; | 157 | static int sysrq_down; |
158 | static int sysrq_alt_use; | 158 | static int sysrq_alt_use; |
159 | #endif | 159 | #endif |
160 | static int sysrq_alt; | 160 | static int sysrq_alt; |
161 | 161 | ||
162 | /* | 162 | /* |
163 | * Translation of scancodes to keycodes. We set them on only the first | 163 | * Translation of scancodes to keycodes. We set them on only the first |
164 | * keyboard in the list that accepts the scancode and keycode. | 164 | * keyboard in the list that accepts the scancode and keycode. |
165 | * Explanation for not choosing the first attached keyboard anymore: | 165 | * Explanation for not choosing the first attached keyboard anymore: |
166 | * USB keyboards for example have two event devices: one for all "normal" | 166 | * USB keyboards for example have two event devices: one for all "normal" |
167 | * keys and one for extra function keys (like "volume up", "make coffee", | 167 | * keys and one for extra function keys (like "volume up", "make coffee", |
168 | * etc.). So this means that scancodes for the extra function keys won't | 168 | * etc.). So this means that scancodes for the extra function keys won't |
169 | * be valid for the first event device, but will be for the second. | 169 | * be valid for the first event device, but will be for the second. |
170 | */ | 170 | */ |
171 | int getkeycode(unsigned int scancode) | 171 | int getkeycode(unsigned int scancode) |
172 | { | 172 | { |
173 | struct input_handle *handle; | 173 | struct input_handle *handle; |
174 | int keycode; | 174 | int keycode; |
175 | int error = -ENODEV; | 175 | int error = -ENODEV; |
176 | 176 | ||
177 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { | 177 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { |
178 | error = handle->dev->getkeycode(handle->dev, scancode, &keycode); | 178 | error = handle->dev->getkeycode(handle->dev, scancode, &keycode); |
179 | if (!error) | 179 | if (!error) |
180 | return keycode; | 180 | return keycode; |
181 | } | 181 | } |
182 | 182 | ||
183 | return error; | 183 | return error; |
184 | } | 184 | } |
185 | 185 | ||
186 | int setkeycode(unsigned int scancode, unsigned int keycode) | 186 | int setkeycode(unsigned int scancode, unsigned int keycode) |
187 | { | 187 | { |
188 | struct input_handle *handle; | 188 | struct input_handle *handle; |
189 | int error = -ENODEV; | 189 | int error = -ENODEV; |
190 | 190 | ||
191 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { | 191 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { |
192 | error = handle->dev->setkeycode(handle->dev, scancode, keycode); | 192 | error = handle->dev->setkeycode(handle->dev, scancode, keycode); |
193 | if (!error) | 193 | if (!error) |
194 | break; | 194 | break; |
195 | } | 195 | } |
196 | 196 | ||
197 | return error; | 197 | return error; |
198 | } | 198 | } |
199 | 199 | ||
200 | /* | 200 | /* |
201 | * Making beeps and bells. | 201 | * Making beeps and bells. |
202 | */ | 202 | */ |
203 | static void kd_nosound(unsigned long ignored) | 203 | static void kd_nosound(unsigned long ignored) |
204 | { | 204 | { |
205 | struct input_handle *handle; | 205 | struct input_handle *handle; |
206 | 206 | ||
207 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { | 207 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { |
208 | if (test_bit(EV_SND, handle->dev->evbit)) { | 208 | if (test_bit(EV_SND, handle->dev->evbit)) { |
209 | if (test_bit(SND_TONE, handle->dev->sndbit)) | 209 | if (test_bit(SND_TONE, handle->dev->sndbit)) |
210 | input_inject_event(handle, EV_SND, SND_TONE, 0); | 210 | input_inject_event(handle, EV_SND, SND_TONE, 0); |
211 | if (test_bit(SND_BELL, handle->dev->sndbit)) | 211 | if (test_bit(SND_BELL, handle->dev->sndbit)) |
212 | input_inject_event(handle, EV_SND, SND_BELL, 0); | 212 | input_inject_event(handle, EV_SND, SND_BELL, 0); |
213 | } | 213 | } |
214 | } | 214 | } |
215 | } | 215 | } |
216 | 216 | ||
217 | static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); | 217 | static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); |
218 | 218 | ||
219 | void kd_mksound(unsigned int hz, unsigned int ticks) | 219 | void kd_mksound(unsigned int hz, unsigned int ticks) |
220 | { | 220 | { |
221 | struct list_head *node; | 221 | struct list_head *node; |
222 | 222 | ||
223 | del_timer(&kd_mksound_timer); | 223 | del_timer(&kd_mksound_timer); |
224 | 224 | ||
225 | if (hz) { | 225 | if (hz) { |
226 | list_for_each_prev(node, &kbd_handler.h_list) { | 226 | list_for_each_prev(node, &kbd_handler.h_list) { |
227 | struct input_handle *handle = to_handle_h(node); | 227 | struct input_handle *handle = to_handle_h(node); |
228 | if (test_bit(EV_SND, handle->dev->evbit)) { | 228 | if (test_bit(EV_SND, handle->dev->evbit)) { |
229 | if (test_bit(SND_TONE, handle->dev->sndbit)) { | 229 | if (test_bit(SND_TONE, handle->dev->sndbit)) { |
230 | input_inject_event(handle, EV_SND, SND_TONE, hz); | 230 | input_inject_event(handle, EV_SND, SND_TONE, hz); |
231 | break; | 231 | break; |
232 | } | 232 | } |
233 | if (test_bit(SND_BELL, handle->dev->sndbit)) { | 233 | if (test_bit(SND_BELL, handle->dev->sndbit)) { |
234 | input_inject_event(handle, EV_SND, SND_BELL, 1); | 234 | input_inject_event(handle, EV_SND, SND_BELL, 1); |
235 | break; | 235 | break; |
236 | } | 236 | } |
237 | } | 237 | } |
238 | } | 238 | } |
239 | if (ticks) | 239 | if (ticks) |
240 | mod_timer(&kd_mksound_timer, jiffies + ticks); | 240 | mod_timer(&kd_mksound_timer, jiffies + ticks); |
241 | } else | 241 | } else |
242 | kd_nosound(0); | 242 | kd_nosound(0); |
243 | } | 243 | } |
244 | 244 | ||
245 | /* | 245 | /* |
246 | * Setting the keyboard rate. | 246 | * Setting the keyboard rate. |
247 | */ | 247 | */ |
248 | 248 | ||
249 | int kbd_rate(struct kbd_repeat *rep) | 249 | int kbd_rate(struct kbd_repeat *rep) |
250 | { | 250 | { |
251 | struct list_head *node; | 251 | struct list_head *node; |
252 | unsigned int d = 0; | 252 | unsigned int d = 0; |
253 | unsigned int p = 0; | 253 | unsigned int p = 0; |
254 | 254 | ||
255 | list_for_each(node, &kbd_handler.h_list) { | 255 | list_for_each(node, &kbd_handler.h_list) { |
256 | struct input_handle *handle = to_handle_h(node); | 256 | struct input_handle *handle = to_handle_h(node); |
257 | struct input_dev *dev = handle->dev; | 257 | struct input_dev *dev = handle->dev; |
258 | 258 | ||
259 | if (test_bit(EV_REP, dev->evbit)) { | 259 | if (test_bit(EV_REP, dev->evbit)) { |
260 | if (rep->delay > 0) | 260 | if (rep->delay > 0) |
261 | input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); | 261 | input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); |
262 | if (rep->period > 0) | 262 | if (rep->period > 0) |
263 | input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); | 263 | input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); |
264 | d = dev->rep[REP_DELAY]; | 264 | d = dev->rep[REP_DELAY]; |
265 | p = dev->rep[REP_PERIOD]; | 265 | p = dev->rep[REP_PERIOD]; |
266 | } | 266 | } |
267 | } | 267 | } |
268 | rep->delay = d; | 268 | rep->delay = d; |
269 | rep->period = p; | 269 | rep->period = p; |
270 | return 0; | 270 | return 0; |
271 | } | 271 | } |
272 | 272 | ||
273 | /* | 273 | /* |
274 | * Helper Functions. | 274 | * Helper Functions. |
275 | */ | 275 | */ |
276 | static void put_queue(struct vc_data *vc, int ch) | 276 | static void put_queue(struct vc_data *vc, int ch) |
277 | { | 277 | { |
278 | struct tty_struct *tty = vc->vc_tty; | 278 | struct tty_struct *tty = vc->vc_tty; |
279 | 279 | ||
280 | if (tty) { | 280 | if (tty) { |
281 | tty_insert_flip_char(tty, ch, 0); | 281 | tty_insert_flip_char(tty, ch, 0); |
282 | con_schedule_flip(tty); | 282 | con_schedule_flip(tty); |
283 | } | 283 | } |
284 | } | 284 | } |
285 | 285 | ||
286 | static void puts_queue(struct vc_data *vc, char *cp) | 286 | static void puts_queue(struct vc_data *vc, char *cp) |
287 | { | 287 | { |
288 | struct tty_struct *tty = vc->vc_tty; | 288 | struct tty_struct *tty = vc->vc_tty; |
289 | 289 | ||
290 | if (!tty) | 290 | if (!tty) |
291 | return; | 291 | return; |
292 | 292 | ||
293 | while (*cp) { | 293 | while (*cp) { |
294 | tty_insert_flip_char(tty, *cp, 0); | 294 | tty_insert_flip_char(tty, *cp, 0); |
295 | cp++; | 295 | cp++; |
296 | } | 296 | } |
297 | con_schedule_flip(tty); | 297 | con_schedule_flip(tty); |
298 | } | 298 | } |
299 | 299 | ||
300 | static void applkey(struct vc_data *vc, int key, char mode) | 300 | static void applkey(struct vc_data *vc, int key, char mode) |
301 | { | 301 | { |
302 | static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; | 302 | static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; |
303 | 303 | ||
304 | buf[1] = (mode ? 'O' : '['); | 304 | buf[1] = (mode ? 'O' : '['); |
305 | buf[2] = key; | 305 | buf[2] = key; |
306 | puts_queue(vc, buf); | 306 | puts_queue(vc, buf); |
307 | } | 307 | } |
308 | 308 | ||
309 | /* | 309 | /* |
310 | * Many other routines do put_queue, but I think either | 310 | * Many other routines do put_queue, but I think either |
311 | * they produce ASCII, or they produce some user-assigned | 311 | * they produce ASCII, or they produce some user-assigned |
312 | * string, and in both cases we might assume that it is | 312 | * string, and in both cases we might assume that it is |
313 | * in utf-8 already. | 313 | * in utf-8 already. |
314 | */ | 314 | */ |
315 | static void to_utf8(struct vc_data *vc, uint c) | 315 | static void to_utf8(struct vc_data *vc, uint c) |
316 | { | 316 | { |
317 | if (c < 0x80) | 317 | if (c < 0x80) |
318 | /* 0******* */ | 318 | /* 0******* */ |
319 | put_queue(vc, c); | 319 | put_queue(vc, c); |
320 | else if (c < 0x800) { | 320 | else if (c < 0x800) { |
321 | /* 110***** 10****** */ | 321 | /* 110***** 10****** */ |
322 | put_queue(vc, 0xc0 | (c >> 6)); | 322 | put_queue(vc, 0xc0 | (c >> 6)); |
323 | put_queue(vc, 0x80 | (c & 0x3f)); | 323 | put_queue(vc, 0x80 | (c & 0x3f)); |
324 | } else if (c < 0x10000) { | 324 | } else if (c < 0x10000) { |
325 | if (c >= 0xD800 && c < 0xE000) | 325 | if (c >= 0xD800 && c < 0xE000) |
326 | return; | 326 | return; |
327 | if (c == 0xFFFF) | 327 | if (c == 0xFFFF) |
328 | return; | 328 | return; |
329 | /* 1110**** 10****** 10****** */ | 329 | /* 1110**** 10****** 10****** */ |
330 | put_queue(vc, 0xe0 | (c >> 12)); | 330 | put_queue(vc, 0xe0 | (c >> 12)); |
331 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); | 331 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); |
332 | put_queue(vc, 0x80 | (c & 0x3f)); | 332 | put_queue(vc, 0x80 | (c & 0x3f)); |
333 | } else if (c < 0x110000) { | 333 | } else if (c < 0x110000) { |
334 | /* 11110*** 10****** 10****** 10****** */ | 334 | /* 11110*** 10****** 10****** 10****** */ |
335 | put_queue(vc, 0xf0 | (c >> 18)); | 335 | put_queue(vc, 0xf0 | (c >> 18)); |
336 | put_queue(vc, 0x80 | ((c >> 12) & 0x3f)); | 336 | put_queue(vc, 0x80 | ((c >> 12) & 0x3f)); |
337 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); | 337 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); |
338 | put_queue(vc, 0x80 | (c & 0x3f)); | 338 | put_queue(vc, 0x80 | (c & 0x3f)); |
339 | } | 339 | } |
340 | } | 340 | } |
341 | 341 | ||
342 | /* | 342 | /* |
343 | * Called after returning from RAW mode or when changing consoles - recompute | 343 | * Called after returning from RAW mode or when changing consoles - recompute |
344 | * shift_down[] and shift_state from key_down[] maybe called when keymap is | 344 | * shift_down[] and shift_state from key_down[] maybe called when keymap is |
345 | * undefined, so that shiftkey release is seen | 345 | * undefined, so that shiftkey release is seen |
346 | */ | 346 | */ |
347 | void compute_shiftstate(void) | 347 | void compute_shiftstate(void) |
348 | { | 348 | { |
349 | unsigned int i, j, k, sym, val; | 349 | unsigned int i, j, k, sym, val; |
350 | 350 | ||
351 | shift_state = 0; | 351 | shift_state = 0; |
352 | memset(shift_down, 0, sizeof(shift_down)); | 352 | memset(shift_down, 0, sizeof(shift_down)); |
353 | 353 | ||
354 | for (i = 0; i < ARRAY_SIZE(key_down); i++) { | 354 | for (i = 0; i < ARRAY_SIZE(key_down); i++) { |
355 | 355 | ||
356 | if (!key_down[i]) | 356 | if (!key_down[i]) |
357 | continue; | 357 | continue; |
358 | 358 | ||
359 | k = i * BITS_PER_LONG; | 359 | k = i * BITS_PER_LONG; |
360 | 360 | ||
361 | for (j = 0; j < BITS_PER_LONG; j++, k++) { | 361 | for (j = 0; j < BITS_PER_LONG; j++, k++) { |
362 | 362 | ||
363 | if (!test_bit(k, key_down)) | 363 | if (!test_bit(k, key_down)) |
364 | continue; | 364 | continue; |
365 | 365 | ||
366 | sym = U(key_maps[0][k]); | 366 | sym = U(key_maps[0][k]); |
367 | if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) | 367 | if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) |
368 | continue; | 368 | continue; |
369 | 369 | ||
370 | val = KVAL(sym); | 370 | val = KVAL(sym); |
371 | if (val == KVAL(K_CAPSSHIFT)) | 371 | if (val == KVAL(K_CAPSSHIFT)) |
372 | val = KVAL(K_SHIFT); | 372 | val = KVAL(K_SHIFT); |
373 | 373 | ||
374 | shift_down[val]++; | 374 | shift_down[val]++; |
375 | shift_state |= (1 << val); | 375 | shift_state |= (1 << val); |
376 | } | 376 | } |
377 | } | 377 | } |
378 | } | 378 | } |
379 | 379 | ||
380 | /* | 380 | /* |
381 | * We have a combining character DIACR here, followed by the character CH. | 381 | * We have a combining character DIACR here, followed by the character CH. |
382 | * If the combination occurs in the table, return the corresponding value. | 382 | * If the combination occurs in the table, return the corresponding value. |
383 | * Otherwise, if CH is a space or equals DIACR, return DIACR. | 383 | * Otherwise, if CH is a space or equals DIACR, return DIACR. |
384 | * Otherwise, conclude that DIACR was not combining after all, | 384 | * Otherwise, conclude that DIACR was not combining after all, |
385 | * queue it and return CH. | 385 | * queue it and return CH. |
386 | */ | 386 | */ |
387 | static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) | 387 | static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) |
388 | { | 388 | { |
389 | unsigned int d = diacr; | 389 | unsigned int d = diacr; |
390 | unsigned int i; | 390 | unsigned int i; |
391 | 391 | ||
392 | diacr = 0; | 392 | diacr = 0; |
393 | 393 | ||
394 | if ((d & ~0xff) == BRL_UC_ROW) { | 394 | if ((d & ~0xff) == BRL_UC_ROW) { |
395 | if ((ch & ~0xff) == BRL_UC_ROW) | 395 | if ((ch & ~0xff) == BRL_UC_ROW) |
396 | return d | ch; | 396 | return d | ch; |
397 | } else { | 397 | } else { |
398 | for (i = 0; i < accent_table_size; i++) | 398 | for (i = 0; i < accent_table_size; i++) |
399 | if (accent_table[i].diacr == d && accent_table[i].base == ch) | 399 | if (accent_table[i].diacr == d && accent_table[i].base == ch) |
400 | return accent_table[i].result; | 400 | return accent_table[i].result; |
401 | } | 401 | } |
402 | 402 | ||
403 | if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) | 403 | if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) |
404 | return d; | 404 | return d; |
405 | 405 | ||
406 | if (kbd->kbdmode == VC_UNICODE) | 406 | if (kbd->kbdmode == VC_UNICODE) |
407 | to_utf8(vc, d); | 407 | to_utf8(vc, d); |
408 | else { | 408 | else { |
409 | int c = conv_uni_to_8bit(d); | 409 | int c = conv_uni_to_8bit(d); |
410 | if (c != -1) | 410 | if (c != -1) |
411 | put_queue(vc, c); | 411 | put_queue(vc, c); |
412 | } | 412 | } |
413 | 413 | ||
414 | return ch; | 414 | return ch; |
415 | } | 415 | } |
416 | 416 | ||
417 | /* | 417 | /* |
418 | * Special function handlers | 418 | * Special function handlers |
419 | */ | 419 | */ |
420 | static void fn_enter(struct vc_data *vc) | 420 | static void fn_enter(struct vc_data *vc) |
421 | { | 421 | { |
422 | if (diacr) { | 422 | if (diacr) { |
423 | if (kbd->kbdmode == VC_UNICODE) | 423 | if (kbd->kbdmode == VC_UNICODE) |
424 | to_utf8(vc, diacr); | 424 | to_utf8(vc, diacr); |
425 | else { | 425 | else { |
426 | int c = conv_uni_to_8bit(diacr); | 426 | int c = conv_uni_to_8bit(diacr); |
427 | if (c != -1) | 427 | if (c != -1) |
428 | put_queue(vc, c); | 428 | put_queue(vc, c); |
429 | } | 429 | } |
430 | diacr = 0; | 430 | diacr = 0; |
431 | } | 431 | } |
432 | put_queue(vc, 13); | 432 | put_queue(vc, 13); |
433 | if (vc_kbd_mode(kbd, VC_CRLF)) | 433 | if (vc_kbd_mode(kbd, VC_CRLF)) |
434 | put_queue(vc, 10); | 434 | put_queue(vc, 10); |
435 | } | 435 | } |
436 | 436 | ||
437 | static void fn_caps_toggle(struct vc_data *vc) | 437 | static void fn_caps_toggle(struct vc_data *vc) |
438 | { | 438 | { |
439 | if (rep) | 439 | if (rep) |
440 | return; | 440 | return; |
441 | chg_vc_kbd_led(kbd, VC_CAPSLOCK); | 441 | chg_vc_kbd_led(kbd, VC_CAPSLOCK); |
442 | } | 442 | } |
443 | 443 | ||
444 | static void fn_caps_on(struct vc_data *vc) | 444 | static void fn_caps_on(struct vc_data *vc) |
445 | { | 445 | { |
446 | if (rep) | 446 | if (rep) |
447 | return; | 447 | return; |
448 | set_vc_kbd_led(kbd, VC_CAPSLOCK); | 448 | set_vc_kbd_led(kbd, VC_CAPSLOCK); |
449 | } | 449 | } |
450 | 450 | ||
451 | static void fn_show_ptregs(struct vc_data *vc) | 451 | static void fn_show_ptregs(struct vc_data *vc) |
452 | { | 452 | { |
453 | struct pt_regs *regs = get_irq_regs(); | 453 | struct pt_regs *regs = get_irq_regs(); |
454 | if (regs) | 454 | if (regs) |
455 | show_regs(regs); | 455 | show_regs(regs); |
456 | } | 456 | } |
457 | 457 | ||
458 | static void fn_hold(struct vc_data *vc) | 458 | static void fn_hold(struct vc_data *vc) |
459 | { | 459 | { |
460 | struct tty_struct *tty = vc->vc_tty; | 460 | struct tty_struct *tty = vc->vc_tty; |
461 | 461 | ||
462 | if (rep || !tty) | 462 | if (rep || !tty) |
463 | return; | 463 | return; |
464 | 464 | ||
465 | /* | 465 | /* |
466 | * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); | 466 | * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); |
467 | * these routines are also activated by ^S/^Q. | 467 | * these routines are also activated by ^S/^Q. |
468 | * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) | 468 | * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) |
469 | */ | 469 | */ |
470 | if (tty->stopped) | 470 | if (tty->stopped) |
471 | start_tty(tty); | 471 | start_tty(tty); |
472 | else | 472 | else |
473 | stop_tty(tty); | 473 | stop_tty(tty); |
474 | } | 474 | } |
475 | 475 | ||
476 | static void fn_num(struct vc_data *vc) | 476 | static void fn_num(struct vc_data *vc) |
477 | { | 477 | { |
478 | if (vc_kbd_mode(kbd,VC_APPLIC)) | 478 | if (vc_kbd_mode(kbd,VC_APPLIC)) |
479 | applkey(vc, 'P', 1); | 479 | applkey(vc, 'P', 1); |
480 | else | 480 | else |
481 | fn_bare_num(vc); | 481 | fn_bare_num(vc); |
482 | } | 482 | } |
483 | 483 | ||
484 | /* | 484 | /* |
485 | * Bind this to Shift-NumLock if you work in application keypad mode | 485 | * Bind this to Shift-NumLock if you work in application keypad mode |
486 | * but want to be able to change the NumLock flag. | 486 | * but want to be able to change the NumLock flag. |
487 | * Bind this to NumLock if you prefer that the NumLock key always | 487 | * Bind this to NumLock if you prefer that the NumLock key always |
488 | * changes the NumLock flag. | 488 | * changes the NumLock flag. |
489 | */ | 489 | */ |
490 | static void fn_bare_num(struct vc_data *vc) | 490 | static void fn_bare_num(struct vc_data *vc) |
491 | { | 491 | { |
492 | if (!rep) | 492 | if (!rep) |
493 | chg_vc_kbd_led(kbd, VC_NUMLOCK); | 493 | chg_vc_kbd_led(kbd, VC_NUMLOCK); |
494 | } | 494 | } |
495 | 495 | ||
496 | static void fn_lastcons(struct vc_data *vc) | 496 | static void fn_lastcons(struct vc_data *vc) |
497 | { | 497 | { |
498 | /* switch to the last used console, ChN */ | 498 | /* switch to the last used console, ChN */ |
499 | set_console(last_console); | 499 | set_console(last_console); |
500 | } | 500 | } |
501 | 501 | ||
502 | static void fn_dec_console(struct vc_data *vc) | 502 | static void fn_dec_console(struct vc_data *vc) |
503 | { | 503 | { |
504 | int i, cur = fg_console; | 504 | int i, cur = fg_console; |
505 | 505 | ||
506 | /* Currently switching? Queue this next switch relative to that. */ | 506 | /* Currently switching? Queue this next switch relative to that. */ |
507 | if (want_console != -1) | 507 | if (want_console != -1) |
508 | cur = want_console; | 508 | cur = want_console; |
509 | 509 | ||
510 | for (i = cur - 1; i != cur; i--) { | 510 | for (i = cur - 1; i != cur; i--) { |
511 | if (i == -1) | 511 | if (i == -1) |
512 | i = MAX_NR_CONSOLES - 1; | 512 | i = MAX_NR_CONSOLES - 1; |
513 | if (vc_cons_allocated(i)) | 513 | if (vc_cons_allocated(i)) |
514 | break; | 514 | break; |
515 | } | 515 | } |
516 | set_console(i); | 516 | set_console(i); |
517 | } | 517 | } |
518 | 518 | ||
519 | static void fn_inc_console(struct vc_data *vc) | 519 | static void fn_inc_console(struct vc_data *vc) |
520 | { | 520 | { |
521 | int i, cur = fg_console; | 521 | int i, cur = fg_console; |
522 | 522 | ||
523 | /* Currently switching? Queue this next switch relative to that. */ | 523 | /* Currently switching? Queue this next switch relative to that. */ |
524 | if (want_console != -1) | 524 | if (want_console != -1) |
525 | cur = want_console; | 525 | cur = want_console; |
526 | 526 | ||
527 | for (i = cur+1; i != cur; i++) { | 527 | for (i = cur+1; i != cur; i++) { |
528 | if (i == MAX_NR_CONSOLES) | 528 | if (i == MAX_NR_CONSOLES) |
529 | i = 0; | 529 | i = 0; |
530 | if (vc_cons_allocated(i)) | 530 | if (vc_cons_allocated(i)) |
531 | break; | 531 | break; |
532 | } | 532 | } |
533 | set_console(i); | 533 | set_console(i); |
534 | } | 534 | } |
535 | 535 | ||
536 | static void fn_send_intr(struct vc_data *vc) | 536 | static void fn_send_intr(struct vc_data *vc) |
537 | { | 537 | { |
538 | struct tty_struct *tty = vc->vc_tty; | 538 | struct tty_struct *tty = vc->vc_tty; |
539 | 539 | ||
540 | if (!tty) | 540 | if (!tty) |
541 | return; | 541 | return; |
542 | tty_insert_flip_char(tty, 0, TTY_BREAK); | 542 | tty_insert_flip_char(tty, 0, TTY_BREAK); |
543 | con_schedule_flip(tty); | 543 | con_schedule_flip(tty); |
544 | } | 544 | } |
545 | 545 | ||
546 | static void fn_scroll_forw(struct vc_data *vc) | 546 | static void fn_scroll_forw(struct vc_data *vc) |
547 | { | 547 | { |
548 | scrollfront(vc, 0); | 548 | scrollfront(vc, 0); |
549 | } | 549 | } |
550 | 550 | ||
551 | static void fn_scroll_back(struct vc_data *vc) | 551 | static void fn_scroll_back(struct vc_data *vc) |
552 | { | 552 | { |
553 | scrollback(vc, 0); | 553 | scrollback(vc, 0); |
554 | } | 554 | } |
555 | 555 | ||
556 | static void fn_show_mem(struct vc_data *vc) | 556 | static void fn_show_mem(struct vc_data *vc) |
557 | { | 557 | { |
558 | show_mem(); | 558 | show_mem(); |
559 | } | 559 | } |
560 | 560 | ||
561 | static void fn_show_state(struct vc_data *vc) | 561 | static void fn_show_state(struct vc_data *vc) |
562 | { | 562 | { |
563 | show_state(); | 563 | show_state(); |
564 | } | 564 | } |
565 | 565 | ||
566 | static void fn_boot_it(struct vc_data *vc) | 566 | static void fn_boot_it(struct vc_data *vc) |
567 | { | 567 | { |
568 | ctrl_alt_del(); | 568 | ctrl_alt_del(); |
569 | } | 569 | } |
570 | 570 | ||
571 | static void fn_compose(struct vc_data *vc) | 571 | static void fn_compose(struct vc_data *vc) |
572 | { | 572 | { |
573 | dead_key_next = 1; | 573 | dead_key_next = 1; |
574 | } | 574 | } |
575 | 575 | ||
576 | static void fn_spawn_con(struct vc_data *vc) | 576 | static void fn_spawn_con(struct vc_data *vc) |
577 | { | 577 | { |
578 | spin_lock(&vt_spawn_con.lock); | 578 | spin_lock(&vt_spawn_con.lock); |
579 | if (vt_spawn_con.pid) | 579 | if (vt_spawn_con.pid) |
580 | if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { | 580 | if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { |
581 | put_pid(vt_spawn_con.pid); | 581 | put_pid(vt_spawn_con.pid); |
582 | vt_spawn_con.pid = NULL; | 582 | vt_spawn_con.pid = NULL; |
583 | } | 583 | } |
584 | spin_unlock(&vt_spawn_con.lock); | 584 | spin_unlock(&vt_spawn_con.lock); |
585 | } | 585 | } |
586 | 586 | ||
587 | static void fn_SAK(struct vc_data *vc) | 587 | static void fn_SAK(struct vc_data *vc) |
588 | { | 588 | { |
589 | struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; | 589 | struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; |
590 | schedule_work(SAK_work); | 590 | schedule_work(SAK_work); |
591 | } | 591 | } |
592 | 592 | ||
593 | static void fn_null(struct vc_data *vc) | 593 | static void fn_null(struct vc_data *vc) |
594 | { | 594 | { |
595 | compute_shiftstate(); | 595 | compute_shiftstate(); |
596 | } | 596 | } |
597 | 597 | ||
598 | /* | 598 | /* |
599 | * Special key handlers | 599 | * Special key handlers |
600 | */ | 600 | */ |
601 | static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) | 601 | static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) |
602 | { | 602 | { |
603 | } | 603 | } |
604 | 604 | ||
605 | static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) | 605 | static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) |
606 | { | 606 | { |
607 | if (up_flag) | 607 | if (up_flag) |
608 | return; | 608 | return; |
609 | if (value >= ARRAY_SIZE(fn_handler)) | 609 | if (value >= ARRAY_SIZE(fn_handler)) |
610 | return; | 610 | return; |
611 | if ((kbd->kbdmode == VC_RAW || | 611 | if ((kbd->kbdmode == VC_RAW || |
612 | kbd->kbdmode == VC_MEDIUMRAW) && | 612 | kbd->kbdmode == VC_MEDIUMRAW) && |
613 | value != KVAL(K_SAK)) | 613 | value != KVAL(K_SAK)) |
614 | return; /* SAK is allowed even in raw mode */ | 614 | return; /* SAK is allowed even in raw mode */ |
615 | fn_handler[value](vc); | 615 | fn_handler[value](vc); |
616 | } | 616 | } |
617 | 617 | ||
618 | static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) | 618 | static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) |
619 | { | 619 | { |
620 | printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); | 620 | printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); |
621 | } | 621 | } |
622 | 622 | ||
623 | static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) | 623 | static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) |
624 | { | 624 | { |
625 | if (up_flag) | 625 | if (up_flag) |
626 | return; /* no action, if this is a key release */ | 626 | return; /* no action, if this is a key release */ |
627 | 627 | ||
628 | if (diacr) | 628 | if (diacr) |
629 | value = handle_diacr(vc, value); | 629 | value = handle_diacr(vc, value); |
630 | 630 | ||
631 | if (dead_key_next) { | 631 | if (dead_key_next) { |
632 | dead_key_next = 0; | 632 | dead_key_next = 0; |
633 | diacr = value; | 633 | diacr = value; |
634 | return; | 634 | return; |
635 | } | 635 | } |
636 | if (kbd->kbdmode == VC_UNICODE) | 636 | if (kbd->kbdmode == VC_UNICODE) |
637 | to_utf8(vc, value); | 637 | to_utf8(vc, value); |
638 | else { | 638 | else { |
639 | int c = conv_uni_to_8bit(value); | 639 | int c = conv_uni_to_8bit(value); |
640 | if (c != -1) | 640 | if (c != -1) |
641 | put_queue(vc, c); | 641 | put_queue(vc, c); |
642 | } | 642 | } |
643 | } | 643 | } |
644 | 644 | ||
645 | /* | 645 | /* |
646 | * Handle dead key. Note that we now may have several | 646 | * Handle dead key. Note that we now may have several |
647 | * dead keys modifying the same character. Very useful | 647 | * dead keys modifying the same character. Very useful |
648 | * for Vietnamese. | 648 | * for Vietnamese. |
649 | */ | 649 | */ |
650 | static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) | 650 | static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) |
651 | { | 651 | { |
652 | if (up_flag) | 652 | if (up_flag) |
653 | return; | 653 | return; |
654 | diacr = (diacr ? handle_diacr(vc, value) : value); | 654 | diacr = (diacr ? handle_diacr(vc, value) : value); |
655 | } | 655 | } |
656 | 656 | ||
657 | static void k_self(struct vc_data *vc, unsigned char value, char up_flag) | 657 | static void k_self(struct vc_data *vc, unsigned char value, char up_flag) |
658 | { | 658 | { |
659 | unsigned int uni; | 659 | unsigned int uni; |
660 | if (kbd->kbdmode == VC_UNICODE) | 660 | if (kbd->kbdmode == VC_UNICODE) |
661 | uni = value; | 661 | uni = value; |
662 | else | 662 | else |
663 | uni = conv_8bit_to_uni(value); | 663 | uni = conv_8bit_to_uni(value); |
664 | k_unicode(vc, uni, up_flag); | 664 | k_unicode(vc, uni, up_flag); |
665 | } | 665 | } |
666 | 666 | ||
667 | static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) | 667 | static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) |
668 | { | 668 | { |
669 | k_deadunicode(vc, value, up_flag); | 669 | k_deadunicode(vc, value, up_flag); |
670 | } | 670 | } |
671 | 671 | ||
672 | /* | 672 | /* |
673 | * Obsolete - for backwards compatibility only | 673 | * Obsolete - for backwards compatibility only |
674 | */ | 674 | */ |
675 | static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) | 675 | static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) |
676 | { | 676 | { |
677 | static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; | 677 | static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; |
678 | value = ret_diacr[value]; | 678 | value = ret_diacr[value]; |
679 | k_deadunicode(vc, value, up_flag); | 679 | k_deadunicode(vc, value, up_flag); |
680 | } | 680 | } |
681 | 681 | ||
682 | static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) | 682 | static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) |
683 | { | 683 | { |
684 | if (up_flag) | 684 | if (up_flag) |
685 | return; | 685 | return; |
686 | set_console(value); | 686 | set_console(value); |
687 | } | 687 | } |
688 | 688 | ||
689 | static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) | 689 | static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) |
690 | { | 690 | { |
691 | unsigned v; | 691 | unsigned v; |
692 | 692 | ||
693 | if (up_flag) | 693 | if (up_flag) |
694 | return; | 694 | return; |
695 | v = value; | 695 | v = value; |
696 | if (v < ARRAY_SIZE(func_table)) { | 696 | if (v < ARRAY_SIZE(func_table)) { |
697 | if (func_table[value]) | 697 | if (func_table[value]) |
698 | puts_queue(vc, func_table[value]); | 698 | puts_queue(vc, func_table[value]); |
699 | } else | 699 | } else |
700 | printk(KERN_ERR "k_fn called with value=%d\n", value); | 700 | printk(KERN_ERR "k_fn called with value=%d\n", value); |
701 | } | 701 | } |
702 | 702 | ||
703 | static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) | 703 | static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) |
704 | { | 704 | { |
705 | static const char cur_chars[] = "BDCA"; | 705 | static const char cur_chars[] = "BDCA"; |
706 | 706 | ||
707 | if (up_flag) | 707 | if (up_flag) |
708 | return; | 708 | return; |
709 | applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE)); | 709 | applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE)); |
710 | } | 710 | } |
711 | 711 | ||
712 | static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) | 712 | static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) |
713 | { | 713 | { |
714 | static const char pad_chars[] = "0123456789+-*/\015,.?()#"; | 714 | static const char pad_chars[] = "0123456789+-*/\015,.?()#"; |
715 | static const char app_map[] = "pqrstuvwxylSRQMnnmPQS"; | 715 | static const char app_map[] = "pqrstuvwxylSRQMnnmPQS"; |
716 | 716 | ||
717 | if (up_flag) | 717 | if (up_flag) |
718 | return; /* no action, if this is a key release */ | 718 | return; /* no action, if this is a key release */ |
719 | 719 | ||
720 | /* kludge... shift forces cursor/number keys */ | 720 | /* kludge... shift forces cursor/number keys */ |
721 | if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) { | 721 | if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) { |
722 | applkey(vc, app_map[value], 1); | 722 | applkey(vc, app_map[value], 1); |
723 | return; | 723 | return; |
724 | } | 724 | } |
725 | 725 | ||
726 | if (!vc_kbd_led(kbd, VC_NUMLOCK)) | 726 | if (!vc_kbd_led(kbd, VC_NUMLOCK)) |
727 | switch (value) { | 727 | switch (value) { |
728 | case KVAL(K_PCOMMA): | 728 | case KVAL(K_PCOMMA): |
729 | case KVAL(K_PDOT): | 729 | case KVAL(K_PDOT): |
730 | k_fn(vc, KVAL(K_REMOVE), 0); | 730 | k_fn(vc, KVAL(K_REMOVE), 0); |
731 | return; | 731 | return; |
732 | case KVAL(K_P0): | 732 | case KVAL(K_P0): |
733 | k_fn(vc, KVAL(K_INSERT), 0); | 733 | k_fn(vc, KVAL(K_INSERT), 0); |
734 | return; | 734 | return; |
735 | case KVAL(K_P1): | 735 | case KVAL(K_P1): |
736 | k_fn(vc, KVAL(K_SELECT), 0); | 736 | k_fn(vc, KVAL(K_SELECT), 0); |
737 | return; | 737 | return; |
738 | case KVAL(K_P2): | 738 | case KVAL(K_P2): |
739 | k_cur(vc, KVAL(K_DOWN), 0); | 739 | k_cur(vc, KVAL(K_DOWN), 0); |
740 | return; | 740 | return; |
741 | case KVAL(K_P3): | 741 | case KVAL(K_P3): |
742 | k_fn(vc, KVAL(K_PGDN), 0); | 742 | k_fn(vc, KVAL(K_PGDN), 0); |
743 | return; | 743 | return; |
744 | case KVAL(K_P4): | 744 | case KVAL(K_P4): |
745 | k_cur(vc, KVAL(K_LEFT), 0); | 745 | k_cur(vc, KVAL(K_LEFT), 0); |
746 | return; | 746 | return; |
747 | case KVAL(K_P6): | 747 | case KVAL(K_P6): |
748 | k_cur(vc, KVAL(K_RIGHT), 0); | 748 | k_cur(vc, KVAL(K_RIGHT), 0); |
749 | return; | 749 | return; |
750 | case KVAL(K_P7): | 750 | case KVAL(K_P7): |
751 | k_fn(vc, KVAL(K_FIND), 0); | 751 | k_fn(vc, KVAL(K_FIND), 0); |
752 | return; | 752 | return; |
753 | case KVAL(K_P8): | 753 | case KVAL(K_P8): |
754 | k_cur(vc, KVAL(K_UP), 0); | 754 | k_cur(vc, KVAL(K_UP), 0); |
755 | return; | 755 | return; |
756 | case KVAL(K_P9): | 756 | case KVAL(K_P9): |
757 | k_fn(vc, KVAL(K_PGUP), 0); | 757 | k_fn(vc, KVAL(K_PGUP), 0); |
758 | return; | 758 | return; |
759 | case KVAL(K_P5): | 759 | case KVAL(K_P5): |
760 | applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); | 760 | applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); |
761 | return; | 761 | return; |
762 | } | 762 | } |
763 | 763 | ||
764 | put_queue(vc, pad_chars[value]); | 764 | put_queue(vc, pad_chars[value]); |
765 | if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) | 765 | if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) |
766 | put_queue(vc, 10); | 766 | put_queue(vc, 10); |
767 | } | 767 | } |
768 | 768 | ||
769 | static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) | 769 | static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) |
770 | { | 770 | { |
771 | int old_state = shift_state; | 771 | int old_state = shift_state; |
772 | 772 | ||
773 | if (rep) | 773 | if (rep) |
774 | return; | 774 | return; |
775 | /* | 775 | /* |
776 | * Mimic typewriter: | 776 | * Mimic typewriter: |
777 | * a CapsShift key acts like Shift but undoes CapsLock | 777 | * a CapsShift key acts like Shift but undoes CapsLock |
778 | */ | 778 | */ |
779 | if (value == KVAL(K_CAPSSHIFT)) { | 779 | if (value == KVAL(K_CAPSSHIFT)) { |
780 | value = KVAL(K_SHIFT); | 780 | value = KVAL(K_SHIFT); |
781 | if (!up_flag) | 781 | if (!up_flag) |
782 | clr_vc_kbd_led(kbd, VC_CAPSLOCK); | 782 | clr_vc_kbd_led(kbd, VC_CAPSLOCK); |
783 | } | 783 | } |
784 | 784 | ||
785 | if (up_flag) { | 785 | if (up_flag) { |
786 | /* | 786 | /* |
787 | * handle the case that two shift or control | 787 | * handle the case that two shift or control |
788 | * keys are depressed simultaneously | 788 | * keys are depressed simultaneously |
789 | */ | 789 | */ |
790 | if (shift_down[value]) | 790 | if (shift_down[value]) |
791 | shift_down[value]--; | 791 | shift_down[value]--; |
792 | } else | 792 | } else |
793 | shift_down[value]++; | 793 | shift_down[value]++; |
794 | 794 | ||
795 | if (shift_down[value]) | 795 | if (shift_down[value]) |
796 | shift_state |= (1 << value); | 796 | shift_state |= (1 << value); |
797 | else | 797 | else |
798 | shift_state &= ~(1 << value); | 798 | shift_state &= ~(1 << value); |
799 | 799 | ||
800 | /* kludge */ | 800 | /* kludge */ |
801 | if (up_flag && shift_state != old_state && npadch != -1) { | 801 | if (up_flag && shift_state != old_state && npadch != -1) { |
802 | if (kbd->kbdmode == VC_UNICODE) | 802 | if (kbd->kbdmode == VC_UNICODE) |
803 | to_utf8(vc, npadch); | 803 | to_utf8(vc, npadch); |
804 | else | 804 | else |
805 | put_queue(vc, npadch & 0xff); | 805 | put_queue(vc, npadch & 0xff); |
806 | npadch = -1; | 806 | npadch = -1; |
807 | } | 807 | } |
808 | } | 808 | } |
809 | 809 | ||
810 | static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) | 810 | static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) |
811 | { | 811 | { |
812 | if (up_flag) | 812 | if (up_flag) |
813 | return; | 813 | return; |
814 | 814 | ||
815 | if (vc_kbd_mode(kbd, VC_META)) { | 815 | if (vc_kbd_mode(kbd, VC_META)) { |
816 | put_queue(vc, '\033'); | 816 | put_queue(vc, '\033'); |
817 | put_queue(vc, value); | 817 | put_queue(vc, value); |
818 | } else | 818 | } else |
819 | put_queue(vc, value | 0x80); | 819 | put_queue(vc, value | 0x80); |
820 | } | 820 | } |
821 | 821 | ||
822 | static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) | 822 | static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) |
823 | { | 823 | { |
824 | int base; | 824 | int base; |
825 | 825 | ||
826 | if (up_flag) | 826 | if (up_flag) |
827 | return; | 827 | return; |
828 | 828 | ||
829 | if (value < 10) { | 829 | if (value < 10) { |
830 | /* decimal input of code, while Alt depressed */ | 830 | /* decimal input of code, while Alt depressed */ |
831 | base = 10; | 831 | base = 10; |
832 | } else { | 832 | } else { |
833 | /* hexadecimal input of code, while AltGr depressed */ | 833 | /* hexadecimal input of code, while AltGr depressed */ |
834 | value -= 10; | 834 | value -= 10; |
835 | base = 16; | 835 | base = 16; |
836 | } | 836 | } |
837 | 837 | ||
838 | if (npadch == -1) | 838 | if (npadch == -1) |
839 | npadch = value; | 839 | npadch = value; |
840 | else | 840 | else |
841 | npadch = npadch * base + value; | 841 | npadch = npadch * base + value; |
842 | } | 842 | } |
843 | 843 | ||
844 | static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) | 844 | static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) |
845 | { | 845 | { |
846 | if (up_flag || rep) | 846 | if (up_flag || rep) |
847 | return; | 847 | return; |
848 | chg_vc_kbd_lock(kbd, value); | 848 | chg_vc_kbd_lock(kbd, value); |
849 | } | 849 | } |
850 | 850 | ||
851 | static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) | 851 | static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) |
852 | { | 852 | { |
853 | k_shift(vc, value, up_flag); | 853 | k_shift(vc, value, up_flag); |
854 | if (up_flag || rep) | 854 | if (up_flag || rep) |
855 | return; | 855 | return; |
856 | chg_vc_kbd_slock(kbd, value); | 856 | chg_vc_kbd_slock(kbd, value); |
857 | /* try to make Alt, oops, AltGr and such work */ | 857 | /* try to make Alt, oops, AltGr and such work */ |
858 | if (!key_maps[kbd->lockstate ^ kbd->slockstate]) { | 858 | if (!key_maps[kbd->lockstate ^ kbd->slockstate]) { |
859 | kbd->slockstate = 0; | 859 | kbd->slockstate = 0; |
860 | chg_vc_kbd_slock(kbd, value); | 860 | chg_vc_kbd_slock(kbd, value); |
861 | } | 861 | } |
862 | } | 862 | } |
863 | 863 | ||
864 | /* by default, 300ms interval for combination release */ | 864 | /* by default, 300ms interval for combination release */ |
865 | static unsigned brl_timeout = 300; | 865 | static unsigned brl_timeout = 300; |
866 | MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)"); | 866 | MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)"); |
867 | module_param(brl_timeout, uint, 0644); | 867 | module_param(brl_timeout, uint, 0644); |
868 | 868 | ||
869 | static unsigned brl_nbchords = 1; | 869 | static unsigned brl_nbchords = 1; |
870 | MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)"); | 870 | MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)"); |
871 | module_param(brl_nbchords, uint, 0644); | 871 | module_param(brl_nbchords, uint, 0644); |
872 | 872 | ||
873 | static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag) | 873 | static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag) |
874 | { | 874 | { |
875 | static unsigned long chords; | 875 | static unsigned long chords; |
876 | static unsigned committed; | 876 | static unsigned committed; |
877 | 877 | ||
878 | if (!brl_nbchords) | 878 | if (!brl_nbchords) |
879 | k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag); | 879 | k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag); |
880 | else { | 880 | else { |
881 | committed |= pattern; | 881 | committed |= pattern; |
882 | chords++; | 882 | chords++; |
883 | if (chords == brl_nbchords) { | 883 | if (chords == brl_nbchords) { |
884 | k_unicode(vc, BRL_UC_ROW | committed, up_flag); | 884 | k_unicode(vc, BRL_UC_ROW | committed, up_flag); |
885 | chords = 0; | 885 | chords = 0; |
886 | committed = 0; | 886 | committed = 0; |
887 | } | 887 | } |
888 | } | 888 | } |
889 | } | 889 | } |
890 | 890 | ||
891 | static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) | 891 | static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) |
892 | { | 892 | { |
893 | static unsigned pressed,committing; | 893 | static unsigned pressed,committing; |
894 | static unsigned long releasestart; | 894 | static unsigned long releasestart; |
895 | 895 | ||
896 | if (kbd->kbdmode != VC_UNICODE) { | 896 | if (kbd->kbdmode != VC_UNICODE) { |
897 | if (!up_flag) | 897 | if (!up_flag) |
898 | printk("keyboard mode must be unicode for braille patterns\n"); | 898 | printk("keyboard mode must be unicode for braille patterns\n"); |
899 | return; | 899 | return; |
900 | } | 900 | } |
901 | 901 | ||
902 | if (!value) { | 902 | if (!value) { |
903 | k_unicode(vc, BRL_UC_ROW, up_flag); | 903 | k_unicode(vc, BRL_UC_ROW, up_flag); |
904 | return; | 904 | return; |
905 | } | 905 | } |
906 | 906 | ||
907 | if (value > 8) | 907 | if (value > 8) |
908 | return; | 908 | return; |
909 | 909 | ||
910 | if (up_flag) { | 910 | if (up_flag) { |
911 | if (brl_timeout) { | 911 | if (brl_timeout) { |
912 | if (!committing || | 912 | if (!committing || |
913 | jiffies - releasestart > (brl_timeout * HZ) / 1000) { | 913 | jiffies - releasestart > (brl_timeout * HZ) / 1000) { |
914 | committing = pressed; | 914 | committing = pressed; |
915 | releasestart = jiffies; | 915 | releasestart = jiffies; |
916 | } | 916 | } |
917 | pressed &= ~(1 << (value - 1)); | 917 | pressed &= ~(1 << (value - 1)); |
918 | if (!pressed) { | 918 | if (!pressed) { |
919 | if (committing) { | 919 | if (committing) { |
920 | k_brlcommit(vc, committing, 0); | 920 | k_brlcommit(vc, committing, 0); |
921 | committing = 0; | 921 | committing = 0; |
922 | } | 922 | } |
923 | } | 923 | } |
924 | } else { | 924 | } else { |
925 | if (committing) { | 925 | if (committing) { |
926 | k_brlcommit(vc, committing, 0); | 926 | k_brlcommit(vc, committing, 0); |
927 | committing = 0; | 927 | committing = 0; |
928 | } | 928 | } |
929 | pressed &= ~(1 << (value - 1)); | 929 | pressed &= ~(1 << (value - 1)); |
930 | } | 930 | } |
931 | } else { | 931 | } else { |
932 | pressed |= 1 << (value - 1); | 932 | pressed |= 1 << (value - 1); |
933 | if (!brl_timeout) | 933 | if (!brl_timeout) |
934 | committing = pressed; | 934 | committing = pressed; |
935 | } | 935 | } |
936 | } | 936 | } |
937 | 937 | ||
938 | /* | 938 | /* |
939 | * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, | 939 | * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, |
940 | * or (ii) whatever pattern of lights people want to show using KDSETLED, | 940 | * or (ii) whatever pattern of lights people want to show using KDSETLED, |
941 | * or (iii) specified bits of specified words in kernel memory. | 941 | * or (iii) specified bits of specified words in kernel memory. |
942 | */ | 942 | */ |
943 | unsigned char getledstate(void) | 943 | unsigned char getledstate(void) |
944 | { | 944 | { |
945 | return ledstate; | 945 | return ledstate; |
946 | } | 946 | } |
947 | 947 | ||
948 | void setledstate(struct kbd_struct *kbd, unsigned int led) | 948 | void setledstate(struct kbd_struct *kbd, unsigned int led) |
949 | { | 949 | { |
950 | if (!(led & ~7)) { | 950 | if (!(led & ~7)) { |
951 | ledioctl = led; | 951 | ledioctl = led; |
952 | kbd->ledmode = LED_SHOW_IOCTL; | 952 | kbd->ledmode = LED_SHOW_IOCTL; |
953 | } else | 953 | } else |
954 | kbd->ledmode = LED_SHOW_FLAGS; | 954 | kbd->ledmode = LED_SHOW_FLAGS; |
955 | set_leds(); | 955 | set_leds(); |
956 | } | 956 | } |
957 | 957 | ||
958 | static inline unsigned char getleds(void) | 958 | static inline unsigned char getleds(void) |
959 | { | 959 | { |
960 | struct kbd_struct *kbd = kbd_table + fg_console; | 960 | struct kbd_struct *kbd = kbd_table + fg_console; |
961 | unsigned char leds; | 961 | unsigned char leds; |
962 | int i; | 962 | int i; |
963 | 963 | ||
964 | if (kbd->ledmode == LED_SHOW_IOCTL) | 964 | if (kbd->ledmode == LED_SHOW_IOCTL) |
965 | return ledioctl; | 965 | return ledioctl; |
966 | 966 | ||
967 | leds = kbd->ledflagstate; | 967 | leds = kbd->ledflagstate; |
968 | 968 | ||
969 | if (kbd->ledmode == LED_SHOW_MEM) { | 969 | if (kbd->ledmode == LED_SHOW_MEM) { |
970 | for (i = 0; i < 3; i++) | 970 | for (i = 0; i < 3; i++) |
971 | if (ledptrs[i].valid) { | 971 | if (ledptrs[i].valid) { |
972 | if (*ledptrs[i].addr & ledptrs[i].mask) | 972 | if (*ledptrs[i].addr & ledptrs[i].mask) |
973 | leds |= (1 << i); | 973 | leds |= (1 << i); |
974 | else | 974 | else |
975 | leds &= ~(1 << i); | 975 | leds &= ~(1 << i); |
976 | } | 976 | } |
977 | } | 977 | } |
978 | return leds; | 978 | return leds; |
979 | } | 979 | } |
980 | 980 | ||
981 | /* | 981 | /* |
982 | * This routine is the bottom half of the keyboard interrupt | 982 | * This routine is the bottom half of the keyboard interrupt |
983 | * routine, and runs with all interrupts enabled. It does | 983 | * routine, and runs with all interrupts enabled. It does |
984 | * console changing, led setting and copy_to_cooked, which can | 984 | * console changing, led setting and copy_to_cooked, which can |
985 | * take a reasonably long time. | 985 | * take a reasonably long time. |
986 | * | 986 | * |
987 | * Aside from timing (which isn't really that important for | 987 | * Aside from timing (which isn't really that important for |
988 | * keyboard interrupts as they happen often), using the software | 988 | * keyboard interrupts as they happen often), using the software |
989 | * interrupt routines for this thing allows us to easily mask | 989 | * interrupt routines for this thing allows us to easily mask |
990 | * this when we don't want any of the above to happen. | 990 | * this when we don't want any of the above to happen. |
991 | * This allows for easy and efficient race-condition prevention | 991 | * This allows for easy and efficient race-condition prevention |
992 | * for kbd_start => input_inject_event(dev, EV_LED, ...) => ... | 992 | * for kbd_start => input_inject_event(dev, EV_LED, ...) => ... |
993 | */ | 993 | */ |
994 | 994 | ||
995 | static void kbd_bh(unsigned long dummy) | 995 | static void kbd_bh(unsigned long dummy) |
996 | { | 996 | { |
997 | struct list_head *node; | 997 | struct list_head *node; |
998 | unsigned char leds = getleds(); | 998 | unsigned char leds = getleds(); |
999 | 999 | ||
1000 | if (leds != ledstate) { | 1000 | if (leds != ledstate) { |
1001 | list_for_each(node, &kbd_handler.h_list) { | 1001 | list_for_each(node, &kbd_handler.h_list) { |
1002 | struct input_handle *handle = to_handle_h(node); | 1002 | struct input_handle *handle = to_handle_h(node); |
1003 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); | 1003 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); |
1004 | input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); | 1004 | input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); |
1005 | input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); | 1005 | input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); |
1006 | input_inject_event(handle, EV_SYN, SYN_REPORT, 0); | 1006 | input_inject_event(handle, EV_SYN, SYN_REPORT, 0); |
1007 | } | 1007 | } |
1008 | } | 1008 | } |
1009 | 1009 | ||
1010 | ledstate = leds; | 1010 | ledstate = leds; |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); | 1013 | DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); |
1014 | 1014 | ||
1015 | #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ | 1015 | #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ |
1016 | defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ | 1016 | defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ |
1017 | defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ | 1017 | defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ |
1018 | (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) | 1018 | (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) |
1019 | 1019 | ||
1020 | #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ | 1020 | #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ |
1021 | ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) | 1021 | ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) |
1022 | 1022 | ||
1023 | static const unsigned short x86_keycodes[256] = | 1023 | static const unsigned short x86_keycodes[256] = |
1024 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | 1024 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
1025 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 1025 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
1026 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, | 1026 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, |
1027 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, | 1027 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, |
1028 | 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, | 1028 | 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, |
1029 | 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92, | 1029 | 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92, |
1030 | 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339, | 1030 | 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339, |
1031 | 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, | 1031 | 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, |
1032 | 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, | 1032 | 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, |
1033 | 103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361, | 1033 | 103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361, |
1034 | 291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114, | 1034 | 291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114, |
1035 | 264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116, | 1035 | 264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116, |
1036 | 377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307, | 1036 | 377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307, |
1037 | 308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330, | 1037 | 308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330, |
1038 | 332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 }; | 1038 | 332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 }; |
1039 | 1039 | ||
1040 | #ifdef CONFIG_SPARC | 1040 | #ifdef CONFIG_SPARC |
1041 | static int sparc_l1_a_state = 0; | 1041 | static int sparc_l1_a_state = 0; |
1042 | extern void sun_do_break(void); | 1042 | extern void sun_do_break(void); |
1043 | #endif | 1043 | #endif |
1044 | 1044 | ||
1045 | static int emulate_raw(struct vc_data *vc, unsigned int keycode, | 1045 | static int emulate_raw(struct vc_data *vc, unsigned int keycode, |
1046 | unsigned char up_flag) | 1046 | unsigned char up_flag) |
1047 | { | 1047 | { |
1048 | int code; | 1048 | int code; |
1049 | 1049 | ||
1050 | switch (keycode) { | 1050 | switch (keycode) { |
1051 | case KEY_PAUSE: | 1051 | case KEY_PAUSE: |
1052 | put_queue(vc, 0xe1); | 1052 | put_queue(vc, 0xe1); |
1053 | put_queue(vc, 0x1d | up_flag); | 1053 | put_queue(vc, 0x1d | up_flag); |
1054 | put_queue(vc, 0x45 | up_flag); | 1054 | put_queue(vc, 0x45 | up_flag); |
1055 | break; | 1055 | break; |
1056 | 1056 | ||
1057 | case KEY_HANGEUL: | 1057 | case KEY_HANGEUL: |
1058 | if (!up_flag) | 1058 | if (!up_flag) |
1059 | put_queue(vc, 0xf2); | 1059 | put_queue(vc, 0xf2); |
1060 | break; | 1060 | break; |
1061 | 1061 | ||
1062 | case KEY_HANJA: | 1062 | case KEY_HANJA: |
1063 | if (!up_flag) | 1063 | if (!up_flag) |
1064 | put_queue(vc, 0xf1); | 1064 | put_queue(vc, 0xf1); |
1065 | break; | 1065 | break; |
1066 | 1066 | ||
1067 | case KEY_SYSRQ: | 1067 | case KEY_SYSRQ: |
1068 | /* | 1068 | /* |
1069 | * Real AT keyboards (that's what we're trying | 1069 | * Real AT keyboards (that's what we're trying |
1070 | * to emulate here emit 0xe0 0x2a 0xe0 0x37 when | 1070 | * to emulate here emit 0xe0 0x2a 0xe0 0x37 when |
1071 | * pressing PrtSc/SysRq alone, but simply 0x54 | 1071 | * pressing PrtSc/SysRq alone, but simply 0x54 |
1072 | * when pressing Alt+PrtSc/SysRq. | 1072 | * when pressing Alt+PrtSc/SysRq. |
1073 | */ | 1073 | */ |
1074 | if (sysrq_alt) { | 1074 | if (sysrq_alt) { |
1075 | put_queue(vc, 0x54 | up_flag); | 1075 | put_queue(vc, 0x54 | up_flag); |
1076 | } else { | 1076 | } else { |
1077 | put_queue(vc, 0xe0); | 1077 | put_queue(vc, 0xe0); |
1078 | put_queue(vc, 0x2a | up_flag); | 1078 | put_queue(vc, 0x2a | up_flag); |
1079 | put_queue(vc, 0xe0); | 1079 | put_queue(vc, 0xe0); |
1080 | put_queue(vc, 0x37 | up_flag); | 1080 | put_queue(vc, 0x37 | up_flag); |
1081 | } | 1081 | } |
1082 | break; | 1082 | break; |
1083 | 1083 | ||
1084 | default: | 1084 | default: |
1085 | if (keycode > 255) | 1085 | if (keycode > 255) |
1086 | return -1; | 1086 | return -1; |
1087 | 1087 | ||
1088 | code = x86_keycodes[keycode]; | 1088 | code = x86_keycodes[keycode]; |
1089 | if (!code) | 1089 | if (!code) |
1090 | return -1; | 1090 | return -1; |
1091 | 1091 | ||
1092 | if (code & 0x100) | 1092 | if (code & 0x100) |
1093 | put_queue(vc, 0xe0); | 1093 | put_queue(vc, 0xe0); |
1094 | put_queue(vc, (code & 0x7f) | up_flag); | 1094 | put_queue(vc, (code & 0x7f) | up_flag); |
1095 | 1095 | ||
1096 | break; | 1096 | break; |
1097 | } | 1097 | } |
1098 | 1098 | ||
1099 | return 0; | 1099 | return 0; |
1100 | } | 1100 | } |
1101 | 1101 | ||
1102 | #else | 1102 | #else |
1103 | 1103 | ||
1104 | #define HW_RAW(dev) 0 | 1104 | #define HW_RAW(dev) 0 |
1105 | 1105 | ||
1106 | #warning "Cannot generate rawmode keyboard for your architecture yet." | 1106 | #warning "Cannot generate rawmode keyboard for your architecture yet." |
1107 | 1107 | ||
1108 | static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) | 1108 | static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) |
1109 | { | 1109 | { |
1110 | if (keycode > 127) | 1110 | if (keycode > 127) |
1111 | return -1; | 1111 | return -1; |
1112 | 1112 | ||
1113 | put_queue(vc, keycode | up_flag); | 1113 | put_queue(vc, keycode | up_flag); |
1114 | return 0; | 1114 | return 0; |
1115 | } | 1115 | } |
1116 | #endif | 1116 | #endif |
1117 | 1117 | ||
1118 | static void kbd_rawcode(unsigned char data) | 1118 | static void kbd_rawcode(unsigned char data) |
1119 | { | 1119 | { |
1120 | struct vc_data *vc = vc_cons[fg_console].d; | 1120 | struct vc_data *vc = vc_cons[fg_console].d; |
1121 | kbd = kbd_table + fg_console; | 1121 | kbd = kbd_table + fg_console; |
1122 | if (kbd->kbdmode == VC_RAW) | 1122 | if (kbd->kbdmode == VC_RAW) |
1123 | put_queue(vc, data); | 1123 | put_queue(vc, data); |
1124 | } | 1124 | } |
1125 | 1125 | ||
1126 | static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | 1126 | static void kbd_keycode(unsigned int keycode, int down, int hw_raw) |
1127 | { | 1127 | { |
1128 | struct vc_data *vc = vc_cons[fg_console].d; | 1128 | struct vc_data *vc = vc_cons[fg_console].d; |
1129 | unsigned short keysym, *key_map; | 1129 | unsigned short keysym, *key_map; |
1130 | unsigned char type, raw_mode; | 1130 | unsigned char type, raw_mode; |
1131 | struct tty_struct *tty; | 1131 | struct tty_struct *tty; |
1132 | int shift_final; | 1132 | int shift_final; |
1133 | 1133 | ||
1134 | tty = vc->vc_tty; | 1134 | tty = vc->vc_tty; |
1135 | 1135 | ||
1136 | if (tty && (!tty->driver_data)) { | 1136 | if (tty && (!tty->driver_data)) { |
1137 | /* No driver data? Strange. Okay we fix it then. */ | 1137 | /* No driver data? Strange. Okay we fix it then. */ |
1138 | tty->driver_data = vc; | 1138 | tty->driver_data = vc; |
1139 | } | 1139 | } |
1140 | 1140 | ||
1141 | kbd = kbd_table + fg_console; | 1141 | kbd = kbd_table + fg_console; |
1142 | 1142 | ||
1143 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) | 1143 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) |
1144 | sysrq_alt = down ? keycode : 0; | 1144 | sysrq_alt = down ? keycode : 0; |
1145 | #ifdef CONFIG_SPARC | 1145 | #ifdef CONFIG_SPARC |
1146 | if (keycode == KEY_STOP) | 1146 | if (keycode == KEY_STOP) |
1147 | sparc_l1_a_state = down; | 1147 | sparc_l1_a_state = down; |
1148 | #endif | 1148 | #endif |
1149 | 1149 | ||
1150 | rep = (down == 2); | 1150 | rep = (down == 2); |
1151 | 1151 | ||
1152 | #ifdef CONFIG_MAC_EMUMOUSEBTN | 1152 | #ifdef CONFIG_MAC_EMUMOUSEBTN |
1153 | if (mac_hid_mouse_emulate_buttons(1, keycode, down)) | 1153 | if (mac_hid_mouse_emulate_buttons(1, keycode, down)) |
1154 | return; | 1154 | return; |
1155 | #endif /* CONFIG_MAC_EMUMOUSEBTN */ | 1155 | #endif /* CONFIG_MAC_EMUMOUSEBTN */ |
1156 | 1156 | ||
1157 | if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) | 1157 | if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) |
1158 | if (emulate_raw(vc, keycode, !down << 7)) | 1158 | if (emulate_raw(vc, keycode, !down << 7)) |
1159 | if (keycode < BTN_MISC && printk_ratelimit()) | 1159 | if (keycode < BTN_MISC && printk_ratelimit()) |
1160 | printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); | 1160 | printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); |
1161 | 1161 | ||
1162 | #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ | 1162 | #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ |
1163 | if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { | 1163 | if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { |
1164 | if (!sysrq_down) { | 1164 | if (!sysrq_down) { |
1165 | sysrq_down = down; | 1165 | sysrq_down = down; |
1166 | sysrq_alt_use = sysrq_alt; | 1166 | sysrq_alt_use = sysrq_alt; |
1167 | } | 1167 | } |
1168 | return; | 1168 | return; |
1169 | } | 1169 | } |
1170 | if (sysrq_down && !down && keycode == sysrq_alt_use) | 1170 | if (sysrq_down && !down && keycode == sysrq_alt_use) |
1171 | sysrq_down = 0; | 1171 | sysrq_down = 0; |
1172 | if (sysrq_down && down && !rep) { | 1172 | if (sysrq_down && down && !rep) { |
1173 | handle_sysrq(kbd_sysrq_xlate[keycode], tty); | 1173 | handle_sysrq(kbd_sysrq_xlate[keycode], tty); |
1174 | return; | 1174 | return; |
1175 | } | 1175 | } |
1176 | #endif | 1176 | #endif |
1177 | #ifdef CONFIG_SPARC | 1177 | #ifdef CONFIG_SPARC |
1178 | if (keycode == KEY_A && sparc_l1_a_state) { | 1178 | if (keycode == KEY_A && sparc_l1_a_state) { |
1179 | sparc_l1_a_state = 0; | 1179 | sparc_l1_a_state = 0; |
1180 | sun_do_break(); | 1180 | sun_do_break(); |
1181 | } | 1181 | } |
1182 | #endif | 1182 | #endif |
1183 | 1183 | ||
1184 | if (kbd->kbdmode == VC_MEDIUMRAW) { | 1184 | if (kbd->kbdmode == VC_MEDIUMRAW) { |
1185 | /* | 1185 | /* |
1186 | * This is extended medium raw mode, with keys above 127 | 1186 | * This is extended medium raw mode, with keys above 127 |
1187 | * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing | 1187 | * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing |
1188 | * the 'up' flag if needed. 0 is reserved, so this shouldn't | 1188 | * the 'up' flag if needed. 0 is reserved, so this shouldn't |
1189 | * interfere with anything else. The two bytes after 0 will | 1189 | * interfere with anything else. The two bytes after 0 will |
1190 | * always have the up flag set not to interfere with older | 1190 | * always have the up flag set not to interfere with older |
1191 | * applications. This allows for 16384 different keycodes, | 1191 | * applications. This allows for 16384 different keycodes, |
1192 | * which should be enough. | 1192 | * which should be enough. |
1193 | */ | 1193 | */ |
1194 | if (keycode < 128) { | 1194 | if (keycode < 128) { |
1195 | put_queue(vc, keycode | (!down << 7)); | 1195 | put_queue(vc, keycode | (!down << 7)); |
1196 | } else { | 1196 | } else { |
1197 | put_queue(vc, !down << 7); | 1197 | put_queue(vc, !down << 7); |
1198 | put_queue(vc, (keycode >> 7) | 0x80); | 1198 | put_queue(vc, (keycode >> 7) | 0x80); |
1199 | put_queue(vc, keycode | 0x80); | 1199 | put_queue(vc, keycode | 0x80); |
1200 | } | 1200 | } |
1201 | raw_mode = 1; | 1201 | raw_mode = 1; |
1202 | } | 1202 | } |
1203 | 1203 | ||
1204 | if (down) | 1204 | if (down) |
1205 | set_bit(keycode, key_down); | 1205 | set_bit(keycode, key_down); |
1206 | else | 1206 | else |
1207 | clear_bit(keycode, key_down); | 1207 | clear_bit(keycode, key_down); |
1208 | 1208 | ||
1209 | if (rep && | 1209 | if (rep && |
1210 | (!vc_kbd_mode(kbd, VC_REPEAT) || | 1210 | (!vc_kbd_mode(kbd, VC_REPEAT) || |
1211 | (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) { | 1211 | (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) { |
1212 | /* | 1212 | /* |
1213 | * Don't repeat a key if the input buffers are not empty and the | 1213 | * Don't repeat a key if the input buffers are not empty and the |
1214 | * characters get aren't echoed locally. This makes key repeat | 1214 | * characters get aren't echoed locally. This makes key repeat |
1215 | * usable with slow applications and under heavy loads. | 1215 | * usable with slow applications and under heavy loads. |
1216 | */ | 1216 | */ |
1217 | return; | 1217 | return; |
1218 | } | 1218 | } |
1219 | 1219 | ||
1220 | shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; | 1220 | shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; |
1221 | key_map = key_maps[shift_final]; | 1221 | key_map = key_maps[shift_final]; |
1222 | 1222 | ||
1223 | if (!key_map) { | 1223 | if (!key_map) { |
1224 | compute_shiftstate(); | 1224 | compute_shiftstate(); |
1225 | kbd->slockstate = 0; | 1225 | kbd->slockstate = 0; |
1226 | return; | 1226 | return; |
1227 | } | 1227 | } |
1228 | 1228 | ||
1229 | if (keycode > NR_KEYS) | 1229 | if (keycode > NR_KEYS) |
1230 | if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) | 1230 | if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) |
1231 | keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1); | 1231 | keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1); |
1232 | else | 1232 | else |
1233 | return; | 1233 | return; |
1234 | else | 1234 | else |
1235 | keysym = key_map[keycode]; | 1235 | keysym = key_map[keycode]; |
1236 | 1236 | ||
1237 | type = KTYP(keysym); | 1237 | type = KTYP(keysym); |
1238 | 1238 | ||
1239 | if (type < 0xf0) { | 1239 | if (type < 0xf0) { |
1240 | if (down && !raw_mode) | 1240 | if (down && !raw_mode) |
1241 | to_utf8(vc, keysym); | 1241 | to_utf8(vc, keysym); |
1242 | return; | 1242 | return; |
1243 | } | 1243 | } |
1244 | 1244 | ||
1245 | type -= 0xf0; | 1245 | type -= 0xf0; |
1246 | 1246 | ||
1247 | if (raw_mode && type != KT_SPEC && type != KT_SHIFT) | 1247 | if (raw_mode && type != KT_SPEC && type != KT_SHIFT) |
1248 | return; | 1248 | return; |
1249 | 1249 | ||
1250 | if (type == KT_LETTER) { | 1250 | if (type == KT_LETTER) { |
1251 | type = KT_LATIN; | 1251 | type = KT_LATIN; |
1252 | if (vc_kbd_led(kbd, VC_CAPSLOCK)) { | 1252 | if (vc_kbd_led(kbd, VC_CAPSLOCK)) { |
1253 | key_map = key_maps[shift_final ^ (1 << KG_SHIFT)]; | 1253 | key_map = key_maps[shift_final ^ (1 << KG_SHIFT)]; |
1254 | if (key_map) | 1254 | if (key_map) |
1255 | keysym = key_map[keycode]; | 1255 | keysym = key_map[keycode]; |
1256 | } | 1256 | } |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | (*k_handler[type])(vc, keysym & 0xff, !down); | 1259 | (*k_handler[type])(vc, keysym & 0xff, !down); |
1260 | 1260 | ||
1261 | if (type != KT_SLOCK) | 1261 | if (type != KT_SLOCK) |
1262 | kbd->slockstate = 0; | 1262 | kbd->slockstate = 0; |
1263 | } | 1263 | } |
1264 | 1264 | ||
1265 | static void kbd_event(struct input_handle *handle, unsigned int event_type, | 1265 | static void kbd_event(struct input_handle *handle, unsigned int event_type, |
1266 | unsigned int event_code, int value) | 1266 | unsigned int event_code, int value) |
1267 | { | 1267 | { |
1268 | if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) | 1268 | if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) |
1269 | kbd_rawcode(value); | 1269 | kbd_rawcode(value); |
1270 | if (event_type == EV_KEY) | 1270 | if (event_type == EV_KEY) |
1271 | kbd_keycode(event_code, value, HW_RAW(handle->dev)); | 1271 | kbd_keycode(event_code, value, HW_RAW(handle->dev)); |
1272 | tasklet_schedule(&keyboard_tasklet); | 1272 | tasklet_schedule(&keyboard_tasklet); |
1273 | do_poke_blanked_console = 1; | 1273 | do_poke_blanked_console = 1; |
1274 | schedule_console_callback(); | 1274 | schedule_console_callback(); |
1275 | } | 1275 | } |
1276 | 1276 | ||
1277 | /* | 1277 | /* |
1278 | * When a keyboard (or other input device) is found, the kbd_connect | 1278 | * When a keyboard (or other input device) is found, the kbd_connect |
1279 | * function is called. The function then looks at the device, and if it | 1279 | * function is called. The function then looks at the device, and if it |
1280 | * likes it, it can open it and get events from it. In this (kbd_connect) | 1280 | * likes it, it can open it and get events from it. In this (kbd_connect) |
1281 | * function, we should decide which VT to bind that keyboard to initially. | 1281 | * function, we should decide which VT to bind that keyboard to initially. |
1282 | */ | 1282 | */ |
1283 | static int kbd_connect(struct input_handler *handler, struct input_dev *dev, | 1283 | static int kbd_connect(struct input_handler *handler, struct input_dev *dev, |
1284 | const struct input_device_id *id) | 1284 | const struct input_device_id *id) |
1285 | { | 1285 | { |
1286 | struct input_handle *handle; | 1286 | struct input_handle *handle; |
1287 | int error; | 1287 | int error; |
1288 | int i; | 1288 | int i; |
1289 | 1289 | ||
1290 | for (i = KEY_RESERVED; i < BTN_MISC; i++) | 1290 | for (i = KEY_RESERVED; i < BTN_MISC; i++) |
1291 | if (test_bit(i, dev->keybit)) | 1291 | if (test_bit(i, dev->keybit)) |
1292 | break; | 1292 | break; |
1293 | 1293 | ||
1294 | if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) | 1294 | if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) |
1295 | return -ENODEV; | 1295 | return -ENODEV; |
1296 | 1296 | ||
1297 | handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); | 1297 | handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); |
1298 | if (!handle) | 1298 | if (!handle) |
1299 | return -ENOMEM; | 1299 | return -ENOMEM; |
1300 | 1300 | ||
1301 | handle->dev = dev; | 1301 | handle->dev = dev; |
1302 | handle->handler = handler; | 1302 | handle->handler = handler; |
1303 | handle->name = "kbd"; | 1303 | handle->name = "kbd"; |
1304 | 1304 | ||
1305 | error = input_register_handle(handle); | 1305 | error = input_register_handle(handle); |
1306 | if (error) | 1306 | if (error) |
1307 | goto err_free_handle; | 1307 | goto err_free_handle; |
1308 | 1308 | ||
1309 | error = input_open_device(handle); | 1309 | error = input_open_device(handle); |
1310 | if (error) | 1310 | if (error) |
1311 | goto err_unregister_handle; | 1311 | goto err_unregister_handle; |
1312 | 1312 | ||
1313 | return 0; | 1313 | return 0; |
1314 | 1314 | ||
1315 | err_unregister_handle: | 1315 | err_unregister_handle: |
1316 | input_unregister_handle(handle); | 1316 | input_unregister_handle(handle); |
1317 | err_free_handle: | 1317 | err_free_handle: |
1318 | kfree(handle); | 1318 | kfree(handle); |
1319 | return error; | 1319 | return error; |
1320 | } | 1320 | } |
1321 | 1321 | ||
1322 | static void kbd_disconnect(struct input_handle *handle) | 1322 | static void kbd_disconnect(struct input_handle *handle) |
1323 | { | 1323 | { |
1324 | input_close_device(handle); | 1324 | input_close_device(handle); |
1325 | input_unregister_handle(handle); | 1325 | input_unregister_handle(handle); |
1326 | kfree(handle); | 1326 | kfree(handle); |
1327 | } | 1327 | } |
1328 | 1328 | ||
1329 | /* | 1329 | /* |
1330 | * Start keyboard handler on the new keyboard by refreshing LED state to | 1330 | * Start keyboard handler on the new keyboard by refreshing LED state to |
1331 | * match the rest of the system. | 1331 | * match the rest of the system. |
1332 | */ | 1332 | */ |
1333 | static void kbd_start(struct input_handle *handle) | 1333 | static void kbd_start(struct input_handle *handle) |
1334 | { | 1334 | { |
1335 | unsigned char leds = ledstate; | 1335 | unsigned char leds = ledstate; |
1336 | 1336 | ||
1337 | tasklet_disable(&keyboard_tasklet); | 1337 | tasklet_disable(&keyboard_tasklet); |
1338 | if (leds != 0xff) { | 1338 | if (leds != 0xff) { |
1339 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); | 1339 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); |
1340 | input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); | 1340 | input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); |
1341 | input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); | 1341 | input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); |
1342 | input_inject_event(handle, EV_SYN, SYN_REPORT, 0); | 1342 | input_inject_event(handle, EV_SYN, SYN_REPORT, 0); |
1343 | } | 1343 | } |
1344 | tasklet_enable(&keyboard_tasklet); | 1344 | tasklet_enable(&keyboard_tasklet); |
1345 | } | 1345 | } |
1346 | 1346 | ||
1347 | static const struct input_device_id kbd_ids[] = { | 1347 | static const struct input_device_id kbd_ids[] = { |
1348 | { | 1348 | { |
1349 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, | 1349 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, |
1350 | .evbit = { BIT(EV_KEY) }, | 1350 | .evbit = { BIT(EV_KEY) }, |
1351 | }, | 1351 | }, |
1352 | 1352 | ||
1353 | { | 1353 | { |
1354 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, | 1354 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, |
1355 | .evbit = { BIT(EV_SND) }, | 1355 | .evbit = { BIT(EV_SND) }, |
1356 | }, | 1356 | }, |
1357 | 1357 | ||
1358 | { }, /* Terminating entry */ | 1358 | { }, /* Terminating entry */ |
1359 | }; | 1359 | }; |
1360 | 1360 | ||
1361 | MODULE_DEVICE_TABLE(input, kbd_ids); | 1361 | MODULE_DEVICE_TABLE(input, kbd_ids); |
1362 | 1362 | ||
1363 | static struct input_handler kbd_handler = { | 1363 | static struct input_handler kbd_handler = { |
1364 | .event = kbd_event, | 1364 | .event = kbd_event, |
1365 | .connect = kbd_connect, | 1365 | .connect = kbd_connect, |
1366 | .disconnect = kbd_disconnect, | 1366 | .disconnect = kbd_disconnect, |
1367 | .start = kbd_start, | 1367 | .start = kbd_start, |
1368 | .name = "kbd", | 1368 | .name = "kbd", |
1369 | .id_table = kbd_ids, | 1369 | .id_table = kbd_ids, |
1370 | }; | 1370 | }; |
1371 | 1371 | ||
1372 | int __init kbd_init(void) | 1372 | int __init kbd_init(void) |
1373 | { | 1373 | { |
1374 | int i; | 1374 | int i; |
1375 | int error; | 1375 | int error; |
1376 | 1376 | ||
1377 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 1377 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
1378 | kbd_table[i].ledflagstate = KBD_DEFLEDS; | 1378 | kbd_table[i].ledflagstate = KBD_DEFLEDS; |
1379 | kbd_table[i].default_ledflagstate = KBD_DEFLEDS; | 1379 | kbd_table[i].default_ledflagstate = KBD_DEFLEDS; |
1380 | kbd_table[i].ledmode = LED_SHOW_FLAGS; | 1380 | kbd_table[i].ledmode = LED_SHOW_FLAGS; |
1381 | kbd_table[i].lockstate = KBD_DEFLOCK; | 1381 | kbd_table[i].lockstate = KBD_DEFLOCK; |
1382 | kbd_table[i].slockstate = 0; | 1382 | kbd_table[i].slockstate = 0; |
1383 | kbd_table[i].modeflags = KBD_DEFMODE; | 1383 | kbd_table[i].modeflags = KBD_DEFMODE; |
1384 | kbd_table[i].kbdmode = VC_XLATE; | 1384 | kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; |
1385 | } | 1385 | } |
1386 | 1386 | ||
1387 | error = input_register_handler(&kbd_handler); | 1387 | error = input_register_handler(&kbd_handler); |
1388 | if (error) | 1388 | if (error) |
1389 | return error; | 1389 | return error; |
1390 | 1390 | ||
1391 | tasklet_enable(&keyboard_tasklet); | 1391 | tasklet_enable(&keyboard_tasklet); |
1392 | tasklet_schedule(&keyboard_tasklet); | 1392 | tasklet_schedule(&keyboard_tasklet); |
1393 | 1393 | ||
1394 | return 0; | 1394 | return 0; |
1395 | } | 1395 | } |
1396 | 1396 |
drivers/char/sysrq.c
1 | /* -*- linux-c -*- | 1 | /* -*- linux-c -*- |
2 | * | 2 | * |
3 | * $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $ | 3 | * $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $ |
4 | * | 4 | * |
5 | * Linux Magic System Request Key Hacks | 5 | * Linux Magic System Request Key Hacks |
6 | * | 6 | * |
7 | * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> | 7 | * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> |
8 | * based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> | 8 | * based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> |
9 | * | 9 | * |
10 | * (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com> | 10 | * (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com> |
11 | * overhauled to use key registration | 11 | * overhauled to use key registration |
12 | * based upon discusions in irc://irc.openprojects.net/#kernelnewbies | 12 | * based upon discusions in irc://irc.openprojects.net/#kernelnewbies |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/tty.h> | 19 | #include <linux/tty.h> |
20 | #include <linux/mount.h> | 20 | #include <linux/mount.h> |
21 | #include <linux/kdev_t.h> | 21 | #include <linux/kdev_t.h> |
22 | #include <linux/major.h> | 22 | #include <linux/major.h> |
23 | #include <linux/reboot.h> | 23 | #include <linux/reboot.h> |
24 | #include <linux/sysrq.h> | 24 | #include <linux/sysrq.h> |
25 | #include <linux/kbd_kern.h> | 25 | #include <linux/kbd_kern.h> |
26 | #include <linux/quotaops.h> | 26 | #include <linux/quotaops.h> |
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/suspend.h> | 29 | #include <linux/suspend.h> |
30 | #include <linux/writeback.h> | 30 | #include <linux/writeback.h> |
31 | #include <linux/buffer_head.h> /* for fsync_bdev() */ | 31 | #include <linux/buffer_head.h> /* for fsync_bdev() */ |
32 | #include <linux/swap.h> | 32 | #include <linux/swap.h> |
33 | #include <linux/spinlock.h> | 33 | #include <linux/spinlock.h> |
34 | #include <linux/vt_kern.h> | 34 | #include <linux/vt_kern.h> |
35 | #include <linux/workqueue.h> | 35 | #include <linux/workqueue.h> |
36 | #include <linux/kexec.h> | 36 | #include <linux/kexec.h> |
37 | #include <linux/irq.h> | 37 | #include <linux/irq.h> |
38 | #include <linux/hrtimer.h> | 38 | #include <linux/hrtimer.h> |
39 | #include <linux/oom.h> | 39 | #include <linux/oom.h> |
40 | 40 | ||
41 | #include <asm/ptrace.h> | 41 | #include <asm/ptrace.h> |
42 | #include <asm/irq_regs.h> | 42 | #include <asm/irq_regs.h> |
43 | 43 | ||
44 | /* Whether we react on sysrq keys or just ignore them */ | 44 | /* Whether we react on sysrq keys or just ignore them */ |
45 | int __read_mostly __sysrq_enabled = 1; | 45 | int __read_mostly __sysrq_enabled = 1; |
46 | 46 | ||
47 | static int __read_mostly sysrq_always_enabled; | 47 | static int __read_mostly sysrq_always_enabled; |
48 | 48 | ||
49 | int sysrq_on(void) | 49 | int sysrq_on(void) |
50 | { | 50 | { |
51 | return __sysrq_enabled || sysrq_always_enabled; | 51 | return __sysrq_enabled || sysrq_always_enabled; |
52 | } | 52 | } |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * A value of 1 means 'all', other nonzero values are an op mask: | 55 | * A value of 1 means 'all', other nonzero values are an op mask: |
56 | */ | 56 | */ |
57 | static inline int sysrq_on_mask(int mask) | 57 | static inline int sysrq_on_mask(int mask) |
58 | { | 58 | { |
59 | return sysrq_always_enabled || __sysrq_enabled == 1 || | 59 | return sysrq_always_enabled || __sysrq_enabled == 1 || |
60 | (__sysrq_enabled & mask); | 60 | (__sysrq_enabled & mask); |
61 | } | 61 | } |
62 | 62 | ||
63 | static int __init sysrq_always_enabled_setup(char *str) | 63 | static int __init sysrq_always_enabled_setup(char *str) |
64 | { | 64 | { |
65 | sysrq_always_enabled = 1; | 65 | sysrq_always_enabled = 1; |
66 | printk(KERN_INFO "debug: sysrq always enabled.\n"); | 66 | printk(KERN_INFO "debug: sysrq always enabled.\n"); |
67 | 67 | ||
68 | return 1; | 68 | return 1; |
69 | } | 69 | } |
70 | 70 | ||
71 | __setup("sysrq_always_enabled", sysrq_always_enabled_setup); | 71 | __setup("sysrq_always_enabled", sysrq_always_enabled_setup); |
72 | 72 | ||
73 | 73 | ||
74 | static void sysrq_handle_loglevel(int key, struct tty_struct *tty) | 74 | static void sysrq_handle_loglevel(int key, struct tty_struct *tty) |
75 | { | 75 | { |
76 | int i; | 76 | int i; |
77 | i = key - '0'; | 77 | i = key - '0'; |
78 | console_loglevel = 7; | 78 | console_loglevel = 7; |
79 | printk("Loglevel set to %d\n", i); | 79 | printk("Loglevel set to %d\n", i); |
80 | console_loglevel = i; | 80 | console_loglevel = i; |
81 | } | 81 | } |
82 | static struct sysrq_key_op sysrq_loglevel_op = { | 82 | static struct sysrq_key_op sysrq_loglevel_op = { |
83 | .handler = sysrq_handle_loglevel, | 83 | .handler = sysrq_handle_loglevel, |
84 | .help_msg = "loglevel0-8", | 84 | .help_msg = "loglevel0-8", |
85 | .action_msg = "Changing Loglevel", | 85 | .action_msg = "Changing Loglevel", |
86 | .enable_mask = SYSRQ_ENABLE_LOG, | 86 | .enable_mask = SYSRQ_ENABLE_LOG, |
87 | }; | 87 | }; |
88 | 88 | ||
89 | #ifdef CONFIG_VT | 89 | #ifdef CONFIG_VT |
90 | static void sysrq_handle_SAK(int key, struct tty_struct *tty) | 90 | static void sysrq_handle_SAK(int key, struct tty_struct *tty) |
91 | { | 91 | { |
92 | struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; | 92 | struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; |
93 | schedule_work(SAK_work); | 93 | schedule_work(SAK_work); |
94 | } | 94 | } |
95 | static struct sysrq_key_op sysrq_SAK_op = { | 95 | static struct sysrq_key_op sysrq_SAK_op = { |
96 | .handler = sysrq_handle_SAK, | 96 | .handler = sysrq_handle_SAK, |
97 | .help_msg = "saK", | 97 | .help_msg = "saK", |
98 | .action_msg = "SAK", | 98 | .action_msg = "SAK", |
99 | .enable_mask = SYSRQ_ENABLE_KEYBOARD, | 99 | .enable_mask = SYSRQ_ENABLE_KEYBOARD, |
100 | }; | 100 | }; |
101 | #else | 101 | #else |
102 | #define sysrq_SAK_op (*(struct sysrq_key_op *)0) | 102 | #define sysrq_SAK_op (*(struct sysrq_key_op *)0) |
103 | #endif | 103 | #endif |
104 | 104 | ||
105 | #ifdef CONFIG_VT | 105 | #ifdef CONFIG_VT |
106 | static void sysrq_handle_unraw(int key, struct tty_struct *tty) | 106 | static void sysrq_handle_unraw(int key, struct tty_struct *tty) |
107 | { | 107 | { |
108 | struct kbd_struct *kbd = &kbd_table[fg_console]; | 108 | struct kbd_struct *kbd = &kbd_table[fg_console]; |
109 | 109 | ||
110 | if (kbd) | 110 | if (kbd) |
111 | kbd->kbdmode = VC_XLATE; | 111 | kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; |
112 | } | 112 | } |
113 | static struct sysrq_key_op sysrq_unraw_op = { | 113 | static struct sysrq_key_op sysrq_unraw_op = { |
114 | .handler = sysrq_handle_unraw, | 114 | .handler = sysrq_handle_unraw, |
115 | .help_msg = "unRaw", | 115 | .help_msg = "unRaw", |
116 | .action_msg = "Keyboard mode set to XLATE", | 116 | .action_msg = "Keyboard mode set to system default", |
117 | .enable_mask = SYSRQ_ENABLE_KEYBOARD, | 117 | .enable_mask = SYSRQ_ENABLE_KEYBOARD, |
118 | }; | 118 | }; |
119 | #else | 119 | #else |
120 | #define sysrq_unraw_op (*(struct sysrq_key_op *)0) | 120 | #define sysrq_unraw_op (*(struct sysrq_key_op *)0) |
121 | #endif /* CONFIG_VT */ | 121 | #endif /* CONFIG_VT */ |
122 | 122 | ||
123 | #ifdef CONFIG_KEXEC | 123 | #ifdef CONFIG_KEXEC |
124 | static void sysrq_handle_crashdump(int key, struct tty_struct *tty) | 124 | static void sysrq_handle_crashdump(int key, struct tty_struct *tty) |
125 | { | 125 | { |
126 | crash_kexec(get_irq_regs()); | 126 | crash_kexec(get_irq_regs()); |
127 | } | 127 | } |
128 | static struct sysrq_key_op sysrq_crashdump_op = { | 128 | static struct sysrq_key_op sysrq_crashdump_op = { |
129 | .handler = sysrq_handle_crashdump, | 129 | .handler = sysrq_handle_crashdump, |
130 | .help_msg = "Crashdump", | 130 | .help_msg = "Crashdump", |
131 | .action_msg = "Trigger a crashdump", | 131 | .action_msg = "Trigger a crashdump", |
132 | .enable_mask = SYSRQ_ENABLE_DUMP, | 132 | .enable_mask = SYSRQ_ENABLE_DUMP, |
133 | }; | 133 | }; |
134 | #else | 134 | #else |
135 | #define sysrq_crashdump_op (*(struct sysrq_key_op *)0) | 135 | #define sysrq_crashdump_op (*(struct sysrq_key_op *)0) |
136 | #endif | 136 | #endif |
137 | 137 | ||
138 | static void sysrq_handle_reboot(int key, struct tty_struct *tty) | 138 | static void sysrq_handle_reboot(int key, struct tty_struct *tty) |
139 | { | 139 | { |
140 | lockdep_off(); | 140 | lockdep_off(); |
141 | local_irq_enable(); | 141 | local_irq_enable(); |
142 | emergency_restart(); | 142 | emergency_restart(); |
143 | } | 143 | } |
144 | static struct sysrq_key_op sysrq_reboot_op = { | 144 | static struct sysrq_key_op sysrq_reboot_op = { |
145 | .handler = sysrq_handle_reboot, | 145 | .handler = sysrq_handle_reboot, |
146 | .help_msg = "reBoot", | 146 | .help_msg = "reBoot", |
147 | .action_msg = "Resetting", | 147 | .action_msg = "Resetting", |
148 | .enable_mask = SYSRQ_ENABLE_BOOT, | 148 | .enable_mask = SYSRQ_ENABLE_BOOT, |
149 | }; | 149 | }; |
150 | 150 | ||
151 | static void sysrq_handle_sync(int key, struct tty_struct *tty) | 151 | static void sysrq_handle_sync(int key, struct tty_struct *tty) |
152 | { | 152 | { |
153 | emergency_sync(); | 153 | emergency_sync(); |
154 | } | 154 | } |
155 | static struct sysrq_key_op sysrq_sync_op = { | 155 | static struct sysrq_key_op sysrq_sync_op = { |
156 | .handler = sysrq_handle_sync, | 156 | .handler = sysrq_handle_sync, |
157 | .help_msg = "Sync", | 157 | .help_msg = "Sync", |
158 | .action_msg = "Emergency Sync", | 158 | .action_msg = "Emergency Sync", |
159 | .enable_mask = SYSRQ_ENABLE_SYNC, | 159 | .enable_mask = SYSRQ_ENABLE_SYNC, |
160 | }; | 160 | }; |
161 | 161 | ||
162 | static void sysrq_handle_show_timers(int key, struct tty_struct *tty) | 162 | static void sysrq_handle_show_timers(int key, struct tty_struct *tty) |
163 | { | 163 | { |
164 | sysrq_timer_list_show(); | 164 | sysrq_timer_list_show(); |
165 | } | 165 | } |
166 | 166 | ||
167 | static struct sysrq_key_op sysrq_show_timers_op = { | 167 | static struct sysrq_key_op sysrq_show_timers_op = { |
168 | .handler = sysrq_handle_show_timers, | 168 | .handler = sysrq_handle_show_timers, |
169 | .help_msg = "show-all-timers(Q)", | 169 | .help_msg = "show-all-timers(Q)", |
170 | .action_msg = "Show Pending Timers", | 170 | .action_msg = "Show Pending Timers", |
171 | }; | 171 | }; |
172 | 172 | ||
173 | static void sysrq_handle_mountro(int key, struct tty_struct *tty) | 173 | static void sysrq_handle_mountro(int key, struct tty_struct *tty) |
174 | { | 174 | { |
175 | emergency_remount(); | 175 | emergency_remount(); |
176 | } | 176 | } |
177 | static struct sysrq_key_op sysrq_mountro_op = { | 177 | static struct sysrq_key_op sysrq_mountro_op = { |
178 | .handler = sysrq_handle_mountro, | 178 | .handler = sysrq_handle_mountro, |
179 | .help_msg = "Unmount", | 179 | .help_msg = "Unmount", |
180 | .action_msg = "Emergency Remount R/O", | 180 | .action_msg = "Emergency Remount R/O", |
181 | .enable_mask = SYSRQ_ENABLE_REMOUNT, | 181 | .enable_mask = SYSRQ_ENABLE_REMOUNT, |
182 | }; | 182 | }; |
183 | 183 | ||
184 | #ifdef CONFIG_LOCKDEP | 184 | #ifdef CONFIG_LOCKDEP |
185 | static void sysrq_handle_showlocks(int key, struct tty_struct *tty) | 185 | static void sysrq_handle_showlocks(int key, struct tty_struct *tty) |
186 | { | 186 | { |
187 | debug_show_all_locks(); | 187 | debug_show_all_locks(); |
188 | } | 188 | } |
189 | 189 | ||
190 | static struct sysrq_key_op sysrq_showlocks_op = { | 190 | static struct sysrq_key_op sysrq_showlocks_op = { |
191 | .handler = sysrq_handle_showlocks, | 191 | .handler = sysrq_handle_showlocks, |
192 | .help_msg = "show-all-locks(D)", | 192 | .help_msg = "show-all-locks(D)", |
193 | .action_msg = "Show Locks Held", | 193 | .action_msg = "Show Locks Held", |
194 | }; | 194 | }; |
195 | #else | 195 | #else |
196 | #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) | 196 | #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) |
197 | #endif | 197 | #endif |
198 | 198 | ||
199 | static void sysrq_handle_showregs(int key, struct tty_struct *tty) | 199 | static void sysrq_handle_showregs(int key, struct tty_struct *tty) |
200 | { | 200 | { |
201 | struct pt_regs *regs = get_irq_regs(); | 201 | struct pt_regs *regs = get_irq_regs(); |
202 | if (regs) | 202 | if (regs) |
203 | show_regs(regs); | 203 | show_regs(regs); |
204 | } | 204 | } |
205 | static struct sysrq_key_op sysrq_showregs_op = { | 205 | static struct sysrq_key_op sysrq_showregs_op = { |
206 | .handler = sysrq_handle_showregs, | 206 | .handler = sysrq_handle_showregs, |
207 | .help_msg = "showPc", | 207 | .help_msg = "showPc", |
208 | .action_msg = "Show Regs", | 208 | .action_msg = "Show Regs", |
209 | .enable_mask = SYSRQ_ENABLE_DUMP, | 209 | .enable_mask = SYSRQ_ENABLE_DUMP, |
210 | }; | 210 | }; |
211 | 211 | ||
212 | static void sysrq_handle_showstate(int key, struct tty_struct *tty) | 212 | static void sysrq_handle_showstate(int key, struct tty_struct *tty) |
213 | { | 213 | { |
214 | show_state(); | 214 | show_state(); |
215 | } | 215 | } |
216 | static struct sysrq_key_op sysrq_showstate_op = { | 216 | static struct sysrq_key_op sysrq_showstate_op = { |
217 | .handler = sysrq_handle_showstate, | 217 | .handler = sysrq_handle_showstate, |
218 | .help_msg = "showTasks", | 218 | .help_msg = "showTasks", |
219 | .action_msg = "Show State", | 219 | .action_msg = "Show State", |
220 | .enable_mask = SYSRQ_ENABLE_DUMP, | 220 | .enable_mask = SYSRQ_ENABLE_DUMP, |
221 | }; | 221 | }; |
222 | 222 | ||
223 | static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) | 223 | static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) |
224 | { | 224 | { |
225 | show_state_filter(TASK_UNINTERRUPTIBLE); | 225 | show_state_filter(TASK_UNINTERRUPTIBLE); |
226 | } | 226 | } |
227 | static struct sysrq_key_op sysrq_showstate_blocked_op = { | 227 | static struct sysrq_key_op sysrq_showstate_blocked_op = { |
228 | .handler = sysrq_handle_showstate_blocked, | 228 | .handler = sysrq_handle_showstate_blocked, |
229 | .help_msg = "shoW-blocked-tasks", | 229 | .help_msg = "shoW-blocked-tasks", |
230 | .action_msg = "Show Blocked State", | 230 | .action_msg = "Show Blocked State", |
231 | .enable_mask = SYSRQ_ENABLE_DUMP, | 231 | .enable_mask = SYSRQ_ENABLE_DUMP, |
232 | }; | 232 | }; |
233 | 233 | ||
234 | 234 | ||
235 | static void sysrq_handle_showmem(int key, struct tty_struct *tty) | 235 | static void sysrq_handle_showmem(int key, struct tty_struct *tty) |
236 | { | 236 | { |
237 | show_mem(); | 237 | show_mem(); |
238 | } | 238 | } |
239 | static struct sysrq_key_op sysrq_showmem_op = { | 239 | static struct sysrq_key_op sysrq_showmem_op = { |
240 | .handler = sysrq_handle_showmem, | 240 | .handler = sysrq_handle_showmem, |
241 | .help_msg = "showMem", | 241 | .help_msg = "showMem", |
242 | .action_msg = "Show Memory", | 242 | .action_msg = "Show Memory", |
243 | .enable_mask = SYSRQ_ENABLE_DUMP, | 243 | .enable_mask = SYSRQ_ENABLE_DUMP, |
244 | }; | 244 | }; |
245 | 245 | ||
246 | /* | 246 | /* |
247 | * Signal sysrq helper function. Sends a signal to all user processes. | 247 | * Signal sysrq helper function. Sends a signal to all user processes. |
248 | */ | 248 | */ |
249 | static void send_sig_all(int sig) | 249 | static void send_sig_all(int sig) |
250 | { | 250 | { |
251 | struct task_struct *p; | 251 | struct task_struct *p; |
252 | 252 | ||
253 | for_each_process(p) { | 253 | for_each_process(p) { |
254 | if (p->mm && !is_init(p)) | 254 | if (p->mm && !is_init(p)) |
255 | /* Not swapper, init nor kernel thread */ | 255 | /* Not swapper, init nor kernel thread */ |
256 | force_sig(sig, p); | 256 | force_sig(sig, p); |
257 | } | 257 | } |
258 | } | 258 | } |
259 | 259 | ||
260 | static void sysrq_handle_term(int key, struct tty_struct *tty) | 260 | static void sysrq_handle_term(int key, struct tty_struct *tty) |
261 | { | 261 | { |
262 | send_sig_all(SIGTERM); | 262 | send_sig_all(SIGTERM); |
263 | console_loglevel = 8; | 263 | console_loglevel = 8; |
264 | } | 264 | } |
265 | static struct sysrq_key_op sysrq_term_op = { | 265 | static struct sysrq_key_op sysrq_term_op = { |
266 | .handler = sysrq_handle_term, | 266 | .handler = sysrq_handle_term, |
267 | .help_msg = "tErm", | 267 | .help_msg = "tErm", |
268 | .action_msg = "Terminate All Tasks", | 268 | .action_msg = "Terminate All Tasks", |
269 | .enable_mask = SYSRQ_ENABLE_SIGNAL, | 269 | .enable_mask = SYSRQ_ENABLE_SIGNAL, |
270 | }; | 270 | }; |
271 | 271 | ||
272 | static void moom_callback(struct work_struct *ignored) | 272 | static void moom_callback(struct work_struct *ignored) |
273 | { | 273 | { |
274 | out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], | 274 | out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], |
275 | GFP_KERNEL, 0); | 275 | GFP_KERNEL, 0); |
276 | } | 276 | } |
277 | 277 | ||
278 | static DECLARE_WORK(moom_work, moom_callback); | 278 | static DECLARE_WORK(moom_work, moom_callback); |
279 | 279 | ||
280 | static void sysrq_handle_moom(int key, struct tty_struct *tty) | 280 | static void sysrq_handle_moom(int key, struct tty_struct *tty) |
281 | { | 281 | { |
282 | schedule_work(&moom_work); | 282 | schedule_work(&moom_work); |
283 | } | 283 | } |
284 | static struct sysrq_key_op sysrq_moom_op = { | 284 | static struct sysrq_key_op sysrq_moom_op = { |
285 | .handler = sysrq_handle_moom, | 285 | .handler = sysrq_handle_moom, |
286 | .help_msg = "Full", | 286 | .help_msg = "Full", |
287 | .action_msg = "Manual OOM execution", | 287 | .action_msg = "Manual OOM execution", |
288 | }; | 288 | }; |
289 | 289 | ||
290 | static void sysrq_handle_kill(int key, struct tty_struct *tty) | 290 | static void sysrq_handle_kill(int key, struct tty_struct *tty) |
291 | { | 291 | { |
292 | send_sig_all(SIGKILL); | 292 | send_sig_all(SIGKILL); |
293 | console_loglevel = 8; | 293 | console_loglevel = 8; |
294 | } | 294 | } |
295 | static struct sysrq_key_op sysrq_kill_op = { | 295 | static struct sysrq_key_op sysrq_kill_op = { |
296 | .handler = sysrq_handle_kill, | 296 | .handler = sysrq_handle_kill, |
297 | .help_msg = "kIll", | 297 | .help_msg = "kIll", |
298 | .action_msg = "Kill All Tasks", | 298 | .action_msg = "Kill All Tasks", |
299 | .enable_mask = SYSRQ_ENABLE_SIGNAL, | 299 | .enable_mask = SYSRQ_ENABLE_SIGNAL, |
300 | }; | 300 | }; |
301 | 301 | ||
302 | static void sysrq_handle_unrt(int key, struct tty_struct *tty) | 302 | static void sysrq_handle_unrt(int key, struct tty_struct *tty) |
303 | { | 303 | { |
304 | normalize_rt_tasks(); | 304 | normalize_rt_tasks(); |
305 | } | 305 | } |
306 | static struct sysrq_key_op sysrq_unrt_op = { | 306 | static struct sysrq_key_op sysrq_unrt_op = { |
307 | .handler = sysrq_handle_unrt, | 307 | .handler = sysrq_handle_unrt, |
308 | .help_msg = "Nice", | 308 | .help_msg = "Nice", |
309 | .action_msg = "Nice All RT Tasks", | 309 | .action_msg = "Nice All RT Tasks", |
310 | .enable_mask = SYSRQ_ENABLE_RTNICE, | 310 | .enable_mask = SYSRQ_ENABLE_RTNICE, |
311 | }; | 311 | }; |
312 | 312 | ||
313 | /* Key Operations table and lock */ | 313 | /* Key Operations table and lock */ |
314 | static DEFINE_SPINLOCK(sysrq_key_table_lock); | 314 | static DEFINE_SPINLOCK(sysrq_key_table_lock); |
315 | 315 | ||
316 | static struct sysrq_key_op *sysrq_key_table[36] = { | 316 | static struct sysrq_key_op *sysrq_key_table[36] = { |
317 | &sysrq_loglevel_op, /* 0 */ | 317 | &sysrq_loglevel_op, /* 0 */ |
318 | &sysrq_loglevel_op, /* 1 */ | 318 | &sysrq_loglevel_op, /* 1 */ |
319 | &sysrq_loglevel_op, /* 2 */ | 319 | &sysrq_loglevel_op, /* 2 */ |
320 | &sysrq_loglevel_op, /* 3 */ | 320 | &sysrq_loglevel_op, /* 3 */ |
321 | &sysrq_loglevel_op, /* 4 */ | 321 | &sysrq_loglevel_op, /* 4 */ |
322 | &sysrq_loglevel_op, /* 5 */ | 322 | &sysrq_loglevel_op, /* 5 */ |
323 | &sysrq_loglevel_op, /* 6 */ | 323 | &sysrq_loglevel_op, /* 6 */ |
324 | &sysrq_loglevel_op, /* 7 */ | 324 | &sysrq_loglevel_op, /* 7 */ |
325 | &sysrq_loglevel_op, /* 8 */ | 325 | &sysrq_loglevel_op, /* 8 */ |
326 | &sysrq_loglevel_op, /* 9 */ | 326 | &sysrq_loglevel_op, /* 9 */ |
327 | 327 | ||
328 | /* | 328 | /* |
329 | * a: Don't use for system provided sysrqs, it is handled specially on | 329 | * a: Don't use for system provided sysrqs, it is handled specially on |
330 | * sparc and will never arrive. | 330 | * sparc and will never arrive. |
331 | */ | 331 | */ |
332 | NULL, /* a */ | 332 | NULL, /* a */ |
333 | &sysrq_reboot_op, /* b */ | 333 | &sysrq_reboot_op, /* b */ |
334 | &sysrq_crashdump_op, /* c & ibm_emac driver debug */ | 334 | &sysrq_crashdump_op, /* c & ibm_emac driver debug */ |
335 | &sysrq_showlocks_op, /* d */ | 335 | &sysrq_showlocks_op, /* d */ |
336 | &sysrq_term_op, /* e */ | 336 | &sysrq_term_op, /* e */ |
337 | &sysrq_moom_op, /* f */ | 337 | &sysrq_moom_op, /* f */ |
338 | /* g: May be registered by ppc for kgdb */ | 338 | /* g: May be registered by ppc for kgdb */ |
339 | NULL, /* g */ | 339 | NULL, /* g */ |
340 | NULL, /* h */ | 340 | NULL, /* h */ |
341 | &sysrq_kill_op, /* i */ | 341 | &sysrq_kill_op, /* i */ |
342 | NULL, /* j */ | 342 | NULL, /* j */ |
343 | &sysrq_SAK_op, /* k */ | 343 | &sysrq_SAK_op, /* k */ |
344 | NULL, /* l */ | 344 | NULL, /* l */ |
345 | &sysrq_showmem_op, /* m */ | 345 | &sysrq_showmem_op, /* m */ |
346 | &sysrq_unrt_op, /* n */ | 346 | &sysrq_unrt_op, /* n */ |
347 | /* o: This will often be registered as 'Off' at init time */ | 347 | /* o: This will often be registered as 'Off' at init time */ |
348 | NULL, /* o */ | 348 | NULL, /* o */ |
349 | &sysrq_showregs_op, /* p */ | 349 | &sysrq_showregs_op, /* p */ |
350 | &sysrq_show_timers_op, /* q */ | 350 | &sysrq_show_timers_op, /* q */ |
351 | &sysrq_unraw_op, /* r */ | 351 | &sysrq_unraw_op, /* r */ |
352 | &sysrq_sync_op, /* s */ | 352 | &sysrq_sync_op, /* s */ |
353 | &sysrq_showstate_op, /* t */ | 353 | &sysrq_showstate_op, /* t */ |
354 | &sysrq_mountro_op, /* u */ | 354 | &sysrq_mountro_op, /* u */ |
355 | /* v: May be registered at init time by SMP VOYAGER */ | 355 | /* v: May be registered at init time by SMP VOYAGER */ |
356 | NULL, /* v */ | 356 | NULL, /* v */ |
357 | &sysrq_showstate_blocked_op, /* w */ | 357 | &sysrq_showstate_blocked_op, /* w */ |
358 | /* x: May be registered on ppc/powerpc for xmon */ | 358 | /* x: May be registered on ppc/powerpc for xmon */ |
359 | NULL, /* x */ | 359 | NULL, /* x */ |
360 | NULL, /* y */ | 360 | NULL, /* y */ |
361 | NULL /* z */ | 361 | NULL /* z */ |
362 | }; | 362 | }; |
363 | 363 | ||
364 | /* key2index calculation, -1 on invalid index */ | 364 | /* key2index calculation, -1 on invalid index */ |
365 | static int sysrq_key_table_key2index(int key) | 365 | static int sysrq_key_table_key2index(int key) |
366 | { | 366 | { |
367 | int retval; | 367 | int retval; |
368 | 368 | ||
369 | if ((key >= '0') && (key <= '9')) | 369 | if ((key >= '0') && (key <= '9')) |
370 | retval = key - '0'; | 370 | retval = key - '0'; |
371 | else if ((key >= 'a') && (key <= 'z')) | 371 | else if ((key >= 'a') && (key <= 'z')) |
372 | retval = key + 10 - 'a'; | 372 | retval = key + 10 - 'a'; |
373 | else | 373 | else |
374 | retval = -1; | 374 | retval = -1; |
375 | return retval; | 375 | return retval; |
376 | } | 376 | } |
377 | 377 | ||
378 | /* | 378 | /* |
379 | * get and put functions for the table, exposed to modules. | 379 | * get and put functions for the table, exposed to modules. |
380 | */ | 380 | */ |
381 | struct sysrq_key_op *__sysrq_get_key_op(int key) | 381 | struct sysrq_key_op *__sysrq_get_key_op(int key) |
382 | { | 382 | { |
383 | struct sysrq_key_op *op_p = NULL; | 383 | struct sysrq_key_op *op_p = NULL; |
384 | int i; | 384 | int i; |
385 | 385 | ||
386 | i = sysrq_key_table_key2index(key); | 386 | i = sysrq_key_table_key2index(key); |
387 | if (i != -1) | 387 | if (i != -1) |
388 | op_p = sysrq_key_table[i]; | 388 | op_p = sysrq_key_table[i]; |
389 | return op_p; | 389 | return op_p; |
390 | } | 390 | } |
391 | 391 | ||
392 | static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) | 392 | static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) |
393 | { | 393 | { |
394 | int i = sysrq_key_table_key2index(key); | 394 | int i = sysrq_key_table_key2index(key); |
395 | 395 | ||
396 | if (i != -1) | 396 | if (i != -1) |
397 | sysrq_key_table[i] = op_p; | 397 | sysrq_key_table[i] = op_p; |
398 | } | 398 | } |
399 | 399 | ||
400 | /* | 400 | /* |
401 | * This is the non-locking version of handle_sysrq. It must/can only be called | 401 | * This is the non-locking version of handle_sysrq. It must/can only be called |
402 | * by sysrq key handlers, as they are inside of the lock | 402 | * by sysrq key handlers, as they are inside of the lock |
403 | */ | 403 | */ |
404 | void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) | 404 | void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) |
405 | { | 405 | { |
406 | struct sysrq_key_op *op_p; | 406 | struct sysrq_key_op *op_p; |
407 | int orig_log_level; | 407 | int orig_log_level; |
408 | int i; | 408 | int i; |
409 | unsigned long flags; | 409 | unsigned long flags; |
410 | 410 | ||
411 | spin_lock_irqsave(&sysrq_key_table_lock, flags); | 411 | spin_lock_irqsave(&sysrq_key_table_lock, flags); |
412 | orig_log_level = console_loglevel; | 412 | orig_log_level = console_loglevel; |
413 | console_loglevel = 7; | 413 | console_loglevel = 7; |
414 | printk(KERN_INFO "SysRq : "); | 414 | printk(KERN_INFO "SysRq : "); |
415 | 415 | ||
416 | op_p = __sysrq_get_key_op(key); | 416 | op_p = __sysrq_get_key_op(key); |
417 | if (op_p) { | 417 | if (op_p) { |
418 | /* | 418 | /* |
419 | * Should we check for enabled operations (/proc/sysrq-trigger | 419 | * Should we check for enabled operations (/proc/sysrq-trigger |
420 | * should not) and is the invoked operation enabled? | 420 | * should not) and is the invoked operation enabled? |
421 | */ | 421 | */ |
422 | if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { | 422 | if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { |
423 | printk("%s\n", op_p->action_msg); | 423 | printk("%s\n", op_p->action_msg); |
424 | console_loglevel = orig_log_level; | 424 | console_loglevel = orig_log_level; |
425 | op_p->handler(key, tty); | 425 | op_p->handler(key, tty); |
426 | } else { | 426 | } else { |
427 | printk("This sysrq operation is disabled.\n"); | 427 | printk("This sysrq operation is disabled.\n"); |
428 | } | 428 | } |
429 | } else { | 429 | } else { |
430 | printk("HELP : "); | 430 | printk("HELP : "); |
431 | /* Only print the help msg once per handler */ | 431 | /* Only print the help msg once per handler */ |
432 | for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) { | 432 | for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) { |
433 | if (sysrq_key_table[i]) { | 433 | if (sysrq_key_table[i]) { |
434 | int j; | 434 | int j; |
435 | 435 | ||
436 | for (j = 0; sysrq_key_table[i] != | 436 | for (j = 0; sysrq_key_table[i] != |
437 | sysrq_key_table[j]; j++) | 437 | sysrq_key_table[j]; j++) |
438 | ; | 438 | ; |
439 | if (j != i) | 439 | if (j != i) |
440 | continue; | 440 | continue; |
441 | printk("%s ", sysrq_key_table[i]->help_msg); | 441 | printk("%s ", sysrq_key_table[i]->help_msg); |
442 | } | 442 | } |
443 | } | 443 | } |
444 | printk("\n"); | 444 | printk("\n"); |
445 | console_loglevel = orig_log_level; | 445 | console_loglevel = orig_log_level; |
446 | } | 446 | } |
447 | spin_unlock_irqrestore(&sysrq_key_table_lock, flags); | 447 | spin_unlock_irqrestore(&sysrq_key_table_lock, flags); |
448 | } | 448 | } |
449 | 449 | ||
450 | /* | 450 | /* |
451 | * This function is called by the keyboard handler when SysRq is pressed | 451 | * This function is called by the keyboard handler when SysRq is pressed |
452 | * and any other keycode arrives. | 452 | * and any other keycode arrives. |
453 | */ | 453 | */ |
454 | void handle_sysrq(int key, struct tty_struct *tty) | 454 | void handle_sysrq(int key, struct tty_struct *tty) |
455 | { | 455 | { |
456 | if (sysrq_on()) | 456 | if (sysrq_on()) |
457 | __handle_sysrq(key, tty, 1); | 457 | __handle_sysrq(key, tty, 1); |
458 | } | 458 | } |
459 | EXPORT_SYMBOL(handle_sysrq); | 459 | EXPORT_SYMBOL(handle_sysrq); |
460 | 460 | ||
461 | static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, | 461 | static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, |
462 | struct sysrq_key_op *remove_op_p) | 462 | struct sysrq_key_op *remove_op_p) |
463 | { | 463 | { |
464 | 464 | ||
465 | int retval; | 465 | int retval; |
466 | unsigned long flags; | 466 | unsigned long flags; |
467 | 467 | ||
468 | spin_lock_irqsave(&sysrq_key_table_lock, flags); | 468 | spin_lock_irqsave(&sysrq_key_table_lock, flags); |
469 | if (__sysrq_get_key_op(key) == remove_op_p) { | 469 | if (__sysrq_get_key_op(key) == remove_op_p) { |
470 | __sysrq_put_key_op(key, insert_op_p); | 470 | __sysrq_put_key_op(key, insert_op_p); |
471 | retval = 0; | 471 | retval = 0; |
472 | } else { | 472 | } else { |
473 | retval = -1; | 473 | retval = -1; |
474 | } | 474 | } |
475 | spin_unlock_irqrestore(&sysrq_key_table_lock, flags); | 475 | spin_unlock_irqrestore(&sysrq_key_table_lock, flags); |
476 | return retval; | 476 | return retval; |
477 | } | 477 | } |
478 | 478 | ||
479 | int register_sysrq_key(int key, struct sysrq_key_op *op_p) | 479 | int register_sysrq_key(int key, struct sysrq_key_op *op_p) |
480 | { | 480 | { |
481 | return __sysrq_swap_key_ops(key, op_p, NULL); | 481 | return __sysrq_swap_key_ops(key, op_p, NULL); |
482 | } | 482 | } |
483 | EXPORT_SYMBOL(register_sysrq_key); | 483 | EXPORT_SYMBOL(register_sysrq_key); |
484 | 484 | ||
485 | int unregister_sysrq_key(int key, struct sysrq_key_op *op_p) | 485 | int unregister_sysrq_key(int key, struct sysrq_key_op *op_p) |
486 | { | 486 | { |
487 | return __sysrq_swap_key_ops(key, NULL, op_p); | 487 | return __sysrq_swap_key_ops(key, NULL, op_p); |
488 | } | 488 | } |
489 | EXPORT_SYMBOL(unregister_sysrq_key); | 489 | EXPORT_SYMBOL(unregister_sysrq_key); |
490 | 490 |
drivers/char/vt.c
1 | /* | 1 | /* |
2 | * linux/drivers/char/vt.c | 2 | * linux/drivers/char/vt.c |
3 | * | 3 | * |
4 | * Copyright (C) 1991, 1992 Linus Torvalds | 4 | * Copyright (C) 1991, 1992 Linus Torvalds |
5 | */ | 5 | */ |
6 | 6 | ||
7 | /* | 7 | /* |
8 | * Hopefully this will be a rather complete VT102 implementation. | 8 | * Hopefully this will be a rather complete VT102 implementation. |
9 | * | 9 | * |
10 | * Beeping thanks to John T Kohl. | 10 | * Beeping thanks to John T Kohl. |
11 | * | 11 | * |
12 | * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics | 12 | * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics |
13 | * Chars, and VT100 enhancements by Peter MacDonald. | 13 | * Chars, and VT100 enhancements by Peter MacDonald. |
14 | * | 14 | * |
15 | * Copy and paste function by Andrew Haylett, | 15 | * Copy and paste function by Andrew Haylett, |
16 | * some enhancements by Alessandro Rubini. | 16 | * some enhancements by Alessandro Rubini. |
17 | * | 17 | * |
18 | * Code to check for different video-cards mostly by Galen Hunt, | 18 | * Code to check for different video-cards mostly by Galen Hunt, |
19 | * <g-hunt@ee.utah.edu> | 19 | * <g-hunt@ee.utah.edu> |
20 | * | 20 | * |
21 | * Rudimentary ISO 10646/Unicode/UTF-8 character set support by | 21 | * Rudimentary ISO 10646/Unicode/UTF-8 character set support by |
22 | * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>. | 22 | * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>. |
23 | * | 23 | * |
24 | * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 | 24 | * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 |
25 | * Resizing of consoles, aeb, 940926 | 25 | * Resizing of consoles, aeb, 940926 |
26 | * | 26 | * |
27 | * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 | 27 | * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 |
28 | * <poe@daimi.aau.dk> | 28 | * <poe@daimi.aau.dk> |
29 | * | 29 | * |
30 | * User-defined bell sound, new setterm control sequences and printk | 30 | * User-defined bell sound, new setterm control sequences and printk |
31 | * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95 | 31 | * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95 |
32 | * | 32 | * |
33 | * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp> | 33 | * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp> |
34 | * | 34 | * |
35 | * Merge with the abstract console driver by Geert Uytterhoeven | 35 | * Merge with the abstract console driver by Geert Uytterhoeven |
36 | * <geert@linux-m68k.org>, Jan 1997. | 36 | * <geert@linux-m68k.org>, Jan 1997. |
37 | * | 37 | * |
38 | * Original m68k console driver modifications by | 38 | * Original m68k console driver modifications by |
39 | * | 39 | * |
40 | * - Arno Griffioen <arno@usn.nl> | 40 | * - Arno Griffioen <arno@usn.nl> |
41 | * - David Carter <carter@cs.bris.ac.uk> | 41 | * - David Carter <carter@cs.bris.ac.uk> |
42 | * | 42 | * |
43 | * The abstract console driver provides a generic interface for a text | 43 | * The abstract console driver provides a generic interface for a text |
44 | * console. It supports VGA text mode, frame buffer based graphical consoles | 44 | * console. It supports VGA text mode, frame buffer based graphical consoles |
45 | * and special graphics processors that are only accessible through some | 45 | * and special graphics processors that are only accessible through some |
46 | * registers (e.g. a TMS340x0 GSP). | 46 | * registers (e.g. a TMS340x0 GSP). |
47 | * | 47 | * |
48 | * The interface to the hardware is specified using a special structure | 48 | * The interface to the hardware is specified using a special structure |
49 | * (struct consw) which contains function pointers to console operations | 49 | * (struct consw) which contains function pointers to console operations |
50 | * (see <linux/console.h> for more information). | 50 | * (see <linux/console.h> for more information). |
51 | * | 51 | * |
52 | * Support for changeable cursor shape | 52 | * Support for changeable cursor shape |
53 | * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997 | 53 | * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997 |
54 | * | 54 | * |
55 | * Ported to i386 and con_scrolldelta fixed | 55 | * Ported to i386 and con_scrolldelta fixed |
56 | * by Emmanuel Marty <core@ggi-project.org>, April 1998 | 56 | * by Emmanuel Marty <core@ggi-project.org>, April 1998 |
57 | * | 57 | * |
58 | * Resurrected character buffers in videoram plus lots of other trickery | 58 | * Resurrected character buffers in videoram plus lots of other trickery |
59 | * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998 | 59 | * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998 |
60 | * | 60 | * |
61 | * Removed old-style timers, introduced console_timer, made timer | 61 | * Removed old-style timers, introduced console_timer, made timer |
62 | * deletion SMP-safe. 17Jun00, Andrew Morton <andrewm@uow.edu.au> | 62 | * deletion SMP-safe. 17Jun00, Andrew Morton <andrewm@uow.edu.au> |
63 | * | 63 | * |
64 | * Removed console_lock, enabled interrupts across all console operations | 64 | * Removed console_lock, enabled interrupts across all console operations |
65 | * 13 March 2001, Andrew Morton | 65 | * 13 March 2001, Andrew Morton |
66 | * | 66 | * |
67 | * Fixed UTF-8 mode so alternate charset modes always work according | 67 | * Fixed UTF-8 mode so alternate charset modes always work according |
68 | * to control sequences interpreted in do_con_trol function | 68 | * to control sequences interpreted in do_con_trol function |
69 | * preserving backward VT100 semigraphics compatibility, | 69 | * preserving backward VT100 semigraphics compatibility, |
70 | * malformed UTF sequences represented as sequences of replacement glyphs, | 70 | * malformed UTF sequences represented as sequences of replacement glyphs, |
71 | * original codes or '?' as a last resort if replacement glyph is undefined | 71 | * original codes or '?' as a last resort if replacement glyph is undefined |
72 | * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006 | 72 | * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006 |
73 | */ | 73 | */ |
74 | 74 | ||
75 | #include <linux/module.h> | 75 | #include <linux/module.h> |
76 | #include <linux/types.h> | 76 | #include <linux/types.h> |
77 | #include <linux/sched.h> | 77 | #include <linux/sched.h> |
78 | #include <linux/tty.h> | 78 | #include <linux/tty.h> |
79 | #include <linux/tty_flip.h> | 79 | #include <linux/tty_flip.h> |
80 | #include <linux/kernel.h> | 80 | #include <linux/kernel.h> |
81 | #include <linux/string.h> | 81 | #include <linux/string.h> |
82 | #include <linux/errno.h> | 82 | #include <linux/errno.h> |
83 | #include <linux/kd.h> | 83 | #include <linux/kd.h> |
84 | #include <linux/slab.h> | 84 | #include <linux/slab.h> |
85 | #include <linux/major.h> | 85 | #include <linux/major.h> |
86 | #include <linux/mm.h> | 86 | #include <linux/mm.h> |
87 | #include <linux/console.h> | 87 | #include <linux/console.h> |
88 | #include <linux/init.h> | 88 | #include <linux/init.h> |
89 | #include <linux/mutex.h> | 89 | #include <linux/mutex.h> |
90 | #include <linux/vt_kern.h> | 90 | #include <linux/vt_kern.h> |
91 | #include <linux/selection.h> | 91 | #include <linux/selection.h> |
92 | #include <linux/tiocl.h> | 92 | #include <linux/tiocl.h> |
93 | #include <linux/kbd_kern.h> | 93 | #include <linux/kbd_kern.h> |
94 | #include <linux/consolemap.h> | 94 | #include <linux/consolemap.h> |
95 | #include <linux/timer.h> | 95 | #include <linux/timer.h> |
96 | #include <linux/interrupt.h> | 96 | #include <linux/interrupt.h> |
97 | #include <linux/workqueue.h> | 97 | #include <linux/workqueue.h> |
98 | #include <linux/bootmem.h> | 98 | #include <linux/bootmem.h> |
99 | #include <linux/pm.h> | 99 | #include <linux/pm.h> |
100 | #include <linux/font.h> | 100 | #include <linux/font.h> |
101 | #include <linux/bitops.h> | 101 | #include <linux/bitops.h> |
102 | 102 | ||
103 | #include <asm/io.h> | 103 | #include <asm/io.h> |
104 | #include <asm/system.h> | 104 | #include <asm/system.h> |
105 | #include <asm/uaccess.h> | 105 | #include <asm/uaccess.h> |
106 | 106 | ||
107 | #define MAX_NR_CON_DRIVER 16 | 107 | #define MAX_NR_CON_DRIVER 16 |
108 | 108 | ||
109 | #define CON_DRIVER_FLAG_MODULE 1 | 109 | #define CON_DRIVER_FLAG_MODULE 1 |
110 | #define CON_DRIVER_FLAG_INIT 2 | 110 | #define CON_DRIVER_FLAG_INIT 2 |
111 | #define CON_DRIVER_FLAG_ATTR 4 | 111 | #define CON_DRIVER_FLAG_ATTR 4 |
112 | 112 | ||
113 | struct con_driver { | 113 | struct con_driver { |
114 | const struct consw *con; | 114 | const struct consw *con; |
115 | const char *desc; | 115 | const char *desc; |
116 | struct device *dev; | 116 | struct device *dev; |
117 | int node; | 117 | int node; |
118 | int first; | 118 | int first; |
119 | int last; | 119 | int last; |
120 | int flag; | 120 | int flag; |
121 | }; | 121 | }; |
122 | 122 | ||
123 | static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER]; | 123 | static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER]; |
124 | const struct consw *conswitchp; | 124 | const struct consw *conswitchp; |
125 | 125 | ||
126 | /* A bitmap for codes <32. A bit of 1 indicates that the code | 126 | /* A bitmap for codes <32. A bit of 1 indicates that the code |
127 | * corresponding to that bit number invokes some special action | 127 | * corresponding to that bit number invokes some special action |
128 | * (such as cursor movement) and should not be displayed as a | 128 | * (such as cursor movement) and should not be displayed as a |
129 | * glyph unless the disp_ctrl mode is explicitly enabled. | 129 | * glyph unless the disp_ctrl mode is explicitly enabled. |
130 | */ | 130 | */ |
131 | #define CTRL_ACTION 0x0d00ff81 | 131 | #define CTRL_ACTION 0x0d00ff81 |
132 | #define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ | 132 | #define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ |
133 | 133 | ||
134 | /* | 134 | /* |
135 | * Here is the default bell parameters: 750HZ, 1/8th of a second | 135 | * Here is the default bell parameters: 750HZ, 1/8th of a second |
136 | */ | 136 | */ |
137 | #define DEFAULT_BELL_PITCH 750 | 137 | #define DEFAULT_BELL_PITCH 750 |
138 | #define DEFAULT_BELL_DURATION (HZ/8) | 138 | #define DEFAULT_BELL_DURATION (HZ/8) |
139 | 139 | ||
140 | struct vc vc_cons [MAX_NR_CONSOLES]; | 140 | struct vc vc_cons [MAX_NR_CONSOLES]; |
141 | 141 | ||
142 | #ifndef VT_SINGLE_DRIVER | 142 | #ifndef VT_SINGLE_DRIVER |
143 | static const struct consw *con_driver_map[MAX_NR_CONSOLES]; | 143 | static const struct consw *con_driver_map[MAX_NR_CONSOLES]; |
144 | #endif | 144 | #endif |
145 | 145 | ||
146 | static int con_open(struct tty_struct *, struct file *); | 146 | static int con_open(struct tty_struct *, struct file *); |
147 | static void vc_init(struct vc_data *vc, unsigned int rows, | 147 | static void vc_init(struct vc_data *vc, unsigned int rows, |
148 | unsigned int cols, int do_clear); | 148 | unsigned int cols, int do_clear); |
149 | static void gotoxy(struct vc_data *vc, int new_x, int new_y); | 149 | static void gotoxy(struct vc_data *vc, int new_x, int new_y); |
150 | static void save_cur(struct vc_data *vc); | 150 | static void save_cur(struct vc_data *vc); |
151 | static void reset_terminal(struct vc_data *vc, int do_clear); | 151 | static void reset_terminal(struct vc_data *vc, int do_clear); |
152 | static void con_flush_chars(struct tty_struct *tty); | 152 | static void con_flush_chars(struct tty_struct *tty); |
153 | static int set_vesa_blanking(char __user *p); | 153 | static int set_vesa_blanking(char __user *p); |
154 | static void set_cursor(struct vc_data *vc); | 154 | static void set_cursor(struct vc_data *vc); |
155 | static void hide_cursor(struct vc_data *vc); | 155 | static void hide_cursor(struct vc_data *vc); |
156 | static void console_callback(struct work_struct *ignored); | 156 | static void console_callback(struct work_struct *ignored); |
157 | static void blank_screen_t(unsigned long dummy); | 157 | static void blank_screen_t(unsigned long dummy); |
158 | static void set_palette(struct vc_data *vc); | 158 | static void set_palette(struct vc_data *vc); |
159 | 159 | ||
160 | static int printable; /* Is console ready for printing? */ | 160 | static int printable; /* Is console ready for printing? */ |
161 | static int default_utf8; | 161 | #ifdef CONFIG_VT_UNICODE |
162 | int default_utf8 = 1; | ||
163 | #else | ||
164 | int default_utf8; | ||
165 | #endif | ||
162 | module_param(default_utf8, int, S_IRUGO | S_IWUSR); | 166 | module_param(default_utf8, int, S_IRUGO | S_IWUSR); |
163 | 167 | ||
164 | /* | 168 | /* |
165 | * ignore_poke: don't unblank the screen when things are typed. This is | 169 | * ignore_poke: don't unblank the screen when things are typed. This is |
166 | * mainly for the privacy of braille terminal users. | 170 | * mainly for the privacy of braille terminal users. |
167 | */ | 171 | */ |
168 | static int ignore_poke; | 172 | static int ignore_poke; |
169 | 173 | ||
170 | int do_poke_blanked_console; | 174 | int do_poke_blanked_console; |
171 | int console_blanked; | 175 | int console_blanked; |
172 | 176 | ||
173 | static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ | 177 | static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ |
174 | static int blankinterval = 10*60*HZ; | 178 | static int blankinterval = 10*60*HZ; |
175 | static int vesa_off_interval; | 179 | static int vesa_off_interval; |
176 | 180 | ||
177 | static DECLARE_WORK(console_work, console_callback); | 181 | static DECLARE_WORK(console_work, console_callback); |
178 | 182 | ||
179 | /* | 183 | /* |
180 | * fg_console is the current virtual console, | 184 | * fg_console is the current virtual console, |
181 | * last_console is the last used one, | 185 | * last_console is the last used one, |
182 | * want_console is the console we want to switch to, | 186 | * want_console is the console we want to switch to, |
183 | * kmsg_redirect is the console for kernel messages, | 187 | * kmsg_redirect is the console for kernel messages, |
184 | */ | 188 | */ |
185 | int fg_console; | 189 | int fg_console; |
186 | int last_console; | 190 | int last_console; |
187 | int want_console = -1; | 191 | int want_console = -1; |
188 | int kmsg_redirect; | 192 | int kmsg_redirect; |
189 | 193 | ||
190 | /* | 194 | /* |
191 | * For each existing display, we have a pointer to console currently visible | 195 | * For each existing display, we have a pointer to console currently visible |
192 | * on that display, allowing consoles other than fg_console to be refreshed | 196 | * on that display, allowing consoles other than fg_console to be refreshed |
193 | * appropriately. Unless the low-level driver supplies its own display_fg | 197 | * appropriately. Unless the low-level driver supplies its own display_fg |
194 | * variable, we use this one for the "master display". | 198 | * variable, we use this one for the "master display". |
195 | */ | 199 | */ |
196 | static struct vc_data *master_display_fg; | 200 | static struct vc_data *master_display_fg; |
197 | 201 | ||
198 | /* | 202 | /* |
199 | * Unfortunately, we need to delay tty echo when we're currently writing to the | 203 | * Unfortunately, we need to delay tty echo when we're currently writing to the |
200 | * console since the code is (and always was) not re-entrant, so we schedule | 204 | * console since the code is (and always was) not re-entrant, so we schedule |
201 | * all flip requests to process context with schedule-task() and run it from | 205 | * all flip requests to process context with schedule-task() and run it from |
202 | * console_callback(). | 206 | * console_callback(). |
203 | */ | 207 | */ |
204 | 208 | ||
205 | /* | 209 | /* |
206 | * For the same reason, we defer scrollback to the console callback. | 210 | * For the same reason, we defer scrollback to the console callback. |
207 | */ | 211 | */ |
208 | static int scrollback_delta; | 212 | static int scrollback_delta; |
209 | 213 | ||
210 | /* | 214 | /* |
211 | * Hook so that the power management routines can (un)blank | 215 | * Hook so that the power management routines can (un)blank |
212 | * the console on our behalf. | 216 | * the console on our behalf. |
213 | */ | 217 | */ |
214 | int (*console_blank_hook)(int); | 218 | int (*console_blank_hook)(int); |
215 | 219 | ||
216 | static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0); | 220 | static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0); |
217 | static int blank_state; | 221 | static int blank_state; |
218 | static int blank_timer_expired; | 222 | static int blank_timer_expired; |
219 | enum { | 223 | enum { |
220 | blank_off = 0, | 224 | blank_off = 0, |
221 | blank_normal_wait, | 225 | blank_normal_wait, |
222 | blank_vesa_wait, | 226 | blank_vesa_wait, |
223 | }; | 227 | }; |
224 | 228 | ||
225 | /* | 229 | /* |
226 | * Low-Level Functions | 230 | * Low-Level Functions |
227 | */ | 231 | */ |
228 | 232 | ||
229 | #define IS_FG(vc) ((vc)->vc_num == fg_console) | 233 | #define IS_FG(vc) ((vc)->vc_num == fg_console) |
230 | 234 | ||
231 | #ifdef VT_BUF_VRAM_ONLY | 235 | #ifdef VT_BUF_VRAM_ONLY |
232 | #define DO_UPDATE(vc) 0 | 236 | #define DO_UPDATE(vc) 0 |
233 | #else | 237 | #else |
234 | #define DO_UPDATE(vc) CON_IS_VISIBLE(vc) | 238 | #define DO_UPDATE(vc) CON_IS_VISIBLE(vc) |
235 | #endif | 239 | #endif |
236 | 240 | ||
237 | static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) | 241 | static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) |
238 | { | 242 | { |
239 | unsigned short *p; | 243 | unsigned short *p; |
240 | 244 | ||
241 | if (!viewed) | 245 | if (!viewed) |
242 | p = (unsigned short *)(vc->vc_origin + offset); | 246 | p = (unsigned short *)(vc->vc_origin + offset); |
243 | else if (!vc->vc_sw->con_screen_pos) | 247 | else if (!vc->vc_sw->con_screen_pos) |
244 | p = (unsigned short *)(vc->vc_visible_origin + offset); | 248 | p = (unsigned short *)(vc->vc_visible_origin + offset); |
245 | else | 249 | else |
246 | p = vc->vc_sw->con_screen_pos(vc, offset); | 250 | p = vc->vc_sw->con_screen_pos(vc, offset); |
247 | return p; | 251 | return p; |
248 | } | 252 | } |
249 | 253 | ||
250 | static inline void scrolldelta(int lines) | 254 | static inline void scrolldelta(int lines) |
251 | { | 255 | { |
252 | scrollback_delta += lines; | 256 | scrollback_delta += lines; |
253 | schedule_console_callback(); | 257 | schedule_console_callback(); |
254 | } | 258 | } |
255 | 259 | ||
256 | void schedule_console_callback(void) | 260 | void schedule_console_callback(void) |
257 | { | 261 | { |
258 | schedule_work(&console_work); | 262 | schedule_work(&console_work); |
259 | } | 263 | } |
260 | 264 | ||
261 | static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) | 265 | static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) |
262 | { | 266 | { |
263 | unsigned short *d, *s; | 267 | unsigned short *d, *s; |
264 | 268 | ||
265 | if (t+nr >= b) | 269 | if (t+nr >= b) |
266 | nr = b - t - 1; | 270 | nr = b - t - 1; |
267 | if (b > vc->vc_rows || t >= b || nr < 1) | 271 | if (b > vc->vc_rows || t >= b || nr < 1) |
268 | return; | 272 | return; |
269 | if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) | 273 | if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) |
270 | return; | 274 | return; |
271 | d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); | 275 | d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); |
272 | s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); | 276 | s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); |
273 | scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); | 277 | scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); |
274 | scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, | 278 | scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, |
275 | vc->vc_size_row * nr); | 279 | vc->vc_size_row * nr); |
276 | } | 280 | } |
277 | 281 | ||
278 | static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) | 282 | static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) |
279 | { | 283 | { |
280 | unsigned short *s; | 284 | unsigned short *s; |
281 | unsigned int step; | 285 | unsigned int step; |
282 | 286 | ||
283 | if (t+nr >= b) | 287 | if (t+nr >= b) |
284 | nr = b - t - 1; | 288 | nr = b - t - 1; |
285 | if (b > vc->vc_rows || t >= b || nr < 1) | 289 | if (b > vc->vc_rows || t >= b || nr < 1) |
286 | return; | 290 | return; |
287 | if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) | 291 | if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) |
288 | return; | 292 | return; |
289 | s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); | 293 | s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); |
290 | step = vc->vc_cols * nr; | 294 | step = vc->vc_cols * nr; |
291 | scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); | 295 | scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); |
292 | scr_memsetw(s, vc->vc_video_erase_char, 2 * step); | 296 | scr_memsetw(s, vc->vc_video_erase_char, 2 * step); |
293 | } | 297 | } |
294 | 298 | ||
295 | static void do_update_region(struct vc_data *vc, unsigned long start, int count) | 299 | static void do_update_region(struct vc_data *vc, unsigned long start, int count) |
296 | { | 300 | { |
297 | #ifndef VT_BUF_VRAM_ONLY | 301 | #ifndef VT_BUF_VRAM_ONLY |
298 | unsigned int xx, yy, offset; | 302 | unsigned int xx, yy, offset; |
299 | u16 *p; | 303 | u16 *p; |
300 | 304 | ||
301 | p = (u16 *) start; | 305 | p = (u16 *) start; |
302 | if (!vc->vc_sw->con_getxy) { | 306 | if (!vc->vc_sw->con_getxy) { |
303 | offset = (start - vc->vc_origin) / 2; | 307 | offset = (start - vc->vc_origin) / 2; |
304 | xx = offset % vc->vc_cols; | 308 | xx = offset % vc->vc_cols; |
305 | yy = offset / vc->vc_cols; | 309 | yy = offset / vc->vc_cols; |
306 | } else { | 310 | } else { |
307 | int nxx, nyy; | 311 | int nxx, nyy; |
308 | start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy); | 312 | start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy); |
309 | xx = nxx; yy = nyy; | 313 | xx = nxx; yy = nyy; |
310 | } | 314 | } |
311 | for(;;) { | 315 | for(;;) { |
312 | u16 attrib = scr_readw(p) & 0xff00; | 316 | u16 attrib = scr_readw(p) & 0xff00; |
313 | int startx = xx; | 317 | int startx = xx; |
314 | u16 *q = p; | 318 | u16 *q = p; |
315 | while (xx < vc->vc_cols && count) { | 319 | while (xx < vc->vc_cols && count) { |
316 | if (attrib != (scr_readw(p) & 0xff00)) { | 320 | if (attrib != (scr_readw(p) & 0xff00)) { |
317 | if (p > q) | 321 | if (p > q) |
318 | vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); | 322 | vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); |
319 | startx = xx; | 323 | startx = xx; |
320 | q = p; | 324 | q = p; |
321 | attrib = scr_readw(p) & 0xff00; | 325 | attrib = scr_readw(p) & 0xff00; |
322 | } | 326 | } |
323 | p++; | 327 | p++; |
324 | xx++; | 328 | xx++; |
325 | count--; | 329 | count--; |
326 | } | 330 | } |
327 | if (p > q) | 331 | if (p > q) |
328 | vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); | 332 | vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); |
329 | if (!count) | 333 | if (!count) |
330 | break; | 334 | break; |
331 | xx = 0; | 335 | xx = 0; |
332 | yy++; | 336 | yy++; |
333 | if (vc->vc_sw->con_getxy) { | 337 | if (vc->vc_sw->con_getxy) { |
334 | p = (u16 *)start; | 338 | p = (u16 *)start; |
335 | start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); | 339 | start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); |
336 | } | 340 | } |
337 | } | 341 | } |
338 | #endif | 342 | #endif |
339 | } | 343 | } |
340 | 344 | ||
341 | void update_region(struct vc_data *vc, unsigned long start, int count) | 345 | void update_region(struct vc_data *vc, unsigned long start, int count) |
342 | { | 346 | { |
343 | WARN_CONSOLE_UNLOCKED(); | 347 | WARN_CONSOLE_UNLOCKED(); |
344 | 348 | ||
345 | if (DO_UPDATE(vc)) { | 349 | if (DO_UPDATE(vc)) { |
346 | hide_cursor(vc); | 350 | hide_cursor(vc); |
347 | do_update_region(vc, start, count); | 351 | do_update_region(vc, start, count); |
348 | set_cursor(vc); | 352 | set_cursor(vc); |
349 | } | 353 | } |
350 | } | 354 | } |
351 | 355 | ||
352 | /* Structure of attributes is hardware-dependent */ | 356 | /* Structure of attributes is hardware-dependent */ |
353 | 357 | ||
354 | static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, | 358 | static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, |
355 | u8 _underline, u8 _reverse, u8 _italic) | 359 | u8 _underline, u8 _reverse, u8 _italic) |
356 | { | 360 | { |
357 | if (vc->vc_sw->con_build_attr) | 361 | if (vc->vc_sw->con_build_attr) |
358 | return vc->vc_sw->con_build_attr(vc, _color, _intensity, | 362 | return vc->vc_sw->con_build_attr(vc, _color, _intensity, |
359 | _blink, _underline, _reverse, _italic); | 363 | _blink, _underline, _reverse, _italic); |
360 | 364 | ||
361 | #ifndef VT_BUF_VRAM_ONLY | 365 | #ifndef VT_BUF_VRAM_ONLY |
362 | /* | 366 | /* |
363 | * ++roman: I completely changed the attribute format for monochrome | 367 | * ++roman: I completely changed the attribute format for monochrome |
364 | * mode (!can_do_color). The formerly used MDA (monochrome display | 368 | * mode (!can_do_color). The formerly used MDA (monochrome display |
365 | * adapter) format didn't allow the combination of certain effects. | 369 | * adapter) format didn't allow the combination of certain effects. |
366 | * Now the attribute is just a bit vector: | 370 | * Now the attribute is just a bit vector: |
367 | * Bit 0..1: intensity (0..2) | 371 | * Bit 0..1: intensity (0..2) |
368 | * Bit 2 : underline | 372 | * Bit 2 : underline |
369 | * Bit 3 : reverse | 373 | * Bit 3 : reverse |
370 | * Bit 7 : blink | 374 | * Bit 7 : blink |
371 | */ | 375 | */ |
372 | { | 376 | { |
373 | u8 a = vc->vc_color; | 377 | u8 a = vc->vc_color; |
374 | if (!vc->vc_can_do_color) | 378 | if (!vc->vc_can_do_color) |
375 | return _intensity | | 379 | return _intensity | |
376 | (_italic ? 2 : 0) | | 380 | (_italic ? 2 : 0) | |
377 | (_underline ? 4 : 0) | | 381 | (_underline ? 4 : 0) | |
378 | (_reverse ? 8 : 0) | | 382 | (_reverse ? 8 : 0) | |
379 | (_blink ? 0x80 : 0); | 383 | (_blink ? 0x80 : 0); |
380 | if (_italic) | 384 | if (_italic) |
381 | a = (a & 0xF0) | vc->vc_itcolor; | 385 | a = (a & 0xF0) | vc->vc_itcolor; |
382 | else if (_underline) | 386 | else if (_underline) |
383 | a = (a & 0xf0) | vc->vc_ulcolor; | 387 | a = (a & 0xf0) | vc->vc_ulcolor; |
384 | else if (_intensity == 0) | 388 | else if (_intensity == 0) |
385 | a = (a & 0xf0) | vc->vc_ulcolor; | 389 | a = (a & 0xf0) | vc->vc_ulcolor; |
386 | if (_reverse) | 390 | if (_reverse) |
387 | a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); | 391 | a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); |
388 | if (_blink) | 392 | if (_blink) |
389 | a ^= 0x80; | 393 | a ^= 0x80; |
390 | if (_intensity == 2) | 394 | if (_intensity == 2) |
391 | a ^= 0x08; | 395 | a ^= 0x08; |
392 | if (vc->vc_hi_font_mask == 0x100) | 396 | if (vc->vc_hi_font_mask == 0x100) |
393 | a <<= 1; | 397 | a <<= 1; |
394 | return a; | 398 | return a; |
395 | } | 399 | } |
396 | #else | 400 | #else |
397 | return 0; | 401 | return 0; |
398 | #endif | 402 | #endif |
399 | } | 403 | } |
400 | 404 | ||
401 | static void update_attr(struct vc_data *vc) | 405 | static void update_attr(struct vc_data *vc) |
402 | { | 406 | { |
403 | vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, | 407 | vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, |
404 | vc->vc_blink, vc->vc_underline, | 408 | vc->vc_blink, vc->vc_underline, |
405 | vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); | 409 | vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); |
406 | vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; | 410 | vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; |
407 | } | 411 | } |
408 | 412 | ||
409 | /* Note: inverting the screen twice should revert to the original state */ | 413 | /* Note: inverting the screen twice should revert to the original state */ |
410 | void invert_screen(struct vc_data *vc, int offset, int count, int viewed) | 414 | void invert_screen(struct vc_data *vc, int offset, int count, int viewed) |
411 | { | 415 | { |
412 | unsigned short *p; | 416 | unsigned short *p; |
413 | 417 | ||
414 | WARN_CONSOLE_UNLOCKED(); | 418 | WARN_CONSOLE_UNLOCKED(); |
415 | 419 | ||
416 | count /= 2; | 420 | count /= 2; |
417 | p = screenpos(vc, offset, viewed); | 421 | p = screenpos(vc, offset, viewed); |
418 | if (vc->vc_sw->con_invert_region) | 422 | if (vc->vc_sw->con_invert_region) |
419 | vc->vc_sw->con_invert_region(vc, p, count); | 423 | vc->vc_sw->con_invert_region(vc, p, count); |
420 | #ifndef VT_BUF_VRAM_ONLY | 424 | #ifndef VT_BUF_VRAM_ONLY |
421 | else { | 425 | else { |
422 | u16 *q = p; | 426 | u16 *q = p; |
423 | int cnt = count; | 427 | int cnt = count; |
424 | u16 a; | 428 | u16 a; |
425 | 429 | ||
426 | if (!vc->vc_can_do_color) { | 430 | if (!vc->vc_can_do_color) { |
427 | while (cnt--) { | 431 | while (cnt--) { |
428 | a = scr_readw(q); | 432 | a = scr_readw(q); |
429 | a ^= 0x0800; | 433 | a ^= 0x0800; |
430 | scr_writew(a, q); | 434 | scr_writew(a, q); |
431 | q++; | 435 | q++; |
432 | } | 436 | } |
433 | } else if (vc->vc_hi_font_mask == 0x100) { | 437 | } else if (vc->vc_hi_font_mask == 0x100) { |
434 | while (cnt--) { | 438 | while (cnt--) { |
435 | a = scr_readw(q); | 439 | a = scr_readw(q); |
436 | a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); | 440 | a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); |
437 | scr_writew(a, q); | 441 | scr_writew(a, q); |
438 | q++; | 442 | q++; |
439 | } | 443 | } |
440 | } else { | 444 | } else { |
441 | while (cnt--) { | 445 | while (cnt--) { |
442 | a = scr_readw(q); | 446 | a = scr_readw(q); |
443 | a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); | 447 | a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); |
444 | scr_writew(a, q); | 448 | scr_writew(a, q); |
445 | q++; | 449 | q++; |
446 | } | 450 | } |
447 | } | 451 | } |
448 | } | 452 | } |
449 | #endif | 453 | #endif |
450 | if (DO_UPDATE(vc)) | 454 | if (DO_UPDATE(vc)) |
451 | do_update_region(vc, (unsigned long) p, count); | 455 | do_update_region(vc, (unsigned long) p, count); |
452 | } | 456 | } |
453 | 457 | ||
454 | /* used by selection: complement pointer position */ | 458 | /* used by selection: complement pointer position */ |
455 | void complement_pos(struct vc_data *vc, int offset) | 459 | void complement_pos(struct vc_data *vc, int offset) |
456 | { | 460 | { |
457 | static int old_offset = -1; | 461 | static int old_offset = -1; |
458 | static unsigned short old; | 462 | static unsigned short old; |
459 | static unsigned short oldx, oldy; | 463 | static unsigned short oldx, oldy; |
460 | 464 | ||
461 | WARN_CONSOLE_UNLOCKED(); | 465 | WARN_CONSOLE_UNLOCKED(); |
462 | 466 | ||
463 | if (old_offset != -1 && old_offset >= 0 && | 467 | if (old_offset != -1 && old_offset >= 0 && |
464 | old_offset < vc->vc_screenbuf_size) { | 468 | old_offset < vc->vc_screenbuf_size) { |
465 | scr_writew(old, screenpos(vc, old_offset, 1)); | 469 | scr_writew(old, screenpos(vc, old_offset, 1)); |
466 | if (DO_UPDATE(vc)) | 470 | if (DO_UPDATE(vc)) |
467 | vc->vc_sw->con_putc(vc, old, oldy, oldx); | 471 | vc->vc_sw->con_putc(vc, old, oldy, oldx); |
468 | } | 472 | } |
469 | 473 | ||
470 | old_offset = offset; | 474 | old_offset = offset; |
471 | 475 | ||
472 | if (offset != -1 && offset >= 0 && | 476 | if (offset != -1 && offset >= 0 && |
473 | offset < vc->vc_screenbuf_size) { | 477 | offset < vc->vc_screenbuf_size) { |
474 | unsigned short new; | 478 | unsigned short new; |
475 | unsigned short *p; | 479 | unsigned short *p; |
476 | p = screenpos(vc, offset, 1); | 480 | p = screenpos(vc, offset, 1); |
477 | old = scr_readw(p); | 481 | old = scr_readw(p); |
478 | new = old ^ vc->vc_complement_mask; | 482 | new = old ^ vc->vc_complement_mask; |
479 | scr_writew(new, p); | 483 | scr_writew(new, p); |
480 | if (DO_UPDATE(vc)) { | 484 | if (DO_UPDATE(vc)) { |
481 | oldx = (offset >> 1) % vc->vc_cols; | 485 | oldx = (offset >> 1) % vc->vc_cols; |
482 | oldy = (offset >> 1) / vc->vc_cols; | 486 | oldy = (offset >> 1) / vc->vc_cols; |
483 | vc->vc_sw->con_putc(vc, new, oldy, oldx); | 487 | vc->vc_sw->con_putc(vc, new, oldy, oldx); |
484 | } | 488 | } |
485 | } | 489 | } |
486 | 490 | ||
487 | } | 491 | } |
488 | 492 | ||
489 | static void insert_char(struct vc_data *vc, unsigned int nr) | 493 | static void insert_char(struct vc_data *vc, unsigned int nr) |
490 | { | 494 | { |
491 | unsigned short *p, *q = (unsigned short *)vc->vc_pos; | 495 | unsigned short *p, *q = (unsigned short *)vc->vc_pos; |
492 | 496 | ||
493 | p = q + vc->vc_cols - nr - vc->vc_x; | 497 | p = q + vc->vc_cols - nr - vc->vc_x; |
494 | while (--p >= q) | 498 | while (--p >= q) |
495 | scr_writew(scr_readw(p), p + nr); | 499 | scr_writew(scr_readw(p), p + nr); |
496 | scr_memsetw(q, vc->vc_video_erase_char, nr * 2); | 500 | scr_memsetw(q, vc->vc_video_erase_char, nr * 2); |
497 | vc->vc_need_wrap = 0; | 501 | vc->vc_need_wrap = 0; |
498 | if (DO_UPDATE(vc)) { | 502 | if (DO_UPDATE(vc)) { |
499 | unsigned short oldattr = vc->vc_attr; | 503 | unsigned short oldattr = vc->vc_attr; |
500 | vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1, | 504 | vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1, |
501 | vc->vc_cols - vc->vc_x - nr); | 505 | vc->vc_cols - vc->vc_x - nr); |
502 | vc->vc_attr = vc->vc_video_erase_char >> 8; | 506 | vc->vc_attr = vc->vc_video_erase_char >> 8; |
503 | while (nr--) | 507 | while (nr--) |
504 | vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr); | 508 | vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr); |
505 | vc->vc_attr = oldattr; | 509 | vc->vc_attr = oldattr; |
506 | } | 510 | } |
507 | } | 511 | } |
508 | 512 | ||
509 | static void delete_char(struct vc_data *vc, unsigned int nr) | 513 | static void delete_char(struct vc_data *vc, unsigned int nr) |
510 | { | 514 | { |
511 | unsigned int i = vc->vc_x; | 515 | unsigned int i = vc->vc_x; |
512 | unsigned short *p = (unsigned short *)vc->vc_pos; | 516 | unsigned short *p = (unsigned short *)vc->vc_pos; |
513 | 517 | ||
514 | while (++i <= vc->vc_cols - nr) { | 518 | while (++i <= vc->vc_cols - nr) { |
515 | scr_writew(scr_readw(p+nr), p); | 519 | scr_writew(scr_readw(p+nr), p); |
516 | p++; | 520 | p++; |
517 | } | 521 | } |
518 | scr_memsetw(p, vc->vc_video_erase_char, nr * 2); | 522 | scr_memsetw(p, vc->vc_video_erase_char, nr * 2); |
519 | vc->vc_need_wrap = 0; | 523 | vc->vc_need_wrap = 0; |
520 | if (DO_UPDATE(vc)) { | 524 | if (DO_UPDATE(vc)) { |
521 | unsigned short oldattr = vc->vc_attr; | 525 | unsigned short oldattr = vc->vc_attr; |
522 | vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1, | 526 | vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1, |
523 | vc->vc_cols - vc->vc_x - nr); | 527 | vc->vc_cols - vc->vc_x - nr); |
524 | vc->vc_attr = vc->vc_video_erase_char >> 8; | 528 | vc->vc_attr = vc->vc_video_erase_char >> 8; |
525 | while (nr--) | 529 | while (nr--) |
526 | vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, | 530 | vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, |
527 | vc->vc_cols - 1 - nr); | 531 | vc->vc_cols - 1 - nr); |
528 | vc->vc_attr = oldattr; | 532 | vc->vc_attr = oldattr; |
529 | } | 533 | } |
530 | } | 534 | } |
531 | 535 | ||
532 | static int softcursor_original; | 536 | static int softcursor_original; |
533 | 537 | ||
534 | static void add_softcursor(struct vc_data *vc) | 538 | static void add_softcursor(struct vc_data *vc) |
535 | { | 539 | { |
536 | int i = scr_readw((u16 *) vc->vc_pos); | 540 | int i = scr_readw((u16 *) vc->vc_pos); |
537 | u32 type = vc->vc_cursor_type; | 541 | u32 type = vc->vc_cursor_type; |
538 | 542 | ||
539 | if (! (type & 0x10)) return; | 543 | if (! (type & 0x10)) return; |
540 | if (softcursor_original != -1) return; | 544 | if (softcursor_original != -1) return; |
541 | softcursor_original = i; | 545 | softcursor_original = i; |
542 | i |= ((type >> 8) & 0xff00 ); | 546 | i |= ((type >> 8) & 0xff00 ); |
543 | i ^= ((type) & 0xff00 ); | 547 | i ^= ((type) & 0xff00 ); |
544 | if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; | 548 | if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; |
545 | if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; | 549 | if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; |
546 | scr_writew(i, (u16 *) vc->vc_pos); | 550 | scr_writew(i, (u16 *) vc->vc_pos); |
547 | if (DO_UPDATE(vc)) | 551 | if (DO_UPDATE(vc)) |
548 | vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x); | 552 | vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x); |
549 | } | 553 | } |
550 | 554 | ||
551 | static void hide_softcursor(struct vc_data *vc) | 555 | static void hide_softcursor(struct vc_data *vc) |
552 | { | 556 | { |
553 | if (softcursor_original != -1) { | 557 | if (softcursor_original != -1) { |
554 | scr_writew(softcursor_original, (u16 *)vc->vc_pos); | 558 | scr_writew(softcursor_original, (u16 *)vc->vc_pos); |
555 | if (DO_UPDATE(vc)) | 559 | if (DO_UPDATE(vc)) |
556 | vc->vc_sw->con_putc(vc, softcursor_original, | 560 | vc->vc_sw->con_putc(vc, softcursor_original, |
557 | vc->vc_y, vc->vc_x); | 561 | vc->vc_y, vc->vc_x); |
558 | softcursor_original = -1; | 562 | softcursor_original = -1; |
559 | } | 563 | } |
560 | } | 564 | } |
561 | 565 | ||
562 | static void hide_cursor(struct vc_data *vc) | 566 | static void hide_cursor(struct vc_data *vc) |
563 | { | 567 | { |
564 | if (vc == sel_cons) | 568 | if (vc == sel_cons) |
565 | clear_selection(); | 569 | clear_selection(); |
566 | vc->vc_sw->con_cursor(vc, CM_ERASE); | 570 | vc->vc_sw->con_cursor(vc, CM_ERASE); |
567 | hide_softcursor(vc); | 571 | hide_softcursor(vc); |
568 | } | 572 | } |
569 | 573 | ||
570 | static void set_cursor(struct vc_data *vc) | 574 | static void set_cursor(struct vc_data *vc) |
571 | { | 575 | { |
572 | if (!IS_FG(vc) || console_blanked || | 576 | if (!IS_FG(vc) || console_blanked || |
573 | vc->vc_mode == KD_GRAPHICS) | 577 | vc->vc_mode == KD_GRAPHICS) |
574 | return; | 578 | return; |
575 | if (vc->vc_deccm) { | 579 | if (vc->vc_deccm) { |
576 | if (vc == sel_cons) | 580 | if (vc == sel_cons) |
577 | clear_selection(); | 581 | clear_selection(); |
578 | add_softcursor(vc); | 582 | add_softcursor(vc); |
579 | if ((vc->vc_cursor_type & 0x0f) != 1) | 583 | if ((vc->vc_cursor_type & 0x0f) != 1) |
580 | vc->vc_sw->con_cursor(vc, CM_DRAW); | 584 | vc->vc_sw->con_cursor(vc, CM_DRAW); |
581 | } else | 585 | } else |
582 | hide_cursor(vc); | 586 | hide_cursor(vc); |
583 | } | 587 | } |
584 | 588 | ||
585 | static void set_origin(struct vc_data *vc) | 589 | static void set_origin(struct vc_data *vc) |
586 | { | 590 | { |
587 | WARN_CONSOLE_UNLOCKED(); | 591 | WARN_CONSOLE_UNLOCKED(); |
588 | 592 | ||
589 | if (!CON_IS_VISIBLE(vc) || | 593 | if (!CON_IS_VISIBLE(vc) || |
590 | !vc->vc_sw->con_set_origin || | 594 | !vc->vc_sw->con_set_origin || |
591 | !vc->vc_sw->con_set_origin(vc)) | 595 | !vc->vc_sw->con_set_origin(vc)) |
592 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; | 596 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; |
593 | vc->vc_visible_origin = vc->vc_origin; | 597 | vc->vc_visible_origin = vc->vc_origin; |
594 | vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size; | 598 | vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size; |
595 | vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x; | 599 | vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x; |
596 | } | 600 | } |
597 | 601 | ||
598 | static inline void save_screen(struct vc_data *vc) | 602 | static inline void save_screen(struct vc_data *vc) |
599 | { | 603 | { |
600 | WARN_CONSOLE_UNLOCKED(); | 604 | WARN_CONSOLE_UNLOCKED(); |
601 | 605 | ||
602 | if (vc->vc_sw->con_save_screen) | 606 | if (vc->vc_sw->con_save_screen) |
603 | vc->vc_sw->con_save_screen(vc); | 607 | vc->vc_sw->con_save_screen(vc); |
604 | } | 608 | } |
605 | 609 | ||
606 | /* | 610 | /* |
607 | * Redrawing of screen | 611 | * Redrawing of screen |
608 | */ | 612 | */ |
609 | 613 | ||
610 | static void clear_buffer_attributes(struct vc_data *vc) | 614 | static void clear_buffer_attributes(struct vc_data *vc) |
611 | { | 615 | { |
612 | unsigned short *p = (unsigned short *)vc->vc_origin; | 616 | unsigned short *p = (unsigned short *)vc->vc_origin; |
613 | int count = vc->vc_screenbuf_size / 2; | 617 | int count = vc->vc_screenbuf_size / 2; |
614 | int mask = vc->vc_hi_font_mask | 0xff; | 618 | int mask = vc->vc_hi_font_mask | 0xff; |
615 | 619 | ||
616 | for (; count > 0; count--, p++) { | 620 | for (; count > 0; count--, p++) { |
617 | scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p); | 621 | scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p); |
618 | } | 622 | } |
619 | } | 623 | } |
620 | 624 | ||
621 | void redraw_screen(struct vc_data *vc, int is_switch) | 625 | void redraw_screen(struct vc_data *vc, int is_switch) |
622 | { | 626 | { |
623 | int redraw = 0; | 627 | int redraw = 0; |
624 | 628 | ||
625 | WARN_CONSOLE_UNLOCKED(); | 629 | WARN_CONSOLE_UNLOCKED(); |
626 | 630 | ||
627 | if (!vc) { | 631 | if (!vc) { |
628 | /* strange ... */ | 632 | /* strange ... */ |
629 | /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */ | 633 | /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */ |
630 | return; | 634 | return; |
631 | } | 635 | } |
632 | 636 | ||
633 | if (is_switch) { | 637 | if (is_switch) { |
634 | struct vc_data *old_vc = vc_cons[fg_console].d; | 638 | struct vc_data *old_vc = vc_cons[fg_console].d; |
635 | if (old_vc == vc) | 639 | if (old_vc == vc) |
636 | return; | 640 | return; |
637 | if (!CON_IS_VISIBLE(vc)) | 641 | if (!CON_IS_VISIBLE(vc)) |
638 | redraw = 1; | 642 | redraw = 1; |
639 | *vc->vc_display_fg = vc; | 643 | *vc->vc_display_fg = vc; |
640 | fg_console = vc->vc_num; | 644 | fg_console = vc->vc_num; |
641 | hide_cursor(old_vc); | 645 | hide_cursor(old_vc); |
642 | if (!CON_IS_VISIBLE(old_vc)) { | 646 | if (!CON_IS_VISIBLE(old_vc)) { |
643 | save_screen(old_vc); | 647 | save_screen(old_vc); |
644 | set_origin(old_vc); | 648 | set_origin(old_vc); |
645 | } | 649 | } |
646 | } else { | 650 | } else { |
647 | hide_cursor(vc); | 651 | hide_cursor(vc); |
648 | redraw = 1; | 652 | redraw = 1; |
649 | } | 653 | } |
650 | 654 | ||
651 | if (redraw) { | 655 | if (redraw) { |
652 | int update; | 656 | int update; |
653 | int old_was_color = vc->vc_can_do_color; | 657 | int old_was_color = vc->vc_can_do_color; |
654 | 658 | ||
655 | set_origin(vc); | 659 | set_origin(vc); |
656 | update = vc->vc_sw->con_switch(vc); | 660 | update = vc->vc_sw->con_switch(vc); |
657 | set_palette(vc); | 661 | set_palette(vc); |
658 | /* | 662 | /* |
659 | * If console changed from mono<->color, the best we can do | 663 | * If console changed from mono<->color, the best we can do |
660 | * is to clear the buffer attributes. As it currently stands, | 664 | * is to clear the buffer attributes. As it currently stands, |
661 | * rebuilding new attributes from the old buffer is not doable | 665 | * rebuilding new attributes from the old buffer is not doable |
662 | * without overly complex code. | 666 | * without overly complex code. |
663 | */ | 667 | */ |
664 | if (old_was_color != vc->vc_can_do_color) { | 668 | if (old_was_color != vc->vc_can_do_color) { |
665 | update_attr(vc); | 669 | update_attr(vc); |
666 | clear_buffer_attributes(vc); | 670 | clear_buffer_attributes(vc); |
667 | } | 671 | } |
668 | if (update && vc->vc_mode != KD_GRAPHICS) | 672 | if (update && vc->vc_mode != KD_GRAPHICS) |
669 | do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); | 673 | do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); |
670 | } | 674 | } |
671 | set_cursor(vc); | 675 | set_cursor(vc); |
672 | if (is_switch) { | 676 | if (is_switch) { |
673 | set_leds(); | 677 | set_leds(); |
674 | compute_shiftstate(); | 678 | compute_shiftstate(); |
675 | } | 679 | } |
676 | } | 680 | } |
677 | 681 | ||
678 | /* | 682 | /* |
679 | * Allocation, freeing and resizing of VTs. | 683 | * Allocation, freeing and resizing of VTs. |
680 | */ | 684 | */ |
681 | 685 | ||
682 | int vc_cons_allocated(unsigned int i) | 686 | int vc_cons_allocated(unsigned int i) |
683 | { | 687 | { |
684 | return (i < MAX_NR_CONSOLES && vc_cons[i].d); | 688 | return (i < MAX_NR_CONSOLES && vc_cons[i].d); |
685 | } | 689 | } |
686 | 690 | ||
687 | static void visual_init(struct vc_data *vc, int num, int init) | 691 | static void visual_init(struct vc_data *vc, int num, int init) |
688 | { | 692 | { |
689 | /* ++Geert: vc->vc_sw->con_init determines console size */ | 693 | /* ++Geert: vc->vc_sw->con_init determines console size */ |
690 | if (vc->vc_sw) | 694 | if (vc->vc_sw) |
691 | module_put(vc->vc_sw->owner); | 695 | module_put(vc->vc_sw->owner); |
692 | vc->vc_sw = conswitchp; | 696 | vc->vc_sw = conswitchp; |
693 | #ifndef VT_SINGLE_DRIVER | 697 | #ifndef VT_SINGLE_DRIVER |
694 | if (con_driver_map[num]) | 698 | if (con_driver_map[num]) |
695 | vc->vc_sw = con_driver_map[num]; | 699 | vc->vc_sw = con_driver_map[num]; |
696 | #endif | 700 | #endif |
697 | __module_get(vc->vc_sw->owner); | 701 | __module_get(vc->vc_sw->owner); |
698 | vc->vc_num = num; | 702 | vc->vc_num = num; |
699 | vc->vc_display_fg = &master_display_fg; | 703 | vc->vc_display_fg = &master_display_fg; |
700 | vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; | 704 | vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; |
701 | vc->vc_uni_pagedir = 0; | 705 | vc->vc_uni_pagedir = 0; |
702 | vc->vc_hi_font_mask = 0; | 706 | vc->vc_hi_font_mask = 0; |
703 | vc->vc_complement_mask = 0; | 707 | vc->vc_complement_mask = 0; |
704 | vc->vc_can_do_color = 0; | 708 | vc->vc_can_do_color = 0; |
705 | vc->vc_sw->con_init(vc, init); | 709 | vc->vc_sw->con_init(vc, init); |
706 | if (!vc->vc_complement_mask) | 710 | if (!vc->vc_complement_mask) |
707 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; | 711 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
708 | vc->vc_s_complement_mask = vc->vc_complement_mask; | 712 | vc->vc_s_complement_mask = vc->vc_complement_mask; |
709 | vc->vc_size_row = vc->vc_cols << 1; | 713 | vc->vc_size_row = vc->vc_cols << 1; |
710 | vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row; | 714 | vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row; |
711 | } | 715 | } |
712 | 716 | ||
713 | int vc_allocate(unsigned int currcons) /* return 0 on success */ | 717 | int vc_allocate(unsigned int currcons) /* return 0 on success */ |
714 | { | 718 | { |
715 | WARN_CONSOLE_UNLOCKED(); | 719 | WARN_CONSOLE_UNLOCKED(); |
716 | 720 | ||
717 | if (currcons >= MAX_NR_CONSOLES) | 721 | if (currcons >= MAX_NR_CONSOLES) |
718 | return -ENXIO; | 722 | return -ENXIO; |
719 | if (!vc_cons[currcons].d) { | 723 | if (!vc_cons[currcons].d) { |
720 | struct vc_data *vc; | 724 | struct vc_data *vc; |
721 | 725 | ||
722 | /* prevent users from taking too much memory */ | 726 | /* prevent users from taking too much memory */ |
723 | if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) | 727 | if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) |
724 | return -EPERM; | 728 | return -EPERM; |
725 | 729 | ||
726 | /* due to the granularity of kmalloc, we waste some memory here */ | 730 | /* due to the granularity of kmalloc, we waste some memory here */ |
727 | /* the alloc is done in two steps, to optimize the common situation | 731 | /* the alloc is done in two steps, to optimize the common situation |
728 | of a 25x80 console (structsize=216, screenbuf_size=4000) */ | 732 | of a 25x80 console (structsize=216, screenbuf_size=4000) */ |
729 | /* although the numbers above are not valid since long ago, the | 733 | /* although the numbers above are not valid since long ago, the |
730 | point is still up-to-date and the comment still has its value | 734 | point is still up-to-date and the comment still has its value |
731 | even if only as a historical artifact. --mj, July 1998 */ | 735 | even if only as a historical artifact. --mj, July 1998 */ |
732 | vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL); | 736 | vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL); |
733 | if (!vc) | 737 | if (!vc) |
734 | return -ENOMEM; | 738 | return -ENOMEM; |
735 | vc_cons[currcons].d = vc; | 739 | vc_cons[currcons].d = vc; |
736 | INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); | 740 | INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); |
737 | visual_init(vc, currcons, 1); | 741 | visual_init(vc, currcons, 1); |
738 | if (!*vc->vc_uni_pagedir_loc) | 742 | if (!*vc->vc_uni_pagedir_loc) |
739 | con_set_default_unimap(vc); | 743 | con_set_default_unimap(vc); |
740 | if (!vc->vc_kmalloced) | 744 | if (!vc->vc_kmalloced) |
741 | vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); | 745 | vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); |
742 | if (!vc->vc_screenbuf) { | 746 | if (!vc->vc_screenbuf) { |
743 | kfree(vc); | 747 | kfree(vc); |
744 | vc_cons[currcons].d = NULL; | 748 | vc_cons[currcons].d = NULL; |
745 | return -ENOMEM; | 749 | return -ENOMEM; |
746 | } | 750 | } |
747 | vc->vc_kmalloced = 1; | 751 | vc->vc_kmalloced = 1; |
748 | vc_init(vc, vc->vc_rows, vc->vc_cols, 1); | 752 | vc_init(vc, vc->vc_rows, vc->vc_cols, 1); |
749 | } | 753 | } |
750 | return 0; | 754 | return 0; |
751 | } | 755 | } |
752 | 756 | ||
753 | static inline int resize_screen(struct vc_data *vc, int width, int height, | 757 | static inline int resize_screen(struct vc_data *vc, int width, int height, |
754 | int user) | 758 | int user) |
755 | { | 759 | { |
756 | /* Resizes the resolution of the display adapater */ | 760 | /* Resizes the resolution of the display adapater */ |
757 | int err = 0; | 761 | int err = 0; |
758 | 762 | ||
759 | if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) | 763 | if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) |
760 | err = vc->vc_sw->con_resize(vc, width, height, user); | 764 | err = vc->vc_sw->con_resize(vc, width, height, user); |
761 | 765 | ||
762 | return err; | 766 | return err; |
763 | } | 767 | } |
764 | 768 | ||
765 | /* | 769 | /* |
766 | * Change # of rows and columns (0 means unchanged/the size of fg_console) | 770 | * Change # of rows and columns (0 means unchanged/the size of fg_console) |
767 | * [this is to be used together with some user program | 771 | * [this is to be used together with some user program |
768 | * like resize that changes the hardware videomode] | 772 | * like resize that changes the hardware videomode] |
769 | */ | 773 | */ |
770 | #define VC_RESIZE_MAXCOL (32767) | 774 | #define VC_RESIZE_MAXCOL (32767) |
771 | #define VC_RESIZE_MAXROW (32767) | 775 | #define VC_RESIZE_MAXROW (32767) |
772 | int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | 776 | int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) |
773 | { | 777 | { |
774 | unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; | 778 | unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; |
775 | unsigned int old_cols, old_rows, old_row_size, old_screen_size; | 779 | unsigned int old_cols, old_rows, old_row_size, old_screen_size; |
776 | unsigned int new_cols, new_rows, new_row_size, new_screen_size; | 780 | unsigned int new_cols, new_rows, new_row_size, new_screen_size; |
777 | unsigned int end, user; | 781 | unsigned int end, user; |
778 | unsigned short *newscreen; | 782 | unsigned short *newscreen; |
779 | 783 | ||
780 | WARN_CONSOLE_UNLOCKED(); | 784 | WARN_CONSOLE_UNLOCKED(); |
781 | 785 | ||
782 | if (!vc) | 786 | if (!vc) |
783 | return -ENXIO; | 787 | return -ENXIO; |
784 | 788 | ||
785 | user = vc->vc_resize_user; | 789 | user = vc->vc_resize_user; |
786 | vc->vc_resize_user = 0; | 790 | vc->vc_resize_user = 0; |
787 | 791 | ||
788 | if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) | 792 | if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) |
789 | return -EINVAL; | 793 | return -EINVAL; |
790 | 794 | ||
791 | new_cols = (cols ? cols : vc->vc_cols); | 795 | new_cols = (cols ? cols : vc->vc_cols); |
792 | new_rows = (lines ? lines : vc->vc_rows); | 796 | new_rows = (lines ? lines : vc->vc_rows); |
793 | new_row_size = new_cols << 1; | 797 | new_row_size = new_cols << 1; |
794 | new_screen_size = new_row_size * new_rows; | 798 | new_screen_size = new_row_size * new_rows; |
795 | 799 | ||
796 | if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) | 800 | if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) |
797 | return 0; | 801 | return 0; |
798 | 802 | ||
799 | newscreen = kmalloc(new_screen_size, GFP_USER); | 803 | newscreen = kmalloc(new_screen_size, GFP_USER); |
800 | if (!newscreen) | 804 | if (!newscreen) |
801 | return -ENOMEM; | 805 | return -ENOMEM; |
802 | 806 | ||
803 | old_rows = vc->vc_rows; | 807 | old_rows = vc->vc_rows; |
804 | old_cols = vc->vc_cols; | 808 | old_cols = vc->vc_cols; |
805 | old_row_size = vc->vc_size_row; | 809 | old_row_size = vc->vc_size_row; |
806 | old_screen_size = vc->vc_screenbuf_size; | 810 | old_screen_size = vc->vc_screenbuf_size; |
807 | 811 | ||
808 | err = resize_screen(vc, new_cols, new_rows, user); | 812 | err = resize_screen(vc, new_cols, new_rows, user); |
809 | if (err) { | 813 | if (err) { |
810 | kfree(newscreen); | 814 | kfree(newscreen); |
811 | return err; | 815 | return err; |
812 | } | 816 | } |
813 | 817 | ||
814 | vc->vc_rows = new_rows; | 818 | vc->vc_rows = new_rows; |
815 | vc->vc_cols = new_cols; | 819 | vc->vc_cols = new_cols; |
816 | vc->vc_size_row = new_row_size; | 820 | vc->vc_size_row = new_row_size; |
817 | vc->vc_screenbuf_size = new_screen_size; | 821 | vc->vc_screenbuf_size = new_screen_size; |
818 | 822 | ||
819 | rlth = min(old_row_size, new_row_size); | 823 | rlth = min(old_row_size, new_row_size); |
820 | rrem = new_row_size - rlth; | 824 | rrem = new_row_size - rlth; |
821 | old_origin = vc->vc_origin; | 825 | old_origin = vc->vc_origin; |
822 | new_origin = (long) newscreen; | 826 | new_origin = (long) newscreen; |
823 | new_scr_end = new_origin + new_screen_size; | 827 | new_scr_end = new_origin + new_screen_size; |
824 | 828 | ||
825 | if (vc->vc_y > new_rows) { | 829 | if (vc->vc_y > new_rows) { |
826 | if (old_rows - vc->vc_y < new_rows) { | 830 | if (old_rows - vc->vc_y < new_rows) { |
827 | /* | 831 | /* |
828 | * Cursor near the bottom, copy contents from the | 832 | * Cursor near the bottom, copy contents from the |
829 | * bottom of buffer | 833 | * bottom of buffer |
830 | */ | 834 | */ |
831 | old_origin += (old_rows - new_rows) * old_row_size; | 835 | old_origin += (old_rows - new_rows) * old_row_size; |
832 | end = vc->vc_scr_end; | 836 | end = vc->vc_scr_end; |
833 | } else { | 837 | } else { |
834 | /* | 838 | /* |
835 | * Cursor is in no man's land, copy 1/2 screenful | 839 | * Cursor is in no man's land, copy 1/2 screenful |
836 | * from the top and bottom of cursor position | 840 | * from the top and bottom of cursor position |
837 | */ | 841 | */ |
838 | old_origin += (vc->vc_y - new_rows/2) * old_row_size; | 842 | old_origin += (vc->vc_y - new_rows/2) * old_row_size; |
839 | end = old_origin + (old_row_size * new_rows); | 843 | end = old_origin + (old_row_size * new_rows); |
840 | } | 844 | } |
841 | } else | 845 | } else |
842 | /* | 846 | /* |
843 | * Cursor near the top, copy contents from the top of buffer | 847 | * Cursor near the top, copy contents from the top of buffer |
844 | */ | 848 | */ |
845 | end = (old_rows > new_rows) ? old_origin + | 849 | end = (old_rows > new_rows) ? old_origin + |
846 | (old_row_size * new_rows) : | 850 | (old_row_size * new_rows) : |
847 | vc->vc_scr_end; | 851 | vc->vc_scr_end; |
848 | 852 | ||
849 | update_attr(vc); | 853 | update_attr(vc); |
850 | 854 | ||
851 | while (old_origin < end) { | 855 | while (old_origin < end) { |
852 | scr_memcpyw((unsigned short *) new_origin, | 856 | scr_memcpyw((unsigned short *) new_origin, |
853 | (unsigned short *) old_origin, rlth); | 857 | (unsigned short *) old_origin, rlth); |
854 | if (rrem) | 858 | if (rrem) |
855 | scr_memsetw((void *)(new_origin + rlth), | 859 | scr_memsetw((void *)(new_origin + rlth), |
856 | vc->vc_video_erase_char, rrem); | 860 | vc->vc_video_erase_char, rrem); |
857 | old_origin += old_row_size; | 861 | old_origin += old_row_size; |
858 | new_origin += new_row_size; | 862 | new_origin += new_row_size; |
859 | } | 863 | } |
860 | if (new_scr_end > new_origin) | 864 | if (new_scr_end > new_origin) |
861 | scr_memsetw((void *)new_origin, vc->vc_video_erase_char, | 865 | scr_memsetw((void *)new_origin, vc->vc_video_erase_char, |
862 | new_scr_end - new_origin); | 866 | new_scr_end - new_origin); |
863 | if (vc->vc_kmalloced) | 867 | if (vc->vc_kmalloced) |
864 | kfree(vc->vc_screenbuf); | 868 | kfree(vc->vc_screenbuf); |
865 | vc->vc_screenbuf = newscreen; | 869 | vc->vc_screenbuf = newscreen; |
866 | vc->vc_kmalloced = 1; | 870 | vc->vc_kmalloced = 1; |
867 | vc->vc_screenbuf_size = new_screen_size; | 871 | vc->vc_screenbuf_size = new_screen_size; |
868 | set_origin(vc); | 872 | set_origin(vc); |
869 | 873 | ||
870 | /* do part of a reset_terminal() */ | 874 | /* do part of a reset_terminal() */ |
871 | vc->vc_top = 0; | 875 | vc->vc_top = 0; |
872 | vc->vc_bottom = vc->vc_rows; | 876 | vc->vc_bottom = vc->vc_rows; |
873 | gotoxy(vc, vc->vc_x, vc->vc_y); | 877 | gotoxy(vc, vc->vc_x, vc->vc_y); |
874 | save_cur(vc); | 878 | save_cur(vc); |
875 | 879 | ||
876 | if (vc->vc_tty) { | 880 | if (vc->vc_tty) { |
877 | struct winsize ws, *cws = &vc->vc_tty->winsize; | 881 | struct winsize ws, *cws = &vc->vc_tty->winsize; |
878 | 882 | ||
879 | memset(&ws, 0, sizeof(ws)); | 883 | memset(&ws, 0, sizeof(ws)); |
880 | ws.ws_row = vc->vc_rows; | 884 | ws.ws_row = vc->vc_rows; |
881 | ws.ws_col = vc->vc_cols; | 885 | ws.ws_col = vc->vc_cols; |
882 | ws.ws_ypixel = vc->vc_scan_lines; | 886 | ws.ws_ypixel = vc->vc_scan_lines; |
883 | if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && | 887 | if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && |
884 | vc->vc_tty->pgrp) | 888 | vc->vc_tty->pgrp) |
885 | kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1); | 889 | kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1); |
886 | *cws = ws; | 890 | *cws = ws; |
887 | } | 891 | } |
888 | 892 | ||
889 | if (CON_IS_VISIBLE(vc)) | 893 | if (CON_IS_VISIBLE(vc)) |
890 | update_screen(vc); | 894 | update_screen(vc); |
891 | return err; | 895 | return err; |
892 | } | 896 | } |
893 | 897 | ||
894 | int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | 898 | int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) |
895 | { | 899 | { |
896 | int rc; | 900 | int rc; |
897 | 901 | ||
898 | acquire_console_sem(); | 902 | acquire_console_sem(); |
899 | rc = vc_resize(vc, cols, lines); | 903 | rc = vc_resize(vc, cols, lines); |
900 | release_console_sem(); | 904 | release_console_sem(); |
901 | return rc; | 905 | return rc; |
902 | } | 906 | } |
903 | 907 | ||
904 | void vc_deallocate(unsigned int currcons) | 908 | void vc_deallocate(unsigned int currcons) |
905 | { | 909 | { |
906 | WARN_CONSOLE_UNLOCKED(); | 910 | WARN_CONSOLE_UNLOCKED(); |
907 | 911 | ||
908 | if (vc_cons_allocated(currcons)) { | 912 | if (vc_cons_allocated(currcons)) { |
909 | struct vc_data *vc = vc_cons[currcons].d; | 913 | struct vc_data *vc = vc_cons[currcons].d; |
910 | vc->vc_sw->con_deinit(vc); | 914 | vc->vc_sw->con_deinit(vc); |
911 | put_pid(vc->vt_pid); | 915 | put_pid(vc->vt_pid); |
912 | module_put(vc->vc_sw->owner); | 916 | module_put(vc->vc_sw->owner); |
913 | if (vc->vc_kmalloced) | 917 | if (vc->vc_kmalloced) |
914 | kfree(vc->vc_screenbuf); | 918 | kfree(vc->vc_screenbuf); |
915 | if (currcons >= MIN_NR_CONSOLES) | 919 | if (currcons >= MIN_NR_CONSOLES) |
916 | kfree(vc); | 920 | kfree(vc); |
917 | vc_cons[currcons].d = NULL; | 921 | vc_cons[currcons].d = NULL; |
918 | } | 922 | } |
919 | } | 923 | } |
920 | 924 | ||
921 | /* | 925 | /* |
922 | * VT102 emulator | 926 | * VT102 emulator |
923 | */ | 927 | */ |
924 | 928 | ||
925 | #define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) | 929 | #define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) |
926 | #define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) | 930 | #define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) |
927 | #define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) | 931 | #define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) |
928 | 932 | ||
929 | #define decarm VC_REPEAT | 933 | #define decarm VC_REPEAT |
930 | #define decckm VC_CKMODE | 934 | #define decckm VC_CKMODE |
931 | #define kbdapplic VC_APPLIC | 935 | #define kbdapplic VC_APPLIC |
932 | #define lnm VC_CRLF | 936 | #define lnm VC_CRLF |
933 | 937 | ||
934 | /* | 938 | /* |
935 | * this is what the terminal answers to a ESC-Z or csi0c query. | 939 | * this is what the terminal answers to a ESC-Z or csi0c query. |
936 | */ | 940 | */ |
937 | #define VT100ID "\033[?1;2c" | 941 | #define VT100ID "\033[?1;2c" |
938 | #define VT102ID "\033[?6c" | 942 | #define VT102ID "\033[?6c" |
939 | 943 | ||
940 | unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, | 944 | unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, |
941 | 8,12,10,14, 9,13,11,15 }; | 945 | 8,12,10,14, 9,13,11,15 }; |
942 | 946 | ||
943 | /* the default colour table, for VGA+ colour systems */ | 947 | /* the default colour table, for VGA+ colour systems */ |
944 | int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, | 948 | int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, |
945 | 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; | 949 | 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; |
946 | int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, | 950 | int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, |
947 | 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; | 951 | 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; |
948 | int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, | 952 | int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, |
949 | 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; | 953 | 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; |
950 | 954 | ||
951 | module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR); | 955 | module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR); |
952 | module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR); | 956 | module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR); |
953 | module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR); | 957 | module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR); |
954 | 958 | ||
955 | /* | 959 | /* |
956 | * gotoxy() must verify all boundaries, because the arguments | 960 | * gotoxy() must verify all boundaries, because the arguments |
957 | * might also be negative. If the given position is out of | 961 | * might also be negative. If the given position is out of |
958 | * bounds, the cursor is placed at the nearest margin. | 962 | * bounds, the cursor is placed at the nearest margin. |
959 | */ | 963 | */ |
960 | static void gotoxy(struct vc_data *vc, int new_x, int new_y) | 964 | static void gotoxy(struct vc_data *vc, int new_x, int new_y) |
961 | { | 965 | { |
962 | int min_y, max_y; | 966 | int min_y, max_y; |
963 | 967 | ||
964 | if (new_x < 0) | 968 | if (new_x < 0) |
965 | vc->vc_x = 0; | 969 | vc->vc_x = 0; |
966 | else { | 970 | else { |
967 | if (new_x >= vc->vc_cols) | 971 | if (new_x >= vc->vc_cols) |
968 | vc->vc_x = vc->vc_cols - 1; | 972 | vc->vc_x = vc->vc_cols - 1; |
969 | else | 973 | else |
970 | vc->vc_x = new_x; | 974 | vc->vc_x = new_x; |
971 | } | 975 | } |
972 | 976 | ||
973 | if (vc->vc_decom) { | 977 | if (vc->vc_decom) { |
974 | min_y = vc->vc_top; | 978 | min_y = vc->vc_top; |
975 | max_y = vc->vc_bottom; | 979 | max_y = vc->vc_bottom; |
976 | } else { | 980 | } else { |
977 | min_y = 0; | 981 | min_y = 0; |
978 | max_y = vc->vc_rows; | 982 | max_y = vc->vc_rows; |
979 | } | 983 | } |
980 | if (new_y < min_y) | 984 | if (new_y < min_y) |
981 | vc->vc_y = min_y; | 985 | vc->vc_y = min_y; |
982 | else if (new_y >= max_y) | 986 | else if (new_y >= max_y) |
983 | vc->vc_y = max_y - 1; | 987 | vc->vc_y = max_y - 1; |
984 | else | 988 | else |
985 | vc->vc_y = new_y; | 989 | vc->vc_y = new_y; |
986 | vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1); | 990 | vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1); |
987 | vc->vc_need_wrap = 0; | 991 | vc->vc_need_wrap = 0; |
988 | } | 992 | } |
989 | 993 | ||
990 | /* for absolute user moves, when decom is set */ | 994 | /* for absolute user moves, when decom is set */ |
991 | static void gotoxay(struct vc_data *vc, int new_x, int new_y) | 995 | static void gotoxay(struct vc_data *vc, int new_x, int new_y) |
992 | { | 996 | { |
993 | gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y); | 997 | gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y); |
994 | } | 998 | } |
995 | 999 | ||
996 | void scrollback(struct vc_data *vc, int lines) | 1000 | void scrollback(struct vc_data *vc, int lines) |
997 | { | 1001 | { |
998 | if (!lines) | 1002 | if (!lines) |
999 | lines = vc->vc_rows / 2; | 1003 | lines = vc->vc_rows / 2; |
1000 | scrolldelta(-lines); | 1004 | scrolldelta(-lines); |
1001 | } | 1005 | } |
1002 | 1006 | ||
1003 | void scrollfront(struct vc_data *vc, int lines) | 1007 | void scrollfront(struct vc_data *vc, int lines) |
1004 | { | 1008 | { |
1005 | if (!lines) | 1009 | if (!lines) |
1006 | lines = vc->vc_rows / 2; | 1010 | lines = vc->vc_rows / 2; |
1007 | scrolldelta(lines); | 1011 | scrolldelta(lines); |
1008 | } | 1012 | } |
1009 | 1013 | ||
1010 | static void lf(struct vc_data *vc) | 1014 | static void lf(struct vc_data *vc) |
1011 | { | 1015 | { |
1012 | /* don't scroll if above bottom of scrolling region, or | 1016 | /* don't scroll if above bottom of scrolling region, or |
1013 | * if below scrolling region | 1017 | * if below scrolling region |
1014 | */ | 1018 | */ |
1015 | if (vc->vc_y + 1 == vc->vc_bottom) | 1019 | if (vc->vc_y + 1 == vc->vc_bottom) |
1016 | scrup(vc, vc->vc_top, vc->vc_bottom, 1); | 1020 | scrup(vc, vc->vc_top, vc->vc_bottom, 1); |
1017 | else if (vc->vc_y < vc->vc_rows - 1) { | 1021 | else if (vc->vc_y < vc->vc_rows - 1) { |
1018 | vc->vc_y++; | 1022 | vc->vc_y++; |
1019 | vc->vc_pos += vc->vc_size_row; | 1023 | vc->vc_pos += vc->vc_size_row; |
1020 | } | 1024 | } |
1021 | vc->vc_need_wrap = 0; | 1025 | vc->vc_need_wrap = 0; |
1022 | } | 1026 | } |
1023 | 1027 | ||
1024 | static void ri(struct vc_data *vc) | 1028 | static void ri(struct vc_data *vc) |
1025 | { | 1029 | { |
1026 | /* don't scroll if below top of scrolling region, or | 1030 | /* don't scroll if below top of scrolling region, or |
1027 | * if above scrolling region | 1031 | * if above scrolling region |
1028 | */ | 1032 | */ |
1029 | if (vc->vc_y == vc->vc_top) | 1033 | if (vc->vc_y == vc->vc_top) |
1030 | scrdown(vc, vc->vc_top, vc->vc_bottom, 1); | 1034 | scrdown(vc, vc->vc_top, vc->vc_bottom, 1); |
1031 | else if (vc->vc_y > 0) { | 1035 | else if (vc->vc_y > 0) { |
1032 | vc->vc_y--; | 1036 | vc->vc_y--; |
1033 | vc->vc_pos -= vc->vc_size_row; | 1037 | vc->vc_pos -= vc->vc_size_row; |
1034 | } | 1038 | } |
1035 | vc->vc_need_wrap = 0; | 1039 | vc->vc_need_wrap = 0; |
1036 | } | 1040 | } |
1037 | 1041 | ||
1038 | static inline void cr(struct vc_data *vc) | 1042 | static inline void cr(struct vc_data *vc) |
1039 | { | 1043 | { |
1040 | vc->vc_pos -= vc->vc_x << 1; | 1044 | vc->vc_pos -= vc->vc_x << 1; |
1041 | vc->vc_need_wrap = vc->vc_x = 0; | 1045 | vc->vc_need_wrap = vc->vc_x = 0; |
1042 | } | 1046 | } |
1043 | 1047 | ||
1044 | static inline void bs(struct vc_data *vc) | 1048 | static inline void bs(struct vc_data *vc) |
1045 | { | 1049 | { |
1046 | if (vc->vc_x) { | 1050 | if (vc->vc_x) { |
1047 | vc->vc_pos -= 2; | 1051 | vc->vc_pos -= 2; |
1048 | vc->vc_x--; | 1052 | vc->vc_x--; |
1049 | vc->vc_need_wrap = 0; | 1053 | vc->vc_need_wrap = 0; |
1050 | } | 1054 | } |
1051 | } | 1055 | } |
1052 | 1056 | ||
1053 | static inline void del(struct vc_data *vc) | 1057 | static inline void del(struct vc_data *vc) |
1054 | { | 1058 | { |
1055 | /* ignored */ | 1059 | /* ignored */ |
1056 | } | 1060 | } |
1057 | 1061 | ||
1058 | static void csi_J(struct vc_data *vc, int vpar) | 1062 | static void csi_J(struct vc_data *vc, int vpar) |
1059 | { | 1063 | { |
1060 | unsigned int count; | 1064 | unsigned int count; |
1061 | unsigned short * start; | 1065 | unsigned short * start; |
1062 | 1066 | ||
1063 | switch (vpar) { | 1067 | switch (vpar) { |
1064 | case 0: /* erase from cursor to end of display */ | 1068 | case 0: /* erase from cursor to end of display */ |
1065 | count = (vc->vc_scr_end - vc->vc_pos) >> 1; | 1069 | count = (vc->vc_scr_end - vc->vc_pos) >> 1; |
1066 | start = (unsigned short *)vc->vc_pos; | 1070 | start = (unsigned short *)vc->vc_pos; |
1067 | if (DO_UPDATE(vc)) { | 1071 | if (DO_UPDATE(vc)) { |
1068 | /* do in two stages */ | 1072 | /* do in two stages */ |
1069 | vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, | 1073 | vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, |
1070 | vc->vc_cols - vc->vc_x); | 1074 | vc->vc_cols - vc->vc_x); |
1071 | vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0, | 1075 | vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0, |
1072 | vc->vc_rows - vc->vc_y - 1, | 1076 | vc->vc_rows - vc->vc_y - 1, |
1073 | vc->vc_cols); | 1077 | vc->vc_cols); |
1074 | } | 1078 | } |
1075 | break; | 1079 | break; |
1076 | case 1: /* erase from start to cursor */ | 1080 | case 1: /* erase from start to cursor */ |
1077 | count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; | 1081 | count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; |
1078 | start = (unsigned short *)vc->vc_origin; | 1082 | start = (unsigned short *)vc->vc_origin; |
1079 | if (DO_UPDATE(vc)) { | 1083 | if (DO_UPDATE(vc)) { |
1080 | /* do in two stages */ | 1084 | /* do in two stages */ |
1081 | vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y, | 1085 | vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y, |
1082 | vc->vc_cols); | 1086 | vc->vc_cols); |
1083 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, | 1087 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, |
1084 | vc->vc_x + 1); | 1088 | vc->vc_x + 1); |
1085 | } | 1089 | } |
1086 | break; | 1090 | break; |
1087 | case 2: /* erase whole display */ | 1091 | case 2: /* erase whole display */ |
1088 | count = vc->vc_cols * vc->vc_rows; | 1092 | count = vc->vc_cols * vc->vc_rows; |
1089 | start = (unsigned short *)vc->vc_origin; | 1093 | start = (unsigned short *)vc->vc_origin; |
1090 | if (DO_UPDATE(vc)) | 1094 | if (DO_UPDATE(vc)) |
1091 | vc->vc_sw->con_clear(vc, 0, 0, | 1095 | vc->vc_sw->con_clear(vc, 0, 0, |
1092 | vc->vc_rows, | 1096 | vc->vc_rows, |
1093 | vc->vc_cols); | 1097 | vc->vc_cols); |
1094 | break; | 1098 | break; |
1095 | default: | 1099 | default: |
1096 | return; | 1100 | return; |
1097 | } | 1101 | } |
1098 | scr_memsetw(start, vc->vc_video_erase_char, 2 * count); | 1102 | scr_memsetw(start, vc->vc_video_erase_char, 2 * count); |
1099 | vc->vc_need_wrap = 0; | 1103 | vc->vc_need_wrap = 0; |
1100 | } | 1104 | } |
1101 | 1105 | ||
1102 | static void csi_K(struct vc_data *vc, int vpar) | 1106 | static void csi_K(struct vc_data *vc, int vpar) |
1103 | { | 1107 | { |
1104 | unsigned int count; | 1108 | unsigned int count; |
1105 | unsigned short * start; | 1109 | unsigned short * start; |
1106 | 1110 | ||
1107 | switch (vpar) { | 1111 | switch (vpar) { |
1108 | case 0: /* erase from cursor to end of line */ | 1112 | case 0: /* erase from cursor to end of line */ |
1109 | count = vc->vc_cols - vc->vc_x; | 1113 | count = vc->vc_cols - vc->vc_x; |
1110 | start = (unsigned short *)vc->vc_pos; | 1114 | start = (unsigned short *)vc->vc_pos; |
1111 | if (DO_UPDATE(vc)) | 1115 | if (DO_UPDATE(vc)) |
1112 | vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, | 1116 | vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, |
1113 | vc->vc_cols - vc->vc_x); | 1117 | vc->vc_cols - vc->vc_x); |
1114 | break; | 1118 | break; |
1115 | case 1: /* erase from start of line to cursor */ | 1119 | case 1: /* erase from start of line to cursor */ |
1116 | start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); | 1120 | start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); |
1117 | count = vc->vc_x + 1; | 1121 | count = vc->vc_x + 1; |
1118 | if (DO_UPDATE(vc)) | 1122 | if (DO_UPDATE(vc)) |
1119 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, | 1123 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, |
1120 | vc->vc_x + 1); | 1124 | vc->vc_x + 1); |
1121 | break; | 1125 | break; |
1122 | case 2: /* erase whole line */ | 1126 | case 2: /* erase whole line */ |
1123 | start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); | 1127 | start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); |
1124 | count = vc->vc_cols; | 1128 | count = vc->vc_cols; |
1125 | if (DO_UPDATE(vc)) | 1129 | if (DO_UPDATE(vc)) |
1126 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, | 1130 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, |
1127 | vc->vc_cols); | 1131 | vc->vc_cols); |
1128 | break; | 1132 | break; |
1129 | default: | 1133 | default: |
1130 | return; | 1134 | return; |
1131 | } | 1135 | } |
1132 | scr_memsetw(start, vc->vc_video_erase_char, 2 * count); | 1136 | scr_memsetw(start, vc->vc_video_erase_char, 2 * count); |
1133 | vc->vc_need_wrap = 0; | 1137 | vc->vc_need_wrap = 0; |
1134 | } | 1138 | } |
1135 | 1139 | ||
1136 | static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */ | 1140 | static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */ |
1137 | { /* not vt100? */ | 1141 | { /* not vt100? */ |
1138 | int count; | 1142 | int count; |
1139 | 1143 | ||
1140 | if (!vpar) | 1144 | if (!vpar) |
1141 | vpar++; | 1145 | vpar++; |
1142 | count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar; | 1146 | count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar; |
1143 | 1147 | ||
1144 | scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); | 1148 | scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); |
1145 | if (DO_UPDATE(vc)) | 1149 | if (DO_UPDATE(vc)) |
1146 | vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count); | 1150 | vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count); |
1147 | vc->vc_need_wrap = 0; | 1151 | vc->vc_need_wrap = 0; |
1148 | } | 1152 | } |
1149 | 1153 | ||
1150 | static void default_attr(struct vc_data *vc) | 1154 | static void default_attr(struct vc_data *vc) |
1151 | { | 1155 | { |
1152 | vc->vc_intensity = 1; | 1156 | vc->vc_intensity = 1; |
1153 | vc->vc_italic = 0; | 1157 | vc->vc_italic = 0; |
1154 | vc->vc_underline = 0; | 1158 | vc->vc_underline = 0; |
1155 | vc->vc_reverse = 0; | 1159 | vc->vc_reverse = 0; |
1156 | vc->vc_blink = 0; | 1160 | vc->vc_blink = 0; |
1157 | vc->vc_color = vc->vc_def_color; | 1161 | vc->vc_color = vc->vc_def_color; |
1158 | } | 1162 | } |
1159 | 1163 | ||
1160 | /* console_sem is held */ | 1164 | /* console_sem is held */ |
1161 | static void csi_m(struct vc_data *vc) | 1165 | static void csi_m(struct vc_data *vc) |
1162 | { | 1166 | { |
1163 | int i; | 1167 | int i; |
1164 | 1168 | ||
1165 | for (i = 0; i <= vc->vc_npar; i++) | 1169 | for (i = 0; i <= vc->vc_npar; i++) |
1166 | switch (vc->vc_par[i]) { | 1170 | switch (vc->vc_par[i]) { |
1167 | case 0: /* all attributes off */ | 1171 | case 0: /* all attributes off */ |
1168 | default_attr(vc); | 1172 | default_attr(vc); |
1169 | break; | 1173 | break; |
1170 | case 1: | 1174 | case 1: |
1171 | vc->vc_intensity = 2; | 1175 | vc->vc_intensity = 2; |
1172 | break; | 1176 | break; |
1173 | case 2: | 1177 | case 2: |
1174 | vc->vc_intensity = 0; | 1178 | vc->vc_intensity = 0; |
1175 | break; | 1179 | break; |
1176 | case 3: | 1180 | case 3: |
1177 | vc->vc_italic = 1; | 1181 | vc->vc_italic = 1; |
1178 | break; | 1182 | break; |
1179 | case 4: | 1183 | case 4: |
1180 | vc->vc_underline = 1; | 1184 | vc->vc_underline = 1; |
1181 | break; | 1185 | break; |
1182 | case 5: | 1186 | case 5: |
1183 | vc->vc_blink = 1; | 1187 | vc->vc_blink = 1; |
1184 | break; | 1188 | break; |
1185 | case 7: | 1189 | case 7: |
1186 | vc->vc_reverse = 1; | 1190 | vc->vc_reverse = 1; |
1187 | break; | 1191 | break; |
1188 | case 10: /* ANSI X3.64-1979 (SCO-ish?) | 1192 | case 10: /* ANSI X3.64-1979 (SCO-ish?) |
1189 | * Select primary font, don't display | 1193 | * Select primary font, don't display |
1190 | * control chars if defined, don't set | 1194 | * control chars if defined, don't set |
1191 | * bit 8 on output. | 1195 | * bit 8 on output. |
1192 | */ | 1196 | */ |
1193 | vc->vc_translate = set_translate(vc->vc_charset == 0 | 1197 | vc->vc_translate = set_translate(vc->vc_charset == 0 |
1194 | ? vc->vc_G0_charset | 1198 | ? vc->vc_G0_charset |
1195 | : vc->vc_G1_charset, vc); | 1199 | : vc->vc_G1_charset, vc); |
1196 | vc->vc_disp_ctrl = 0; | 1200 | vc->vc_disp_ctrl = 0; |
1197 | vc->vc_toggle_meta = 0; | 1201 | vc->vc_toggle_meta = 0; |
1198 | break; | 1202 | break; |
1199 | case 11: /* ANSI X3.64-1979 (SCO-ish?) | 1203 | case 11: /* ANSI X3.64-1979 (SCO-ish?) |
1200 | * Select first alternate font, lets | 1204 | * Select first alternate font, lets |
1201 | * chars < 32 be displayed as ROM chars. | 1205 | * chars < 32 be displayed as ROM chars. |
1202 | */ | 1206 | */ |
1203 | vc->vc_translate = set_translate(IBMPC_MAP, vc); | 1207 | vc->vc_translate = set_translate(IBMPC_MAP, vc); |
1204 | vc->vc_disp_ctrl = 1; | 1208 | vc->vc_disp_ctrl = 1; |
1205 | vc->vc_toggle_meta = 0; | 1209 | vc->vc_toggle_meta = 0; |
1206 | break; | 1210 | break; |
1207 | case 12: /* ANSI X3.64-1979 (SCO-ish?) | 1211 | case 12: /* ANSI X3.64-1979 (SCO-ish?) |
1208 | * Select second alternate font, toggle | 1212 | * Select second alternate font, toggle |
1209 | * high bit before displaying as ROM char. | 1213 | * high bit before displaying as ROM char. |
1210 | */ | 1214 | */ |
1211 | vc->vc_translate = set_translate(IBMPC_MAP, vc); | 1215 | vc->vc_translate = set_translate(IBMPC_MAP, vc); |
1212 | vc->vc_disp_ctrl = 1; | 1216 | vc->vc_disp_ctrl = 1; |
1213 | vc->vc_toggle_meta = 1; | 1217 | vc->vc_toggle_meta = 1; |
1214 | break; | 1218 | break; |
1215 | case 21: | 1219 | case 21: |
1216 | case 22: | 1220 | case 22: |
1217 | vc->vc_intensity = 1; | 1221 | vc->vc_intensity = 1; |
1218 | break; | 1222 | break; |
1219 | case 23: | 1223 | case 23: |
1220 | vc->vc_italic = 0; | 1224 | vc->vc_italic = 0; |
1221 | break; | 1225 | break; |
1222 | case 24: | 1226 | case 24: |
1223 | vc->vc_underline = 0; | 1227 | vc->vc_underline = 0; |
1224 | break; | 1228 | break; |
1225 | case 25: | 1229 | case 25: |
1226 | vc->vc_blink = 0; | 1230 | vc->vc_blink = 0; |
1227 | break; | 1231 | break; |
1228 | case 27: | 1232 | case 27: |
1229 | vc->vc_reverse = 0; | 1233 | vc->vc_reverse = 0; |
1230 | break; | 1234 | break; |
1231 | case 38: /* ANSI X3.64-1979 (SCO-ish?) | 1235 | case 38: /* ANSI X3.64-1979 (SCO-ish?) |
1232 | * Enables underscore, white foreground | 1236 | * Enables underscore, white foreground |
1233 | * with white underscore (Linux - use | 1237 | * with white underscore (Linux - use |
1234 | * default foreground). | 1238 | * default foreground). |
1235 | */ | 1239 | */ |
1236 | vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); | 1240 | vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); |
1237 | vc->vc_underline = 1; | 1241 | vc->vc_underline = 1; |
1238 | break; | 1242 | break; |
1239 | case 39: /* ANSI X3.64-1979 (SCO-ish?) | 1243 | case 39: /* ANSI X3.64-1979 (SCO-ish?) |
1240 | * Disable underline option. | 1244 | * Disable underline option. |
1241 | * Reset colour to default? It did this | 1245 | * Reset colour to default? It did this |
1242 | * before... | 1246 | * before... |
1243 | */ | 1247 | */ |
1244 | vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); | 1248 | vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); |
1245 | vc->vc_underline = 0; | 1249 | vc->vc_underline = 0; |
1246 | break; | 1250 | break; |
1247 | case 49: | 1251 | case 49: |
1248 | vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f); | 1252 | vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f); |
1249 | break; | 1253 | break; |
1250 | default: | 1254 | default: |
1251 | if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) | 1255 | if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) |
1252 | vc->vc_color = color_table[vc->vc_par[i] - 30] | 1256 | vc->vc_color = color_table[vc->vc_par[i] - 30] |
1253 | | (vc->vc_color & 0xf0); | 1257 | | (vc->vc_color & 0xf0); |
1254 | else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47) | 1258 | else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47) |
1255 | vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4) | 1259 | vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4) |
1256 | | (vc->vc_color & 0x0f); | 1260 | | (vc->vc_color & 0x0f); |
1257 | break; | 1261 | break; |
1258 | } | 1262 | } |
1259 | update_attr(vc); | 1263 | update_attr(vc); |
1260 | } | 1264 | } |
1261 | 1265 | ||
1262 | static void respond_string(const char *p, struct tty_struct *tty) | 1266 | static void respond_string(const char *p, struct tty_struct *tty) |
1263 | { | 1267 | { |
1264 | while (*p) { | 1268 | while (*p) { |
1265 | tty_insert_flip_char(tty, *p, 0); | 1269 | tty_insert_flip_char(tty, *p, 0); |
1266 | p++; | 1270 | p++; |
1267 | } | 1271 | } |
1268 | con_schedule_flip(tty); | 1272 | con_schedule_flip(tty); |
1269 | } | 1273 | } |
1270 | 1274 | ||
1271 | static void cursor_report(struct vc_data *vc, struct tty_struct *tty) | 1275 | static void cursor_report(struct vc_data *vc, struct tty_struct *tty) |
1272 | { | 1276 | { |
1273 | char buf[40]; | 1277 | char buf[40]; |
1274 | 1278 | ||
1275 | sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1); | 1279 | sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1); |
1276 | respond_string(buf, tty); | 1280 | respond_string(buf, tty); |
1277 | } | 1281 | } |
1278 | 1282 | ||
1279 | static inline void status_report(struct tty_struct *tty) | 1283 | static inline void status_report(struct tty_struct *tty) |
1280 | { | 1284 | { |
1281 | respond_string("\033[0n", tty); /* Terminal ok */ | 1285 | respond_string("\033[0n", tty); /* Terminal ok */ |
1282 | } | 1286 | } |
1283 | 1287 | ||
1284 | static inline void respond_ID(struct tty_struct * tty) | 1288 | static inline void respond_ID(struct tty_struct * tty) |
1285 | { | 1289 | { |
1286 | respond_string(VT102ID, tty); | 1290 | respond_string(VT102ID, tty); |
1287 | } | 1291 | } |
1288 | 1292 | ||
1289 | void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry) | 1293 | void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry) |
1290 | { | 1294 | { |
1291 | char buf[8]; | 1295 | char buf[8]; |
1292 | 1296 | ||
1293 | sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), | 1297 | sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), |
1294 | (char)('!' + mry)); | 1298 | (char)('!' + mry)); |
1295 | respond_string(buf, tty); | 1299 | respond_string(buf, tty); |
1296 | } | 1300 | } |
1297 | 1301 | ||
1298 | /* invoked via ioctl(TIOCLINUX) and through set_selection */ | 1302 | /* invoked via ioctl(TIOCLINUX) and through set_selection */ |
1299 | int mouse_reporting(void) | 1303 | int mouse_reporting(void) |
1300 | { | 1304 | { |
1301 | return vc_cons[fg_console].d->vc_report_mouse; | 1305 | return vc_cons[fg_console].d->vc_report_mouse; |
1302 | } | 1306 | } |
1303 | 1307 | ||
1304 | /* console_sem is held */ | 1308 | /* console_sem is held */ |
1305 | static void set_mode(struct vc_data *vc, int on_off) | 1309 | static void set_mode(struct vc_data *vc, int on_off) |
1306 | { | 1310 | { |
1307 | int i; | 1311 | int i; |
1308 | 1312 | ||
1309 | for (i = 0; i <= vc->vc_npar; i++) | 1313 | for (i = 0; i <= vc->vc_npar; i++) |
1310 | if (vc->vc_ques) { | 1314 | if (vc->vc_ques) { |
1311 | switch(vc->vc_par[i]) { /* DEC private modes set/reset */ | 1315 | switch(vc->vc_par[i]) { /* DEC private modes set/reset */ |
1312 | case 1: /* Cursor keys send ^[Ox/^[[x */ | 1316 | case 1: /* Cursor keys send ^[Ox/^[[x */ |
1313 | if (on_off) | 1317 | if (on_off) |
1314 | set_kbd(vc, decckm); | 1318 | set_kbd(vc, decckm); |
1315 | else | 1319 | else |
1316 | clr_kbd(vc, decckm); | 1320 | clr_kbd(vc, decckm); |
1317 | break; | 1321 | break; |
1318 | case 3: /* 80/132 mode switch unimplemented */ | 1322 | case 3: /* 80/132 mode switch unimplemented */ |
1319 | vc->vc_deccolm = on_off; | 1323 | vc->vc_deccolm = on_off; |
1320 | #if 0 | 1324 | #if 0 |
1321 | vc_resize(deccolm ? 132 : 80, vc->vc_rows); | 1325 | vc_resize(deccolm ? 132 : 80, vc->vc_rows); |
1322 | /* this alone does not suffice; some user mode | 1326 | /* this alone does not suffice; some user mode |
1323 | utility has to change the hardware regs */ | 1327 | utility has to change the hardware regs */ |
1324 | #endif | 1328 | #endif |
1325 | break; | 1329 | break; |
1326 | case 5: /* Inverted screen on/off */ | 1330 | case 5: /* Inverted screen on/off */ |
1327 | if (vc->vc_decscnm != on_off) { | 1331 | if (vc->vc_decscnm != on_off) { |
1328 | vc->vc_decscnm = on_off; | 1332 | vc->vc_decscnm = on_off; |
1329 | invert_screen(vc, 0, vc->vc_screenbuf_size, 0); | 1333 | invert_screen(vc, 0, vc->vc_screenbuf_size, 0); |
1330 | update_attr(vc); | 1334 | update_attr(vc); |
1331 | } | 1335 | } |
1332 | break; | 1336 | break; |
1333 | case 6: /* Origin relative/absolute */ | 1337 | case 6: /* Origin relative/absolute */ |
1334 | vc->vc_decom = on_off; | 1338 | vc->vc_decom = on_off; |
1335 | gotoxay(vc, 0, 0); | 1339 | gotoxay(vc, 0, 0); |
1336 | break; | 1340 | break; |
1337 | case 7: /* Autowrap on/off */ | 1341 | case 7: /* Autowrap on/off */ |
1338 | vc->vc_decawm = on_off; | 1342 | vc->vc_decawm = on_off; |
1339 | break; | 1343 | break; |
1340 | case 8: /* Autorepeat on/off */ | 1344 | case 8: /* Autorepeat on/off */ |
1341 | if (on_off) | 1345 | if (on_off) |
1342 | set_kbd(vc, decarm); | 1346 | set_kbd(vc, decarm); |
1343 | else | 1347 | else |
1344 | clr_kbd(vc, decarm); | 1348 | clr_kbd(vc, decarm); |
1345 | break; | 1349 | break; |
1346 | case 9: | 1350 | case 9: |
1347 | vc->vc_report_mouse = on_off ? 1 : 0; | 1351 | vc->vc_report_mouse = on_off ? 1 : 0; |
1348 | break; | 1352 | break; |
1349 | case 25: /* Cursor on/off */ | 1353 | case 25: /* Cursor on/off */ |
1350 | vc->vc_deccm = on_off; | 1354 | vc->vc_deccm = on_off; |
1351 | break; | 1355 | break; |
1352 | case 1000: | 1356 | case 1000: |
1353 | vc->vc_report_mouse = on_off ? 2 : 0; | 1357 | vc->vc_report_mouse = on_off ? 2 : 0; |
1354 | break; | 1358 | break; |
1355 | } | 1359 | } |
1356 | } else { | 1360 | } else { |
1357 | switch(vc->vc_par[i]) { /* ANSI modes set/reset */ | 1361 | switch(vc->vc_par[i]) { /* ANSI modes set/reset */ |
1358 | case 3: /* Monitor (display ctrls) */ | 1362 | case 3: /* Monitor (display ctrls) */ |
1359 | vc->vc_disp_ctrl = on_off; | 1363 | vc->vc_disp_ctrl = on_off; |
1360 | break; | 1364 | break; |
1361 | case 4: /* Insert Mode on/off */ | 1365 | case 4: /* Insert Mode on/off */ |
1362 | vc->vc_decim = on_off; | 1366 | vc->vc_decim = on_off; |
1363 | break; | 1367 | break; |
1364 | case 20: /* Lf, Enter == CrLf/Lf */ | 1368 | case 20: /* Lf, Enter == CrLf/Lf */ |
1365 | if (on_off) | 1369 | if (on_off) |
1366 | set_kbd(vc, lnm); | 1370 | set_kbd(vc, lnm); |
1367 | else | 1371 | else |
1368 | clr_kbd(vc, lnm); | 1372 | clr_kbd(vc, lnm); |
1369 | break; | 1373 | break; |
1370 | } | 1374 | } |
1371 | } | 1375 | } |
1372 | } | 1376 | } |
1373 | 1377 | ||
1374 | /* console_sem is held */ | 1378 | /* console_sem is held */ |
1375 | static void setterm_command(struct vc_data *vc) | 1379 | static void setterm_command(struct vc_data *vc) |
1376 | { | 1380 | { |
1377 | switch(vc->vc_par[0]) { | 1381 | switch(vc->vc_par[0]) { |
1378 | case 1: /* set color for underline mode */ | 1382 | case 1: /* set color for underline mode */ |
1379 | if (vc->vc_can_do_color && | 1383 | if (vc->vc_can_do_color && |
1380 | vc->vc_par[1] < 16) { | 1384 | vc->vc_par[1] < 16) { |
1381 | vc->vc_ulcolor = color_table[vc->vc_par[1]]; | 1385 | vc->vc_ulcolor = color_table[vc->vc_par[1]]; |
1382 | if (vc->vc_underline) | 1386 | if (vc->vc_underline) |
1383 | update_attr(vc); | 1387 | update_attr(vc); |
1384 | } | 1388 | } |
1385 | break; | 1389 | break; |
1386 | case 2: /* set color for half intensity mode */ | 1390 | case 2: /* set color for half intensity mode */ |
1387 | if (vc->vc_can_do_color && | 1391 | if (vc->vc_can_do_color && |
1388 | vc->vc_par[1] < 16) { | 1392 | vc->vc_par[1] < 16) { |
1389 | vc->vc_halfcolor = color_table[vc->vc_par[1]]; | 1393 | vc->vc_halfcolor = color_table[vc->vc_par[1]]; |
1390 | if (vc->vc_intensity == 0) | 1394 | if (vc->vc_intensity == 0) |
1391 | update_attr(vc); | 1395 | update_attr(vc); |
1392 | } | 1396 | } |
1393 | break; | 1397 | break; |
1394 | case 8: /* store colors as defaults */ | 1398 | case 8: /* store colors as defaults */ |
1395 | vc->vc_def_color = vc->vc_attr; | 1399 | vc->vc_def_color = vc->vc_attr; |
1396 | if (vc->vc_hi_font_mask == 0x100) | 1400 | if (vc->vc_hi_font_mask == 0x100) |
1397 | vc->vc_def_color >>= 1; | 1401 | vc->vc_def_color >>= 1; |
1398 | default_attr(vc); | 1402 | default_attr(vc); |
1399 | update_attr(vc); | 1403 | update_attr(vc); |
1400 | break; | 1404 | break; |
1401 | case 9: /* set blanking interval */ | 1405 | case 9: /* set blanking interval */ |
1402 | blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ; | 1406 | blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ; |
1403 | poke_blanked_console(); | 1407 | poke_blanked_console(); |
1404 | break; | 1408 | break; |
1405 | case 10: /* set bell frequency in Hz */ | 1409 | case 10: /* set bell frequency in Hz */ |
1406 | if (vc->vc_npar >= 1) | 1410 | if (vc->vc_npar >= 1) |
1407 | vc->vc_bell_pitch = vc->vc_par[1]; | 1411 | vc->vc_bell_pitch = vc->vc_par[1]; |
1408 | else | 1412 | else |
1409 | vc->vc_bell_pitch = DEFAULT_BELL_PITCH; | 1413 | vc->vc_bell_pitch = DEFAULT_BELL_PITCH; |
1410 | break; | 1414 | break; |
1411 | case 11: /* set bell duration in msec */ | 1415 | case 11: /* set bell duration in msec */ |
1412 | if (vc->vc_npar >= 1) | 1416 | if (vc->vc_npar >= 1) |
1413 | vc->vc_bell_duration = (vc->vc_par[1] < 2000) ? | 1417 | vc->vc_bell_duration = (vc->vc_par[1] < 2000) ? |
1414 | vc->vc_par[1] * HZ / 1000 : 0; | 1418 | vc->vc_par[1] * HZ / 1000 : 0; |
1415 | else | 1419 | else |
1416 | vc->vc_bell_duration = DEFAULT_BELL_DURATION; | 1420 | vc->vc_bell_duration = DEFAULT_BELL_DURATION; |
1417 | break; | 1421 | break; |
1418 | case 12: /* bring specified console to the front */ | 1422 | case 12: /* bring specified console to the front */ |
1419 | if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1)) | 1423 | if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1)) |
1420 | set_console(vc->vc_par[1] - 1); | 1424 | set_console(vc->vc_par[1] - 1); |
1421 | break; | 1425 | break; |
1422 | case 13: /* unblank the screen */ | 1426 | case 13: /* unblank the screen */ |
1423 | poke_blanked_console(); | 1427 | poke_blanked_console(); |
1424 | break; | 1428 | break; |
1425 | case 14: /* set vesa powerdown interval */ | 1429 | case 14: /* set vesa powerdown interval */ |
1426 | vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ; | 1430 | vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ; |
1427 | break; | 1431 | break; |
1428 | case 15: /* activate the previous console */ | 1432 | case 15: /* activate the previous console */ |
1429 | set_console(last_console); | 1433 | set_console(last_console); |
1430 | break; | 1434 | break; |
1431 | } | 1435 | } |
1432 | } | 1436 | } |
1433 | 1437 | ||
1434 | /* console_sem is held */ | 1438 | /* console_sem is held */ |
1435 | static void csi_at(struct vc_data *vc, unsigned int nr) | 1439 | static void csi_at(struct vc_data *vc, unsigned int nr) |
1436 | { | 1440 | { |
1437 | if (nr > vc->vc_cols - vc->vc_x) | 1441 | if (nr > vc->vc_cols - vc->vc_x) |
1438 | nr = vc->vc_cols - vc->vc_x; | 1442 | nr = vc->vc_cols - vc->vc_x; |
1439 | else if (!nr) | 1443 | else if (!nr) |
1440 | nr = 1; | 1444 | nr = 1; |
1441 | insert_char(vc, nr); | 1445 | insert_char(vc, nr); |
1442 | } | 1446 | } |
1443 | 1447 | ||
1444 | /* console_sem is held */ | 1448 | /* console_sem is held */ |
1445 | static void csi_L(struct vc_data *vc, unsigned int nr) | 1449 | static void csi_L(struct vc_data *vc, unsigned int nr) |
1446 | { | 1450 | { |
1447 | if (nr > vc->vc_rows - vc->vc_y) | 1451 | if (nr > vc->vc_rows - vc->vc_y) |
1448 | nr = vc->vc_rows - vc->vc_y; | 1452 | nr = vc->vc_rows - vc->vc_y; |
1449 | else if (!nr) | 1453 | else if (!nr) |
1450 | nr = 1; | 1454 | nr = 1; |
1451 | scrdown(vc, vc->vc_y, vc->vc_bottom, nr); | 1455 | scrdown(vc, vc->vc_y, vc->vc_bottom, nr); |
1452 | vc->vc_need_wrap = 0; | 1456 | vc->vc_need_wrap = 0; |
1453 | } | 1457 | } |
1454 | 1458 | ||
1455 | /* console_sem is held */ | 1459 | /* console_sem is held */ |
1456 | static void csi_P(struct vc_data *vc, unsigned int nr) | 1460 | static void csi_P(struct vc_data *vc, unsigned int nr) |
1457 | { | 1461 | { |
1458 | if (nr > vc->vc_cols - vc->vc_x) | 1462 | if (nr > vc->vc_cols - vc->vc_x) |
1459 | nr = vc->vc_cols - vc->vc_x; | 1463 | nr = vc->vc_cols - vc->vc_x; |
1460 | else if (!nr) | 1464 | else if (!nr) |
1461 | nr = 1; | 1465 | nr = 1; |
1462 | delete_char(vc, nr); | 1466 | delete_char(vc, nr); |
1463 | } | 1467 | } |
1464 | 1468 | ||
1465 | /* console_sem is held */ | 1469 | /* console_sem is held */ |
1466 | static void csi_M(struct vc_data *vc, unsigned int nr) | 1470 | static void csi_M(struct vc_data *vc, unsigned int nr) |
1467 | { | 1471 | { |
1468 | if (nr > vc->vc_rows - vc->vc_y) | 1472 | if (nr > vc->vc_rows - vc->vc_y) |
1469 | nr = vc->vc_rows - vc->vc_y; | 1473 | nr = vc->vc_rows - vc->vc_y; |
1470 | else if (!nr) | 1474 | else if (!nr) |
1471 | nr=1; | 1475 | nr=1; |
1472 | scrup(vc, vc->vc_y, vc->vc_bottom, nr); | 1476 | scrup(vc, vc->vc_y, vc->vc_bottom, nr); |
1473 | vc->vc_need_wrap = 0; | 1477 | vc->vc_need_wrap = 0; |
1474 | } | 1478 | } |
1475 | 1479 | ||
1476 | /* console_sem is held (except via vc_init->reset_terminal */ | 1480 | /* console_sem is held (except via vc_init->reset_terminal */ |
1477 | static void save_cur(struct vc_data *vc) | 1481 | static void save_cur(struct vc_data *vc) |
1478 | { | 1482 | { |
1479 | vc->vc_saved_x = vc->vc_x; | 1483 | vc->vc_saved_x = vc->vc_x; |
1480 | vc->vc_saved_y = vc->vc_y; | 1484 | vc->vc_saved_y = vc->vc_y; |
1481 | vc->vc_s_intensity = vc->vc_intensity; | 1485 | vc->vc_s_intensity = vc->vc_intensity; |
1482 | vc->vc_s_italic = vc->vc_italic; | 1486 | vc->vc_s_italic = vc->vc_italic; |
1483 | vc->vc_s_underline = vc->vc_underline; | 1487 | vc->vc_s_underline = vc->vc_underline; |
1484 | vc->vc_s_blink = vc->vc_blink; | 1488 | vc->vc_s_blink = vc->vc_blink; |
1485 | vc->vc_s_reverse = vc->vc_reverse; | 1489 | vc->vc_s_reverse = vc->vc_reverse; |
1486 | vc->vc_s_charset = vc->vc_charset; | 1490 | vc->vc_s_charset = vc->vc_charset; |
1487 | vc->vc_s_color = vc->vc_color; | 1491 | vc->vc_s_color = vc->vc_color; |
1488 | vc->vc_saved_G0 = vc->vc_G0_charset; | 1492 | vc->vc_saved_G0 = vc->vc_G0_charset; |
1489 | vc->vc_saved_G1 = vc->vc_G1_charset; | 1493 | vc->vc_saved_G1 = vc->vc_G1_charset; |
1490 | } | 1494 | } |
1491 | 1495 | ||
1492 | /* console_sem is held */ | 1496 | /* console_sem is held */ |
1493 | static void restore_cur(struct vc_data *vc) | 1497 | static void restore_cur(struct vc_data *vc) |
1494 | { | 1498 | { |
1495 | gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y); | 1499 | gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y); |
1496 | vc->vc_intensity = vc->vc_s_intensity; | 1500 | vc->vc_intensity = vc->vc_s_intensity; |
1497 | vc->vc_italic = vc->vc_s_italic; | 1501 | vc->vc_italic = vc->vc_s_italic; |
1498 | vc->vc_underline = vc->vc_s_underline; | 1502 | vc->vc_underline = vc->vc_s_underline; |
1499 | vc->vc_blink = vc->vc_s_blink; | 1503 | vc->vc_blink = vc->vc_s_blink; |
1500 | vc->vc_reverse = vc->vc_s_reverse; | 1504 | vc->vc_reverse = vc->vc_s_reverse; |
1501 | vc->vc_charset = vc->vc_s_charset; | 1505 | vc->vc_charset = vc->vc_s_charset; |
1502 | vc->vc_color = vc->vc_s_color; | 1506 | vc->vc_color = vc->vc_s_color; |
1503 | vc->vc_G0_charset = vc->vc_saved_G0; | 1507 | vc->vc_G0_charset = vc->vc_saved_G0; |
1504 | vc->vc_G1_charset = vc->vc_saved_G1; | 1508 | vc->vc_G1_charset = vc->vc_saved_G1; |
1505 | vc->vc_translate = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc); | 1509 | vc->vc_translate = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc); |
1506 | update_attr(vc); | 1510 | update_attr(vc); |
1507 | vc->vc_need_wrap = 0; | 1511 | vc->vc_need_wrap = 0; |
1508 | } | 1512 | } |
1509 | 1513 | ||
1510 | enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, | 1514 | enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, |
1511 | EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, | 1515 | EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, |
1512 | ESpalette }; | 1516 | ESpalette }; |
1513 | 1517 | ||
1514 | /* console_sem is held (except via vc_init()) */ | 1518 | /* console_sem is held (except via vc_init()) */ |
1515 | static void reset_terminal(struct vc_data *vc, int do_clear) | 1519 | static void reset_terminal(struct vc_data *vc, int do_clear) |
1516 | { | 1520 | { |
1517 | vc->vc_top = 0; | 1521 | vc->vc_top = 0; |
1518 | vc->vc_bottom = vc->vc_rows; | 1522 | vc->vc_bottom = vc->vc_rows; |
1519 | vc->vc_state = ESnormal; | 1523 | vc->vc_state = ESnormal; |
1520 | vc->vc_ques = 0; | 1524 | vc->vc_ques = 0; |
1521 | vc->vc_translate = set_translate(LAT1_MAP, vc); | 1525 | vc->vc_translate = set_translate(LAT1_MAP, vc); |
1522 | vc->vc_G0_charset = LAT1_MAP; | 1526 | vc->vc_G0_charset = LAT1_MAP; |
1523 | vc->vc_G1_charset = GRAF_MAP; | 1527 | vc->vc_G1_charset = GRAF_MAP; |
1524 | vc->vc_charset = 0; | 1528 | vc->vc_charset = 0; |
1525 | vc->vc_need_wrap = 0; | 1529 | vc->vc_need_wrap = 0; |
1526 | vc->vc_report_mouse = 0; | 1530 | vc->vc_report_mouse = 0; |
1527 | vc->vc_utf = default_utf8; | 1531 | vc->vc_utf = default_utf8; |
1528 | vc->vc_utf_count = 0; | 1532 | vc->vc_utf_count = 0; |
1529 | 1533 | ||
1530 | vc->vc_disp_ctrl = 0; | 1534 | vc->vc_disp_ctrl = 0; |
1531 | vc->vc_toggle_meta = 0; | 1535 | vc->vc_toggle_meta = 0; |
1532 | 1536 | ||
1533 | vc->vc_decscnm = 0; | 1537 | vc->vc_decscnm = 0; |
1534 | vc->vc_decom = 0; | 1538 | vc->vc_decom = 0; |
1535 | vc->vc_decawm = 1; | 1539 | vc->vc_decawm = 1; |
1536 | vc->vc_deccm = 1; | 1540 | vc->vc_deccm = 1; |
1537 | vc->vc_decim = 0; | 1541 | vc->vc_decim = 0; |
1538 | 1542 | ||
1539 | set_kbd(vc, decarm); | 1543 | set_kbd(vc, decarm); |
1540 | clr_kbd(vc, decckm); | 1544 | clr_kbd(vc, decckm); |
1541 | clr_kbd(vc, kbdapplic); | 1545 | clr_kbd(vc, kbdapplic); |
1542 | clr_kbd(vc, lnm); | 1546 | clr_kbd(vc, lnm); |
1543 | kbd_table[vc->vc_num].lockstate = 0; | 1547 | kbd_table[vc->vc_num].lockstate = 0; |
1544 | kbd_table[vc->vc_num].slockstate = 0; | 1548 | kbd_table[vc->vc_num].slockstate = 0; |
1545 | kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS; | 1549 | kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS; |
1546 | kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate; | 1550 | kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate; |
1547 | /* do not do set_leds here because this causes an endless tasklet loop | 1551 | /* do not do set_leds here because this causes an endless tasklet loop |
1548 | when the keyboard hasn't been initialized yet */ | 1552 | when the keyboard hasn't been initialized yet */ |
1549 | 1553 | ||
1550 | vc->vc_cursor_type = CUR_DEFAULT; | 1554 | vc->vc_cursor_type = CUR_DEFAULT; |
1551 | vc->vc_complement_mask = vc->vc_s_complement_mask; | 1555 | vc->vc_complement_mask = vc->vc_s_complement_mask; |
1552 | 1556 | ||
1553 | default_attr(vc); | 1557 | default_attr(vc); |
1554 | update_attr(vc); | 1558 | update_attr(vc); |
1555 | 1559 | ||
1556 | vc->vc_tab_stop[0] = 0x01010100; | 1560 | vc->vc_tab_stop[0] = 0x01010100; |
1557 | vc->vc_tab_stop[1] = | 1561 | vc->vc_tab_stop[1] = |
1558 | vc->vc_tab_stop[2] = | 1562 | vc->vc_tab_stop[2] = |
1559 | vc->vc_tab_stop[3] = | 1563 | vc->vc_tab_stop[3] = |
1560 | vc->vc_tab_stop[4] = 0x01010101; | 1564 | vc->vc_tab_stop[4] = 0x01010101; |
1561 | 1565 | ||
1562 | vc->vc_bell_pitch = DEFAULT_BELL_PITCH; | 1566 | vc->vc_bell_pitch = DEFAULT_BELL_PITCH; |
1563 | vc->vc_bell_duration = DEFAULT_BELL_DURATION; | 1567 | vc->vc_bell_duration = DEFAULT_BELL_DURATION; |
1564 | 1568 | ||
1565 | gotoxy(vc, 0, 0); | 1569 | gotoxy(vc, 0, 0); |
1566 | save_cur(vc); | 1570 | save_cur(vc); |
1567 | if (do_clear) | 1571 | if (do_clear) |
1568 | csi_J(vc, 2); | 1572 | csi_J(vc, 2); |
1569 | } | 1573 | } |
1570 | 1574 | ||
1571 | /* console_sem is held */ | 1575 | /* console_sem is held */ |
1572 | static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) | 1576 | static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) |
1573 | { | 1577 | { |
1574 | /* | 1578 | /* |
1575 | * Control characters can be used in the _middle_ | 1579 | * Control characters can be used in the _middle_ |
1576 | * of an escape sequence. | 1580 | * of an escape sequence. |
1577 | */ | 1581 | */ |
1578 | switch (c) { | 1582 | switch (c) { |
1579 | case 0: | 1583 | case 0: |
1580 | return; | 1584 | return; |
1581 | case 7: | 1585 | case 7: |
1582 | if (vc->vc_bell_duration) | 1586 | if (vc->vc_bell_duration) |
1583 | kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration); | 1587 | kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration); |
1584 | return; | 1588 | return; |
1585 | case 8: | 1589 | case 8: |
1586 | bs(vc); | 1590 | bs(vc); |
1587 | return; | 1591 | return; |
1588 | case 9: | 1592 | case 9: |
1589 | vc->vc_pos -= (vc->vc_x << 1); | 1593 | vc->vc_pos -= (vc->vc_x << 1); |
1590 | while (vc->vc_x < vc->vc_cols - 1) { | 1594 | while (vc->vc_x < vc->vc_cols - 1) { |
1591 | vc->vc_x++; | 1595 | vc->vc_x++; |
1592 | if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31))) | 1596 | if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31))) |
1593 | break; | 1597 | break; |
1594 | } | 1598 | } |
1595 | vc->vc_pos += (vc->vc_x << 1); | 1599 | vc->vc_pos += (vc->vc_x << 1); |
1596 | return; | 1600 | return; |
1597 | case 10: case 11: case 12: | 1601 | case 10: case 11: case 12: |
1598 | lf(vc); | 1602 | lf(vc); |
1599 | if (!is_kbd(vc, lnm)) | 1603 | if (!is_kbd(vc, lnm)) |
1600 | return; | 1604 | return; |
1601 | case 13: | 1605 | case 13: |
1602 | cr(vc); | 1606 | cr(vc); |
1603 | return; | 1607 | return; |
1604 | case 14: | 1608 | case 14: |
1605 | vc->vc_charset = 1; | 1609 | vc->vc_charset = 1; |
1606 | vc->vc_translate = set_translate(vc->vc_G1_charset, vc); | 1610 | vc->vc_translate = set_translate(vc->vc_G1_charset, vc); |
1607 | vc->vc_disp_ctrl = 1; | 1611 | vc->vc_disp_ctrl = 1; |
1608 | return; | 1612 | return; |
1609 | case 15: | 1613 | case 15: |
1610 | vc->vc_charset = 0; | 1614 | vc->vc_charset = 0; |
1611 | vc->vc_translate = set_translate(vc->vc_G0_charset, vc); | 1615 | vc->vc_translate = set_translate(vc->vc_G0_charset, vc); |
1612 | vc->vc_disp_ctrl = 0; | 1616 | vc->vc_disp_ctrl = 0; |
1613 | return; | 1617 | return; |
1614 | case 24: case 26: | 1618 | case 24: case 26: |
1615 | vc->vc_state = ESnormal; | 1619 | vc->vc_state = ESnormal; |
1616 | return; | 1620 | return; |
1617 | case 27: | 1621 | case 27: |
1618 | vc->vc_state = ESesc; | 1622 | vc->vc_state = ESesc; |
1619 | return; | 1623 | return; |
1620 | case 127: | 1624 | case 127: |
1621 | del(vc); | 1625 | del(vc); |
1622 | return; | 1626 | return; |
1623 | case 128+27: | 1627 | case 128+27: |
1624 | vc->vc_state = ESsquare; | 1628 | vc->vc_state = ESsquare; |
1625 | return; | 1629 | return; |
1626 | } | 1630 | } |
1627 | switch(vc->vc_state) { | 1631 | switch(vc->vc_state) { |
1628 | case ESesc: | 1632 | case ESesc: |
1629 | vc->vc_state = ESnormal; | 1633 | vc->vc_state = ESnormal; |
1630 | switch (c) { | 1634 | switch (c) { |
1631 | case '[': | 1635 | case '[': |
1632 | vc->vc_state = ESsquare; | 1636 | vc->vc_state = ESsquare; |
1633 | return; | 1637 | return; |
1634 | case ']': | 1638 | case ']': |
1635 | vc->vc_state = ESnonstd; | 1639 | vc->vc_state = ESnonstd; |
1636 | return; | 1640 | return; |
1637 | case '%': | 1641 | case '%': |
1638 | vc->vc_state = ESpercent; | 1642 | vc->vc_state = ESpercent; |
1639 | return; | 1643 | return; |
1640 | case 'E': | 1644 | case 'E': |
1641 | cr(vc); | 1645 | cr(vc); |
1642 | lf(vc); | 1646 | lf(vc); |
1643 | return; | 1647 | return; |
1644 | case 'M': | 1648 | case 'M': |
1645 | ri(vc); | 1649 | ri(vc); |
1646 | return; | 1650 | return; |
1647 | case 'D': | 1651 | case 'D': |
1648 | lf(vc); | 1652 | lf(vc); |
1649 | return; | 1653 | return; |
1650 | case 'H': | 1654 | case 'H': |
1651 | vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31)); | 1655 | vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31)); |
1652 | return; | 1656 | return; |
1653 | case 'Z': | 1657 | case 'Z': |
1654 | respond_ID(tty); | 1658 | respond_ID(tty); |
1655 | return; | 1659 | return; |
1656 | case '7': | 1660 | case '7': |
1657 | save_cur(vc); | 1661 | save_cur(vc); |
1658 | return; | 1662 | return; |
1659 | case '8': | 1663 | case '8': |
1660 | restore_cur(vc); | 1664 | restore_cur(vc); |
1661 | return; | 1665 | return; |
1662 | case '(': | 1666 | case '(': |
1663 | vc->vc_state = ESsetG0; | 1667 | vc->vc_state = ESsetG0; |
1664 | return; | 1668 | return; |
1665 | case ')': | 1669 | case ')': |
1666 | vc->vc_state = ESsetG1; | 1670 | vc->vc_state = ESsetG1; |
1667 | return; | 1671 | return; |
1668 | case '#': | 1672 | case '#': |
1669 | vc->vc_state = EShash; | 1673 | vc->vc_state = EShash; |
1670 | return; | 1674 | return; |
1671 | case 'c': | 1675 | case 'c': |
1672 | reset_terminal(vc, 1); | 1676 | reset_terminal(vc, 1); |
1673 | return; | 1677 | return; |
1674 | case '>': /* Numeric keypad */ | 1678 | case '>': /* Numeric keypad */ |
1675 | clr_kbd(vc, kbdapplic); | 1679 | clr_kbd(vc, kbdapplic); |
1676 | return; | 1680 | return; |
1677 | case '=': /* Appl. keypad */ | 1681 | case '=': /* Appl. keypad */ |
1678 | set_kbd(vc, kbdapplic); | 1682 | set_kbd(vc, kbdapplic); |
1679 | return; | 1683 | return; |
1680 | } | 1684 | } |
1681 | return; | 1685 | return; |
1682 | case ESnonstd: | 1686 | case ESnonstd: |
1683 | if (c=='P') { /* palette escape sequence */ | 1687 | if (c=='P') { /* palette escape sequence */ |
1684 | for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) | 1688 | for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) |
1685 | vc->vc_par[vc->vc_npar] = 0; | 1689 | vc->vc_par[vc->vc_npar] = 0; |
1686 | vc->vc_npar = 0; | 1690 | vc->vc_npar = 0; |
1687 | vc->vc_state = ESpalette; | 1691 | vc->vc_state = ESpalette; |
1688 | return; | 1692 | return; |
1689 | } else if (c=='R') { /* reset palette */ | 1693 | } else if (c=='R') { /* reset palette */ |
1690 | reset_palette(vc); | 1694 | reset_palette(vc); |
1691 | vc->vc_state = ESnormal; | 1695 | vc->vc_state = ESnormal; |
1692 | } else | 1696 | } else |
1693 | vc->vc_state = ESnormal; | 1697 | vc->vc_state = ESnormal; |
1694 | return; | 1698 | return; |
1695 | case ESpalette: | 1699 | case ESpalette: |
1696 | if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { | 1700 | if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { |
1697 | vc->vc_par[vc->vc_npar++] = (c > '9' ? (c & 0xDF) - 'A' + 10 : c - '0'); | 1701 | vc->vc_par[vc->vc_npar++] = (c > '9' ? (c & 0xDF) - 'A' + 10 : c - '0'); |
1698 | if (vc->vc_npar == 7) { | 1702 | if (vc->vc_npar == 7) { |
1699 | int i = vc->vc_par[0] * 3, j = 1; | 1703 | int i = vc->vc_par[0] * 3, j = 1; |
1700 | vc->vc_palette[i] = 16 * vc->vc_par[j++]; | 1704 | vc->vc_palette[i] = 16 * vc->vc_par[j++]; |
1701 | vc->vc_palette[i++] += vc->vc_par[j++]; | 1705 | vc->vc_palette[i++] += vc->vc_par[j++]; |
1702 | vc->vc_palette[i] = 16 * vc->vc_par[j++]; | 1706 | vc->vc_palette[i] = 16 * vc->vc_par[j++]; |
1703 | vc->vc_palette[i++] += vc->vc_par[j++]; | 1707 | vc->vc_palette[i++] += vc->vc_par[j++]; |
1704 | vc->vc_palette[i] = 16 * vc->vc_par[j++]; | 1708 | vc->vc_palette[i] = 16 * vc->vc_par[j++]; |
1705 | vc->vc_palette[i] += vc->vc_par[j]; | 1709 | vc->vc_palette[i] += vc->vc_par[j]; |
1706 | set_palette(vc); | 1710 | set_palette(vc); |
1707 | vc->vc_state = ESnormal; | 1711 | vc->vc_state = ESnormal; |
1708 | } | 1712 | } |
1709 | } else | 1713 | } else |
1710 | vc->vc_state = ESnormal; | 1714 | vc->vc_state = ESnormal; |
1711 | return; | 1715 | return; |
1712 | case ESsquare: | 1716 | case ESsquare: |
1713 | for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) | 1717 | for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++) |
1714 | vc->vc_par[vc->vc_npar] = 0; | 1718 | vc->vc_par[vc->vc_npar] = 0; |
1715 | vc->vc_npar = 0; | 1719 | vc->vc_npar = 0; |
1716 | vc->vc_state = ESgetpars; | 1720 | vc->vc_state = ESgetpars; |
1717 | if (c == '[') { /* Function key */ | 1721 | if (c == '[') { /* Function key */ |
1718 | vc->vc_state=ESfunckey; | 1722 | vc->vc_state=ESfunckey; |
1719 | return; | 1723 | return; |
1720 | } | 1724 | } |
1721 | vc->vc_ques = (c == '?'); | 1725 | vc->vc_ques = (c == '?'); |
1722 | if (vc->vc_ques) | 1726 | if (vc->vc_ques) |
1723 | return; | 1727 | return; |
1724 | case ESgetpars: | 1728 | case ESgetpars: |
1725 | if (c == ';' && vc->vc_npar < NPAR - 1) { | 1729 | if (c == ';' && vc->vc_npar < NPAR - 1) { |
1726 | vc->vc_npar++; | 1730 | vc->vc_npar++; |
1727 | return; | 1731 | return; |
1728 | } else if (c>='0' && c<='9') { | 1732 | } else if (c>='0' && c<='9') { |
1729 | vc->vc_par[vc->vc_npar] *= 10; | 1733 | vc->vc_par[vc->vc_npar] *= 10; |
1730 | vc->vc_par[vc->vc_npar] += c - '0'; | 1734 | vc->vc_par[vc->vc_npar] += c - '0'; |
1731 | return; | 1735 | return; |
1732 | } else | 1736 | } else |
1733 | vc->vc_state = ESgotpars; | 1737 | vc->vc_state = ESgotpars; |
1734 | case ESgotpars: | 1738 | case ESgotpars: |
1735 | vc->vc_state = ESnormal; | 1739 | vc->vc_state = ESnormal; |
1736 | switch(c) { | 1740 | switch(c) { |
1737 | case 'h': | 1741 | case 'h': |
1738 | set_mode(vc, 1); | 1742 | set_mode(vc, 1); |
1739 | return; | 1743 | return; |
1740 | case 'l': | 1744 | case 'l': |
1741 | set_mode(vc, 0); | 1745 | set_mode(vc, 0); |
1742 | return; | 1746 | return; |
1743 | case 'c': | 1747 | case 'c': |
1744 | if (vc->vc_ques) { | 1748 | if (vc->vc_ques) { |
1745 | if (vc->vc_par[0]) | 1749 | if (vc->vc_par[0]) |
1746 | vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16); | 1750 | vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16); |
1747 | else | 1751 | else |
1748 | vc->vc_cursor_type = CUR_DEFAULT; | 1752 | vc->vc_cursor_type = CUR_DEFAULT; |
1749 | return; | 1753 | return; |
1750 | } | 1754 | } |
1751 | break; | 1755 | break; |
1752 | case 'm': | 1756 | case 'm': |
1753 | if (vc->vc_ques) { | 1757 | if (vc->vc_ques) { |
1754 | clear_selection(); | 1758 | clear_selection(); |
1755 | if (vc->vc_par[0]) | 1759 | if (vc->vc_par[0]) |
1756 | vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1]; | 1760 | vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1]; |
1757 | else | 1761 | else |
1758 | vc->vc_complement_mask = vc->vc_s_complement_mask; | 1762 | vc->vc_complement_mask = vc->vc_s_complement_mask; |
1759 | return; | 1763 | return; |
1760 | } | 1764 | } |
1761 | break; | 1765 | break; |
1762 | case 'n': | 1766 | case 'n': |
1763 | if (!vc->vc_ques) { | 1767 | if (!vc->vc_ques) { |
1764 | if (vc->vc_par[0] == 5) | 1768 | if (vc->vc_par[0] == 5) |
1765 | status_report(tty); | 1769 | status_report(tty); |
1766 | else if (vc->vc_par[0] == 6) | 1770 | else if (vc->vc_par[0] == 6) |
1767 | cursor_report(vc, tty); | 1771 | cursor_report(vc, tty); |
1768 | } | 1772 | } |
1769 | return; | 1773 | return; |
1770 | } | 1774 | } |
1771 | if (vc->vc_ques) { | 1775 | if (vc->vc_ques) { |
1772 | vc->vc_ques = 0; | 1776 | vc->vc_ques = 0; |
1773 | return; | 1777 | return; |
1774 | } | 1778 | } |
1775 | switch(c) { | 1779 | switch(c) { |
1776 | case 'G': case '`': | 1780 | case 'G': case '`': |
1777 | if (vc->vc_par[0]) | 1781 | if (vc->vc_par[0]) |
1778 | vc->vc_par[0]--; | 1782 | vc->vc_par[0]--; |
1779 | gotoxy(vc, vc->vc_par[0], vc->vc_y); | 1783 | gotoxy(vc, vc->vc_par[0], vc->vc_y); |
1780 | return; | 1784 | return; |
1781 | case 'A': | 1785 | case 'A': |
1782 | if (!vc->vc_par[0]) | 1786 | if (!vc->vc_par[0]) |
1783 | vc->vc_par[0]++; | 1787 | vc->vc_par[0]++; |
1784 | gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]); | 1788 | gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]); |
1785 | return; | 1789 | return; |
1786 | case 'B': case 'e': | 1790 | case 'B': case 'e': |
1787 | if (!vc->vc_par[0]) | 1791 | if (!vc->vc_par[0]) |
1788 | vc->vc_par[0]++; | 1792 | vc->vc_par[0]++; |
1789 | gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]); | 1793 | gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]); |
1790 | return; | 1794 | return; |
1791 | case 'C': case 'a': | 1795 | case 'C': case 'a': |
1792 | if (!vc->vc_par[0]) | 1796 | if (!vc->vc_par[0]) |
1793 | vc->vc_par[0]++; | 1797 | vc->vc_par[0]++; |
1794 | gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y); | 1798 | gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y); |
1795 | return; | 1799 | return; |
1796 | case 'D': | 1800 | case 'D': |
1797 | if (!vc->vc_par[0]) | 1801 | if (!vc->vc_par[0]) |
1798 | vc->vc_par[0]++; | 1802 | vc->vc_par[0]++; |
1799 | gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y); | 1803 | gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y); |
1800 | return; | 1804 | return; |
1801 | case 'E': | 1805 | case 'E': |
1802 | if (!vc->vc_par[0]) | 1806 | if (!vc->vc_par[0]) |
1803 | vc->vc_par[0]++; | 1807 | vc->vc_par[0]++; |
1804 | gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]); | 1808 | gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]); |
1805 | return; | 1809 | return; |
1806 | case 'F': | 1810 | case 'F': |
1807 | if (!vc->vc_par[0]) | 1811 | if (!vc->vc_par[0]) |
1808 | vc->vc_par[0]++; | 1812 | vc->vc_par[0]++; |
1809 | gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]); | 1813 | gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]); |
1810 | return; | 1814 | return; |
1811 | case 'd': | 1815 | case 'd': |
1812 | if (vc->vc_par[0]) | 1816 | if (vc->vc_par[0]) |
1813 | vc->vc_par[0]--; | 1817 | vc->vc_par[0]--; |
1814 | gotoxay(vc, vc->vc_x ,vc->vc_par[0]); | 1818 | gotoxay(vc, vc->vc_x ,vc->vc_par[0]); |
1815 | return; | 1819 | return; |
1816 | case 'H': case 'f': | 1820 | case 'H': case 'f': |
1817 | if (vc->vc_par[0]) | 1821 | if (vc->vc_par[0]) |
1818 | vc->vc_par[0]--; | 1822 | vc->vc_par[0]--; |
1819 | if (vc->vc_par[1]) | 1823 | if (vc->vc_par[1]) |
1820 | vc->vc_par[1]--; | 1824 | vc->vc_par[1]--; |
1821 | gotoxay(vc, vc->vc_par[1], vc->vc_par[0]); | 1825 | gotoxay(vc, vc->vc_par[1], vc->vc_par[0]); |
1822 | return; | 1826 | return; |
1823 | case 'J': | 1827 | case 'J': |
1824 | csi_J(vc, vc->vc_par[0]); | 1828 | csi_J(vc, vc->vc_par[0]); |
1825 | return; | 1829 | return; |
1826 | case 'K': | 1830 | case 'K': |
1827 | csi_K(vc, vc->vc_par[0]); | 1831 | csi_K(vc, vc->vc_par[0]); |
1828 | return; | 1832 | return; |
1829 | case 'L': | 1833 | case 'L': |
1830 | csi_L(vc, vc->vc_par[0]); | 1834 | csi_L(vc, vc->vc_par[0]); |
1831 | return; | 1835 | return; |
1832 | case 'M': | 1836 | case 'M': |
1833 | csi_M(vc, vc->vc_par[0]); | 1837 | csi_M(vc, vc->vc_par[0]); |
1834 | return; | 1838 | return; |
1835 | case 'P': | 1839 | case 'P': |
1836 | csi_P(vc, vc->vc_par[0]); | 1840 | csi_P(vc, vc->vc_par[0]); |
1837 | return; | 1841 | return; |
1838 | case 'c': | 1842 | case 'c': |
1839 | if (!vc->vc_par[0]) | 1843 | if (!vc->vc_par[0]) |
1840 | respond_ID(tty); | 1844 | respond_ID(tty); |
1841 | return; | 1845 | return; |
1842 | case 'g': | 1846 | case 'g': |
1843 | if (!vc->vc_par[0]) | 1847 | if (!vc->vc_par[0]) |
1844 | vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31)); | 1848 | vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31)); |
1845 | else if (vc->vc_par[0] == 3) { | 1849 | else if (vc->vc_par[0] == 3) { |
1846 | vc->vc_tab_stop[0] = | 1850 | vc->vc_tab_stop[0] = |
1847 | vc->vc_tab_stop[1] = | 1851 | vc->vc_tab_stop[1] = |
1848 | vc->vc_tab_stop[2] = | 1852 | vc->vc_tab_stop[2] = |
1849 | vc->vc_tab_stop[3] = | 1853 | vc->vc_tab_stop[3] = |
1850 | vc->vc_tab_stop[4] = 0; | 1854 | vc->vc_tab_stop[4] = 0; |
1851 | } | 1855 | } |
1852 | return; | 1856 | return; |
1853 | case 'm': | 1857 | case 'm': |
1854 | csi_m(vc); | 1858 | csi_m(vc); |
1855 | return; | 1859 | return; |
1856 | case 'q': /* DECLL - but only 3 leds */ | 1860 | case 'q': /* DECLL - but only 3 leds */ |
1857 | /* map 0,1,2,3 to 0,1,2,4 */ | 1861 | /* map 0,1,2,3 to 0,1,2,4 */ |
1858 | if (vc->vc_par[0] < 4) | 1862 | if (vc->vc_par[0] < 4) |
1859 | setledstate(kbd_table + vc->vc_num, | 1863 | setledstate(kbd_table + vc->vc_num, |
1860 | (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); | 1864 | (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); |
1861 | return; | 1865 | return; |
1862 | case 'r': | 1866 | case 'r': |
1863 | if (!vc->vc_par[0]) | 1867 | if (!vc->vc_par[0]) |
1864 | vc->vc_par[0]++; | 1868 | vc->vc_par[0]++; |
1865 | if (!vc->vc_par[1]) | 1869 | if (!vc->vc_par[1]) |
1866 | vc->vc_par[1] = vc->vc_rows; | 1870 | vc->vc_par[1] = vc->vc_rows; |
1867 | /* Minimum allowed region is 2 lines */ | 1871 | /* Minimum allowed region is 2 lines */ |
1868 | if (vc->vc_par[0] < vc->vc_par[1] && | 1872 | if (vc->vc_par[0] < vc->vc_par[1] && |
1869 | vc->vc_par[1] <= vc->vc_rows) { | 1873 | vc->vc_par[1] <= vc->vc_rows) { |
1870 | vc->vc_top = vc->vc_par[0] - 1; | 1874 | vc->vc_top = vc->vc_par[0] - 1; |
1871 | vc->vc_bottom = vc->vc_par[1]; | 1875 | vc->vc_bottom = vc->vc_par[1]; |
1872 | gotoxay(vc, 0, 0); | 1876 | gotoxay(vc, 0, 0); |
1873 | } | 1877 | } |
1874 | return; | 1878 | return; |
1875 | case 's': | 1879 | case 's': |
1876 | save_cur(vc); | 1880 | save_cur(vc); |
1877 | return; | 1881 | return; |
1878 | case 'u': | 1882 | case 'u': |
1879 | restore_cur(vc); | 1883 | restore_cur(vc); |
1880 | return; | 1884 | return; |
1881 | case 'X': | 1885 | case 'X': |
1882 | csi_X(vc, vc->vc_par[0]); | 1886 | csi_X(vc, vc->vc_par[0]); |
1883 | return; | 1887 | return; |
1884 | case '@': | 1888 | case '@': |
1885 | csi_at(vc, vc->vc_par[0]); | 1889 | csi_at(vc, vc->vc_par[0]); |
1886 | return; | 1890 | return; |
1887 | case ']': /* setterm functions */ | 1891 | case ']': /* setterm functions */ |
1888 | setterm_command(vc); | 1892 | setterm_command(vc); |
1889 | return; | 1893 | return; |
1890 | } | 1894 | } |
1891 | return; | 1895 | return; |
1892 | case ESpercent: | 1896 | case ESpercent: |
1893 | vc->vc_state = ESnormal; | 1897 | vc->vc_state = ESnormal; |
1894 | switch (c) { | 1898 | switch (c) { |
1895 | case '@': /* defined in ISO 2022 */ | 1899 | case '@': /* defined in ISO 2022 */ |
1896 | vc->vc_utf = 0; | 1900 | vc->vc_utf = 0; |
1897 | return; | 1901 | return; |
1898 | case 'G': /* prelim official escape code */ | 1902 | case 'G': /* prelim official escape code */ |
1899 | case '8': /* retained for compatibility */ | 1903 | case '8': /* retained for compatibility */ |
1900 | vc->vc_utf = 1; | 1904 | vc->vc_utf = 1; |
1901 | return; | 1905 | return; |
1902 | } | 1906 | } |
1903 | return; | 1907 | return; |
1904 | case ESfunckey: | 1908 | case ESfunckey: |
1905 | vc->vc_state = ESnormal; | 1909 | vc->vc_state = ESnormal; |
1906 | return; | 1910 | return; |
1907 | case EShash: | 1911 | case EShash: |
1908 | vc->vc_state = ESnormal; | 1912 | vc->vc_state = ESnormal; |
1909 | if (c == '8') { | 1913 | if (c == '8') { |
1910 | /* DEC screen alignment test. kludge :-) */ | 1914 | /* DEC screen alignment test. kludge :-) */ |
1911 | vc->vc_video_erase_char = | 1915 | vc->vc_video_erase_char = |
1912 | (vc->vc_video_erase_char & 0xff00) | 'E'; | 1916 | (vc->vc_video_erase_char & 0xff00) | 'E'; |
1913 | csi_J(vc, 2); | 1917 | csi_J(vc, 2); |
1914 | vc->vc_video_erase_char = | 1918 | vc->vc_video_erase_char = |
1915 | (vc->vc_video_erase_char & 0xff00) | ' '; | 1919 | (vc->vc_video_erase_char & 0xff00) | ' '; |
1916 | do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); | 1920 | do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); |
1917 | } | 1921 | } |
1918 | return; | 1922 | return; |
1919 | case ESsetG0: | 1923 | case ESsetG0: |
1920 | if (c == '0') | 1924 | if (c == '0') |
1921 | vc->vc_G0_charset = GRAF_MAP; | 1925 | vc->vc_G0_charset = GRAF_MAP; |
1922 | else if (c == 'B') | 1926 | else if (c == 'B') |
1923 | vc->vc_G0_charset = LAT1_MAP; | 1927 | vc->vc_G0_charset = LAT1_MAP; |
1924 | else if (c == 'U') | 1928 | else if (c == 'U') |
1925 | vc->vc_G0_charset = IBMPC_MAP; | 1929 | vc->vc_G0_charset = IBMPC_MAP; |
1926 | else if (c == 'K') | 1930 | else if (c == 'K') |
1927 | vc->vc_G0_charset = USER_MAP; | 1931 | vc->vc_G0_charset = USER_MAP; |
1928 | if (vc->vc_charset == 0) | 1932 | if (vc->vc_charset == 0) |
1929 | vc->vc_translate = set_translate(vc->vc_G0_charset, vc); | 1933 | vc->vc_translate = set_translate(vc->vc_G0_charset, vc); |
1930 | vc->vc_state = ESnormal; | 1934 | vc->vc_state = ESnormal; |
1931 | return; | 1935 | return; |
1932 | case ESsetG1: | 1936 | case ESsetG1: |
1933 | if (c == '0') | 1937 | if (c == '0') |
1934 | vc->vc_G1_charset = GRAF_MAP; | 1938 | vc->vc_G1_charset = GRAF_MAP; |
1935 | else if (c == 'B') | 1939 | else if (c == 'B') |
1936 | vc->vc_G1_charset = LAT1_MAP; | 1940 | vc->vc_G1_charset = LAT1_MAP; |
1937 | else if (c == 'U') | 1941 | else if (c == 'U') |
1938 | vc->vc_G1_charset = IBMPC_MAP; | 1942 | vc->vc_G1_charset = IBMPC_MAP; |
1939 | else if (c == 'K') | 1943 | else if (c == 'K') |
1940 | vc->vc_G1_charset = USER_MAP; | 1944 | vc->vc_G1_charset = USER_MAP; |
1941 | if (vc->vc_charset == 1) | 1945 | if (vc->vc_charset == 1) |
1942 | vc->vc_translate = set_translate(vc->vc_G1_charset, vc); | 1946 | vc->vc_translate = set_translate(vc->vc_G1_charset, vc); |
1943 | vc->vc_state = ESnormal; | 1947 | vc->vc_state = ESnormal; |
1944 | return; | 1948 | return; |
1945 | default: | 1949 | default: |
1946 | vc->vc_state = ESnormal; | 1950 | vc->vc_state = ESnormal; |
1947 | } | 1951 | } |
1948 | } | 1952 | } |
1949 | 1953 | ||
1950 | /* This is a temporary buffer used to prepare a tty console write | 1954 | /* This is a temporary buffer used to prepare a tty console write |
1951 | * so that we can easily avoid touching user space while holding the | 1955 | * so that we can easily avoid touching user space while holding the |
1952 | * console spinlock. It is allocated in con_init and is shared by | 1956 | * console spinlock. It is allocated in con_init and is shared by |
1953 | * this code and the vc_screen read/write tty calls. | 1957 | * this code and the vc_screen read/write tty calls. |
1954 | * | 1958 | * |
1955 | * We have to allocate this statically in the kernel data section | 1959 | * We have to allocate this statically in the kernel data section |
1956 | * since console_init (and thus con_init) are called before any | 1960 | * since console_init (and thus con_init) are called before any |
1957 | * kernel memory allocation is available. | 1961 | * kernel memory allocation is available. |
1958 | */ | 1962 | */ |
1959 | char con_buf[CON_BUF_SIZE]; | 1963 | char con_buf[CON_BUF_SIZE]; |
1960 | DEFINE_MUTEX(con_buf_mtx); | 1964 | DEFINE_MUTEX(con_buf_mtx); |
1961 | 1965 | ||
1962 | /* is_double_width() is based on the wcwidth() implementation by | 1966 | /* is_double_width() is based on the wcwidth() implementation by |
1963 | * Markus Kuhn -- 2007-05-26 (Unicode 5.0) | 1967 | * Markus Kuhn -- 2007-05-26 (Unicode 5.0) |
1964 | * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c | 1968 | * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c |
1965 | */ | 1969 | */ |
1966 | struct interval { | 1970 | struct interval { |
1967 | uint32_t first; | 1971 | uint32_t first; |
1968 | uint32_t last; | 1972 | uint32_t last; |
1969 | }; | 1973 | }; |
1970 | 1974 | ||
1971 | static int bisearch(uint32_t ucs, const struct interval *table, int max) | 1975 | static int bisearch(uint32_t ucs, const struct interval *table, int max) |
1972 | { | 1976 | { |
1973 | int min = 0; | 1977 | int min = 0; |
1974 | int mid; | 1978 | int mid; |
1975 | 1979 | ||
1976 | if (ucs < table[0].first || ucs > table[max].last) | 1980 | if (ucs < table[0].first || ucs > table[max].last) |
1977 | return 0; | 1981 | return 0; |
1978 | while (max >= min) { | 1982 | while (max >= min) { |
1979 | mid = (min + max) / 2; | 1983 | mid = (min + max) / 2; |
1980 | if (ucs > table[mid].last) | 1984 | if (ucs > table[mid].last) |
1981 | min = mid + 1; | 1985 | min = mid + 1; |
1982 | else if (ucs < table[mid].first) | 1986 | else if (ucs < table[mid].first) |
1983 | max = mid - 1; | 1987 | max = mid - 1; |
1984 | else | 1988 | else |
1985 | return 1; | 1989 | return 1; |
1986 | } | 1990 | } |
1987 | return 0; | 1991 | return 0; |
1988 | } | 1992 | } |
1989 | 1993 | ||
1990 | static int is_double_width(uint32_t ucs) | 1994 | static int is_double_width(uint32_t ucs) |
1991 | { | 1995 | { |
1992 | static const struct interval double_width[] = { | 1996 | static const struct interval double_width[] = { |
1993 | { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E }, | 1997 | { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E }, |
1994 | { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF }, | 1998 | { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF }, |
1995 | { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, | 1999 | { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, |
1996 | { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD } | 2000 | { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD } |
1997 | }; | 2001 | }; |
1998 | return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1); | 2002 | return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1); |
1999 | } | 2003 | } |
2000 | 2004 | ||
2001 | /* acquires console_sem */ | 2005 | /* acquires console_sem */ |
2002 | static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) | 2006 | static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) |
2003 | { | 2007 | { |
2004 | #ifdef VT_BUF_VRAM_ONLY | 2008 | #ifdef VT_BUF_VRAM_ONLY |
2005 | #define FLUSH do { } while(0); | 2009 | #define FLUSH do { } while(0); |
2006 | #else | 2010 | #else |
2007 | #define FLUSH if (draw_x >= 0) { \ | 2011 | #define FLUSH if (draw_x >= 0) { \ |
2008 | vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \ | 2012 | vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \ |
2009 | draw_x = -1; \ | 2013 | draw_x = -1; \ |
2010 | } | 2014 | } |
2011 | #endif | 2015 | #endif |
2012 | 2016 | ||
2013 | int c, tc, ok, n = 0, draw_x = -1; | 2017 | int c, tc, ok, n = 0, draw_x = -1; |
2014 | unsigned int currcons; | 2018 | unsigned int currcons; |
2015 | unsigned long draw_from = 0, draw_to = 0; | 2019 | unsigned long draw_from = 0, draw_to = 0; |
2016 | struct vc_data *vc; | 2020 | struct vc_data *vc; |
2017 | unsigned char vc_attr; | 2021 | unsigned char vc_attr; |
2018 | uint8_t rescan; | 2022 | uint8_t rescan; |
2019 | uint8_t inverse; | 2023 | uint8_t inverse; |
2020 | uint8_t width; | 2024 | uint8_t width; |
2021 | u16 himask, charmask; | 2025 | u16 himask, charmask; |
2022 | const unsigned char *orig_buf = NULL; | 2026 | const unsigned char *orig_buf = NULL; |
2023 | int orig_count; | 2027 | int orig_count; |
2024 | 2028 | ||
2025 | if (in_interrupt()) | 2029 | if (in_interrupt()) |
2026 | return count; | 2030 | return count; |
2027 | 2031 | ||
2028 | might_sleep(); | 2032 | might_sleep(); |
2029 | 2033 | ||
2030 | acquire_console_sem(); | 2034 | acquire_console_sem(); |
2031 | vc = tty->driver_data; | 2035 | vc = tty->driver_data; |
2032 | if (vc == NULL) { | 2036 | if (vc == NULL) { |
2033 | printk(KERN_ERR "vt: argh, driver_data is NULL !\n"); | 2037 | printk(KERN_ERR "vt: argh, driver_data is NULL !\n"); |
2034 | release_console_sem(); | 2038 | release_console_sem(); |
2035 | return 0; | 2039 | return 0; |
2036 | } | 2040 | } |
2037 | 2041 | ||
2038 | currcons = vc->vc_num; | 2042 | currcons = vc->vc_num; |
2039 | if (!vc_cons_allocated(currcons)) { | 2043 | if (!vc_cons_allocated(currcons)) { |
2040 | /* could this happen? */ | 2044 | /* could this happen? */ |
2041 | static int error = 0; | 2045 | static int error = 0; |
2042 | if (!error) { | 2046 | if (!error) { |
2043 | error = 1; | 2047 | error = 1; |
2044 | printk("con_write: tty %d not allocated\n", currcons+1); | 2048 | printk("con_write: tty %d not allocated\n", currcons+1); |
2045 | } | 2049 | } |
2046 | release_console_sem(); | 2050 | release_console_sem(); |
2047 | return 0; | 2051 | return 0; |
2048 | } | 2052 | } |
2049 | release_console_sem(); | 2053 | release_console_sem(); |
2050 | 2054 | ||
2051 | orig_buf = buf; | 2055 | orig_buf = buf; |
2052 | orig_count = count; | 2056 | orig_count = count; |
2053 | 2057 | ||
2054 | /* At this point 'buf' is guaranteed to be a kernel buffer | 2058 | /* At this point 'buf' is guaranteed to be a kernel buffer |
2055 | * and therefore no access to userspace (and therefore sleeping) | 2059 | * and therefore no access to userspace (and therefore sleeping) |
2056 | * will be needed. The con_buf_mtx serializes all tty based | 2060 | * will be needed. The con_buf_mtx serializes all tty based |
2057 | * console rendering and vcs write/read operations. We hold | 2061 | * console rendering and vcs write/read operations. We hold |
2058 | * the console spinlock during the entire write. | 2062 | * the console spinlock during the entire write. |
2059 | */ | 2063 | */ |
2060 | 2064 | ||
2061 | acquire_console_sem(); | 2065 | acquire_console_sem(); |
2062 | 2066 | ||
2063 | vc = tty->driver_data; | 2067 | vc = tty->driver_data; |
2064 | if (vc == NULL) { | 2068 | if (vc == NULL) { |
2065 | printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n"); | 2069 | printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n"); |
2066 | release_console_sem(); | 2070 | release_console_sem(); |
2067 | goto out; | 2071 | goto out; |
2068 | } | 2072 | } |
2069 | 2073 | ||
2070 | himask = vc->vc_hi_font_mask; | 2074 | himask = vc->vc_hi_font_mask; |
2071 | charmask = himask ? 0x1ff : 0xff; | 2075 | charmask = himask ? 0x1ff : 0xff; |
2072 | 2076 | ||
2073 | /* undraw cursor first */ | 2077 | /* undraw cursor first */ |
2074 | if (IS_FG(vc)) | 2078 | if (IS_FG(vc)) |
2075 | hide_cursor(vc); | 2079 | hide_cursor(vc); |
2076 | 2080 | ||
2077 | while (!tty->stopped && count) { | 2081 | while (!tty->stopped && count) { |
2078 | int orig = *buf; | 2082 | int orig = *buf; |
2079 | c = orig; | 2083 | c = orig; |
2080 | buf++; | 2084 | buf++; |
2081 | n++; | 2085 | n++; |
2082 | count--; | 2086 | count--; |
2083 | rescan = 0; | 2087 | rescan = 0; |
2084 | inverse = 0; | 2088 | inverse = 0; |
2085 | width = 1; | 2089 | width = 1; |
2086 | 2090 | ||
2087 | /* Do no translation at all in control states */ | 2091 | /* Do no translation at all in control states */ |
2088 | if (vc->vc_state != ESnormal) { | 2092 | if (vc->vc_state != ESnormal) { |
2089 | tc = c; | 2093 | tc = c; |
2090 | } else if (vc->vc_utf && !vc->vc_disp_ctrl) { | 2094 | } else if (vc->vc_utf && !vc->vc_disp_ctrl) { |
2091 | /* Combine UTF-8 into Unicode in vc_utf_char. | 2095 | /* Combine UTF-8 into Unicode in vc_utf_char. |
2092 | * vc_utf_count is the number of continuation bytes still | 2096 | * vc_utf_count is the number of continuation bytes still |
2093 | * expected to arrive. | 2097 | * expected to arrive. |
2094 | * vc_npar is the number of continuation bytes arrived so | 2098 | * vc_npar is the number of continuation bytes arrived so |
2095 | * far | 2099 | * far |
2096 | */ | 2100 | */ |
2097 | rescan_last_byte: | 2101 | rescan_last_byte: |
2098 | if ((c & 0xc0) == 0x80) { | 2102 | if ((c & 0xc0) == 0x80) { |
2099 | /* Continuation byte received */ | 2103 | /* Continuation byte received */ |
2100 | static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff }; | 2104 | static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff }; |
2101 | if (vc->vc_utf_count) { | 2105 | if (vc->vc_utf_count) { |
2102 | vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); | 2106 | vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); |
2103 | vc->vc_npar++; | 2107 | vc->vc_npar++; |
2104 | if (--vc->vc_utf_count) { | 2108 | if (--vc->vc_utf_count) { |
2105 | /* Still need some bytes */ | 2109 | /* Still need some bytes */ |
2106 | continue; | 2110 | continue; |
2107 | } | 2111 | } |
2108 | /* Got a whole character */ | 2112 | /* Got a whole character */ |
2109 | c = vc->vc_utf_char; | 2113 | c = vc->vc_utf_char; |
2110 | /* Reject overlong sequences */ | 2114 | /* Reject overlong sequences */ |
2111 | if (c <= utf8_length_changes[vc->vc_npar - 1] || | 2115 | if (c <= utf8_length_changes[vc->vc_npar - 1] || |
2112 | c > utf8_length_changes[vc->vc_npar]) | 2116 | c > utf8_length_changes[vc->vc_npar]) |
2113 | c = 0xfffd; | 2117 | c = 0xfffd; |
2114 | } else { | 2118 | } else { |
2115 | /* Unexpected continuation byte */ | 2119 | /* Unexpected continuation byte */ |
2116 | vc->vc_utf_count = 0; | 2120 | vc->vc_utf_count = 0; |
2117 | c = 0xfffd; | 2121 | c = 0xfffd; |
2118 | } | 2122 | } |
2119 | } else { | 2123 | } else { |
2120 | /* Single ASCII byte or first byte of a sequence received */ | 2124 | /* Single ASCII byte or first byte of a sequence received */ |
2121 | if (vc->vc_utf_count) { | 2125 | if (vc->vc_utf_count) { |
2122 | /* Continuation byte expected */ | 2126 | /* Continuation byte expected */ |
2123 | rescan = 1; | 2127 | rescan = 1; |
2124 | vc->vc_utf_count = 0; | 2128 | vc->vc_utf_count = 0; |
2125 | c = 0xfffd; | 2129 | c = 0xfffd; |
2126 | } else if (c > 0x7f) { | 2130 | } else if (c > 0x7f) { |
2127 | /* First byte of a multibyte sequence received */ | 2131 | /* First byte of a multibyte sequence received */ |
2128 | vc->vc_npar = 0; | 2132 | vc->vc_npar = 0; |
2129 | if ((c & 0xe0) == 0xc0) { | 2133 | if ((c & 0xe0) == 0xc0) { |
2130 | vc->vc_utf_count = 1; | 2134 | vc->vc_utf_count = 1; |
2131 | vc->vc_utf_char = (c & 0x1f); | 2135 | vc->vc_utf_char = (c & 0x1f); |
2132 | } else if ((c & 0xf0) == 0xe0) { | 2136 | } else if ((c & 0xf0) == 0xe0) { |
2133 | vc->vc_utf_count = 2; | 2137 | vc->vc_utf_count = 2; |
2134 | vc->vc_utf_char = (c & 0x0f); | 2138 | vc->vc_utf_char = (c & 0x0f); |
2135 | } else if ((c & 0xf8) == 0xf0) { | 2139 | } else if ((c & 0xf8) == 0xf0) { |
2136 | vc->vc_utf_count = 3; | 2140 | vc->vc_utf_count = 3; |
2137 | vc->vc_utf_char = (c & 0x07); | 2141 | vc->vc_utf_char = (c & 0x07); |
2138 | } else if ((c & 0xfc) == 0xf8) { | 2142 | } else if ((c & 0xfc) == 0xf8) { |
2139 | vc->vc_utf_count = 4; | 2143 | vc->vc_utf_count = 4; |
2140 | vc->vc_utf_char = (c & 0x03); | 2144 | vc->vc_utf_char = (c & 0x03); |
2141 | } else if ((c & 0xfe) == 0xfc) { | 2145 | } else if ((c & 0xfe) == 0xfc) { |
2142 | vc->vc_utf_count = 5; | 2146 | vc->vc_utf_count = 5; |
2143 | vc->vc_utf_char = (c & 0x01); | 2147 | vc->vc_utf_char = (c & 0x01); |
2144 | } else { | 2148 | } else { |
2145 | /* 254 and 255 are invalid */ | 2149 | /* 254 and 255 are invalid */ |
2146 | c = 0xfffd; | 2150 | c = 0xfffd; |
2147 | } | 2151 | } |
2148 | if (vc->vc_utf_count) { | 2152 | if (vc->vc_utf_count) { |
2149 | /* Still need some bytes */ | 2153 | /* Still need some bytes */ |
2150 | continue; | 2154 | continue; |
2151 | } | 2155 | } |
2152 | } | 2156 | } |
2153 | /* Nothing to do if an ASCII byte was received */ | 2157 | /* Nothing to do if an ASCII byte was received */ |
2154 | } | 2158 | } |
2155 | /* End of UTF-8 decoding. */ | 2159 | /* End of UTF-8 decoding. */ |
2156 | /* c is the received character, or U+FFFD for invalid sequences. */ | 2160 | /* c is the received character, or U+FFFD for invalid sequences. */ |
2157 | /* Replace invalid Unicode code points with U+FFFD too */ | 2161 | /* Replace invalid Unicode code points with U+FFFD too */ |
2158 | if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) | 2162 | if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) |
2159 | c = 0xfffd; | 2163 | c = 0xfffd; |
2160 | tc = c; | 2164 | tc = c; |
2161 | } else { /* no utf or alternate charset mode */ | 2165 | } else { /* no utf or alternate charset mode */ |
2162 | tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; | 2166 | tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; |
2163 | } | 2167 | } |
2164 | 2168 | ||
2165 | /* If the original code was a control character we | 2169 | /* If the original code was a control character we |
2166 | * only allow a glyph to be displayed if the code is | 2170 | * only allow a glyph to be displayed if the code is |
2167 | * not normally used (such as for cursor movement) or | 2171 | * not normally used (such as for cursor movement) or |
2168 | * if the disp_ctrl mode has been explicitly enabled. | 2172 | * if the disp_ctrl mode has been explicitly enabled. |
2169 | * Certain characters (as given by the CTRL_ALWAYS | 2173 | * Certain characters (as given by the CTRL_ALWAYS |
2170 | * bitmap) are always displayed as control characters, | 2174 | * bitmap) are always displayed as control characters, |
2171 | * as the console would be pretty useless without | 2175 | * as the console would be pretty useless without |
2172 | * them; to display an arbitrary font position use the | 2176 | * them; to display an arbitrary font position use the |
2173 | * direct-to-font zone in UTF-8 mode. | 2177 | * direct-to-font zone in UTF-8 mode. |
2174 | */ | 2178 | */ |
2175 | ok = tc && (c >= 32 || | 2179 | ok = tc && (c >= 32 || |
2176 | !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 : | 2180 | !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 : |
2177 | vc->vc_utf || ((CTRL_ACTION >> c) & 1))) | 2181 | vc->vc_utf || ((CTRL_ACTION >> c) & 1))) |
2178 | && (c != 127 || vc->vc_disp_ctrl) | 2182 | && (c != 127 || vc->vc_disp_ctrl) |
2179 | && (c != 128+27); | 2183 | && (c != 128+27); |
2180 | 2184 | ||
2181 | if (vc->vc_state == ESnormal && ok) { | 2185 | if (vc->vc_state == ESnormal && ok) { |
2182 | if (vc->vc_utf && !vc->vc_disp_ctrl) { | 2186 | if (vc->vc_utf && !vc->vc_disp_ctrl) { |
2183 | if (is_double_width(c)) | 2187 | if (is_double_width(c)) |
2184 | width = 2; | 2188 | width = 2; |
2185 | } | 2189 | } |
2186 | /* Now try to find out how to display it */ | 2190 | /* Now try to find out how to display it */ |
2187 | tc = conv_uni_to_pc(vc, tc); | 2191 | tc = conv_uni_to_pc(vc, tc); |
2188 | if (tc & ~charmask) { | 2192 | if (tc & ~charmask) { |
2189 | if (tc == -1 || tc == -2) { | 2193 | if (tc == -1 || tc == -2) { |
2190 | continue; /* nothing to display */ | 2194 | continue; /* nothing to display */ |
2191 | } | 2195 | } |
2192 | /* Glyph not found */ | 2196 | /* Glyph not found */ |
2193 | if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) { | 2197 | if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) { |
2194 | /* In legacy mode use the glyph we get by a 1:1 mapping. | 2198 | /* In legacy mode use the glyph we get by a 1:1 mapping. |
2195 | This would make absolutely no sense with Unicode in mind, | 2199 | This would make absolutely no sense with Unicode in mind, |
2196 | but do this for ASCII characters since a font may lack | 2200 | but do this for ASCII characters since a font may lack |
2197 | Unicode mapping info and we don't want to end up with | 2201 | Unicode mapping info and we don't want to end up with |
2198 | having question marks only. */ | 2202 | having question marks only. */ |
2199 | tc = c; | 2203 | tc = c; |
2200 | } else { | 2204 | } else { |
2201 | /* Display U+FFFD. If it's not found, display an inverse question mark. */ | 2205 | /* Display U+FFFD. If it's not found, display an inverse question mark. */ |
2202 | tc = conv_uni_to_pc(vc, 0xfffd); | 2206 | tc = conv_uni_to_pc(vc, 0xfffd); |
2203 | if (tc < 0) { | 2207 | if (tc < 0) { |
2204 | inverse = 1; | 2208 | inverse = 1; |
2205 | tc = conv_uni_to_pc(vc, '?'); | 2209 | tc = conv_uni_to_pc(vc, '?'); |
2206 | if (tc < 0) tc = '?'; | 2210 | if (tc < 0) tc = '?'; |
2207 | } | 2211 | } |
2208 | } | 2212 | } |
2209 | } | 2213 | } |
2210 | 2214 | ||
2211 | if (!inverse) { | 2215 | if (!inverse) { |
2212 | vc_attr = vc->vc_attr; | 2216 | vc_attr = vc->vc_attr; |
2213 | } else { | 2217 | } else { |
2214 | /* invert vc_attr */ | 2218 | /* invert vc_attr */ |
2215 | if (!vc->vc_can_do_color) { | 2219 | if (!vc->vc_can_do_color) { |
2216 | vc_attr = (vc->vc_attr) ^ 0x08; | 2220 | vc_attr = (vc->vc_attr) ^ 0x08; |
2217 | } else if (vc->vc_hi_font_mask == 0x100) { | 2221 | } else if (vc->vc_hi_font_mask == 0x100) { |
2218 | vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4); | 2222 | vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4); |
2219 | } else { | 2223 | } else { |
2220 | vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4); | 2224 | vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4); |
2221 | } | 2225 | } |
2222 | FLUSH | 2226 | FLUSH |
2223 | } | 2227 | } |
2224 | 2228 | ||
2225 | while (1) { | 2229 | while (1) { |
2226 | if (vc->vc_need_wrap || vc->vc_decim) | 2230 | if (vc->vc_need_wrap || vc->vc_decim) |
2227 | FLUSH | 2231 | FLUSH |
2228 | if (vc->vc_need_wrap) { | 2232 | if (vc->vc_need_wrap) { |
2229 | cr(vc); | 2233 | cr(vc); |
2230 | lf(vc); | 2234 | lf(vc); |
2231 | } | 2235 | } |
2232 | if (vc->vc_decim) | 2236 | if (vc->vc_decim) |
2233 | insert_char(vc, 1); | 2237 | insert_char(vc, 1); |
2234 | scr_writew(himask ? | 2238 | scr_writew(himask ? |
2235 | ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : | 2239 | ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : |
2236 | (vc_attr << 8) + tc, | 2240 | (vc_attr << 8) + tc, |
2237 | (u16 *) vc->vc_pos); | 2241 | (u16 *) vc->vc_pos); |
2238 | if (DO_UPDATE(vc) && draw_x < 0) { | 2242 | if (DO_UPDATE(vc) && draw_x < 0) { |
2239 | draw_x = vc->vc_x; | 2243 | draw_x = vc->vc_x; |
2240 | draw_from = vc->vc_pos; | 2244 | draw_from = vc->vc_pos; |
2241 | } | 2245 | } |
2242 | if (vc->vc_x == vc->vc_cols - 1) { | 2246 | if (vc->vc_x == vc->vc_cols - 1) { |
2243 | vc->vc_need_wrap = vc->vc_decawm; | 2247 | vc->vc_need_wrap = vc->vc_decawm; |
2244 | draw_to = vc->vc_pos + 2; | 2248 | draw_to = vc->vc_pos + 2; |
2245 | } else { | 2249 | } else { |
2246 | vc->vc_x++; | 2250 | vc->vc_x++; |
2247 | draw_to = (vc->vc_pos += 2); | 2251 | draw_to = (vc->vc_pos += 2); |
2248 | } | 2252 | } |
2249 | 2253 | ||
2250 | if (!--width) break; | 2254 | if (!--width) break; |
2251 | 2255 | ||
2252 | tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ | 2256 | tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ |
2253 | if (tc < 0) tc = ' '; | 2257 | if (tc < 0) tc = ' '; |
2254 | } | 2258 | } |
2255 | 2259 | ||
2256 | if (inverse) { | 2260 | if (inverse) { |
2257 | FLUSH | 2261 | FLUSH |
2258 | } | 2262 | } |
2259 | 2263 | ||
2260 | if (rescan) { | 2264 | if (rescan) { |
2261 | rescan = 0; | 2265 | rescan = 0; |
2262 | inverse = 0; | 2266 | inverse = 0; |
2263 | width = 1; | 2267 | width = 1; |
2264 | c = orig; | 2268 | c = orig; |
2265 | goto rescan_last_byte; | 2269 | goto rescan_last_byte; |
2266 | } | 2270 | } |
2267 | continue; | 2271 | continue; |
2268 | } | 2272 | } |
2269 | FLUSH | 2273 | FLUSH |
2270 | do_con_trol(tty, vc, orig); | 2274 | do_con_trol(tty, vc, orig); |
2271 | } | 2275 | } |
2272 | FLUSH | 2276 | FLUSH |
2273 | console_conditional_schedule(); | 2277 | console_conditional_schedule(); |
2274 | release_console_sem(); | 2278 | release_console_sem(); |
2275 | 2279 | ||
2276 | out: | 2280 | out: |
2277 | return n; | 2281 | return n; |
2278 | #undef FLUSH | 2282 | #undef FLUSH |
2279 | } | 2283 | } |
2280 | 2284 | ||
2281 | /* | 2285 | /* |
2282 | * This is the console switching callback. | 2286 | * This is the console switching callback. |
2283 | * | 2287 | * |
2284 | * Doing console switching in a process context allows | 2288 | * Doing console switching in a process context allows |
2285 | * us to do the switches asynchronously (needed when we want | 2289 | * us to do the switches asynchronously (needed when we want |
2286 | * to switch due to a keyboard interrupt). Synchronization | 2290 | * to switch due to a keyboard interrupt). Synchronization |
2287 | * with other console code and prevention of re-entrancy is | 2291 | * with other console code and prevention of re-entrancy is |
2288 | * ensured with console_sem. | 2292 | * ensured with console_sem. |
2289 | */ | 2293 | */ |
2290 | static void console_callback(struct work_struct *ignored) | 2294 | static void console_callback(struct work_struct *ignored) |
2291 | { | 2295 | { |
2292 | acquire_console_sem(); | 2296 | acquire_console_sem(); |
2293 | 2297 | ||
2294 | if (want_console >= 0) { | 2298 | if (want_console >= 0) { |
2295 | if (want_console != fg_console && | 2299 | if (want_console != fg_console && |
2296 | vc_cons_allocated(want_console)) { | 2300 | vc_cons_allocated(want_console)) { |
2297 | hide_cursor(vc_cons[fg_console].d); | 2301 | hide_cursor(vc_cons[fg_console].d); |
2298 | change_console(vc_cons[want_console].d); | 2302 | change_console(vc_cons[want_console].d); |
2299 | /* we only changed when the console had already | 2303 | /* we only changed when the console had already |
2300 | been allocated - a new console is not created | 2304 | been allocated - a new console is not created |
2301 | in an interrupt routine */ | 2305 | in an interrupt routine */ |
2302 | } | 2306 | } |
2303 | want_console = -1; | 2307 | want_console = -1; |
2304 | } | 2308 | } |
2305 | if (do_poke_blanked_console) { /* do not unblank for a LED change */ | 2309 | if (do_poke_blanked_console) { /* do not unblank for a LED change */ |
2306 | do_poke_blanked_console = 0; | 2310 | do_poke_blanked_console = 0; |
2307 | poke_blanked_console(); | 2311 | poke_blanked_console(); |
2308 | } | 2312 | } |
2309 | if (scrollback_delta) { | 2313 | if (scrollback_delta) { |
2310 | struct vc_data *vc = vc_cons[fg_console].d; | 2314 | struct vc_data *vc = vc_cons[fg_console].d; |
2311 | clear_selection(); | 2315 | clear_selection(); |
2312 | if (vc->vc_mode == KD_TEXT) | 2316 | if (vc->vc_mode == KD_TEXT) |
2313 | vc->vc_sw->con_scrolldelta(vc, scrollback_delta); | 2317 | vc->vc_sw->con_scrolldelta(vc, scrollback_delta); |
2314 | scrollback_delta = 0; | 2318 | scrollback_delta = 0; |
2315 | } | 2319 | } |
2316 | if (blank_timer_expired) { | 2320 | if (blank_timer_expired) { |
2317 | do_blank_screen(0); | 2321 | do_blank_screen(0); |
2318 | blank_timer_expired = 0; | 2322 | blank_timer_expired = 0; |
2319 | } | 2323 | } |
2320 | 2324 | ||
2321 | release_console_sem(); | 2325 | release_console_sem(); |
2322 | } | 2326 | } |
2323 | 2327 | ||
2324 | int set_console(int nr) | 2328 | int set_console(int nr) |
2325 | { | 2329 | { |
2326 | struct vc_data *vc = vc_cons[fg_console].d; | 2330 | struct vc_data *vc = vc_cons[fg_console].d; |
2327 | 2331 | ||
2328 | if (!vc_cons_allocated(nr) || vt_dont_switch || | 2332 | if (!vc_cons_allocated(nr) || vt_dont_switch || |
2329 | (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) { | 2333 | (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) { |
2330 | 2334 | ||
2331 | /* | 2335 | /* |
2332 | * Console switch will fail in console_callback() or | 2336 | * Console switch will fail in console_callback() or |
2333 | * change_console() so there is no point scheduling | 2337 | * change_console() so there is no point scheduling |
2334 | * the callback | 2338 | * the callback |
2335 | * | 2339 | * |
2336 | * Existing set_console() users don't check the return | 2340 | * Existing set_console() users don't check the return |
2337 | * value so this shouldn't break anything | 2341 | * value so this shouldn't break anything |
2338 | */ | 2342 | */ |
2339 | return -EINVAL; | 2343 | return -EINVAL; |
2340 | } | 2344 | } |
2341 | 2345 | ||
2342 | want_console = nr; | 2346 | want_console = nr; |
2343 | schedule_console_callback(); | 2347 | schedule_console_callback(); |
2344 | 2348 | ||
2345 | return 0; | 2349 | return 0; |
2346 | } | 2350 | } |
2347 | 2351 | ||
2348 | struct tty_driver *console_driver; | 2352 | struct tty_driver *console_driver; |
2349 | 2353 | ||
2350 | #ifdef CONFIG_VT_CONSOLE | 2354 | #ifdef CONFIG_VT_CONSOLE |
2351 | 2355 | ||
2352 | /* | 2356 | /* |
2353 | * Console on virtual terminal | 2357 | * Console on virtual terminal |
2354 | * | 2358 | * |
2355 | * The console must be locked when we get here. | 2359 | * The console must be locked when we get here. |
2356 | */ | 2360 | */ |
2357 | 2361 | ||
2358 | static void vt_console_print(struct console *co, const char *b, unsigned count) | 2362 | static void vt_console_print(struct console *co, const char *b, unsigned count) |
2359 | { | 2363 | { |
2360 | struct vc_data *vc = vc_cons[fg_console].d; | 2364 | struct vc_data *vc = vc_cons[fg_console].d; |
2361 | unsigned char c; | 2365 | unsigned char c; |
2362 | static unsigned long printing; | 2366 | static unsigned long printing; |
2363 | const ushort *start; | 2367 | const ushort *start; |
2364 | ushort cnt = 0; | 2368 | ushort cnt = 0; |
2365 | ushort myx; | 2369 | ushort myx; |
2366 | 2370 | ||
2367 | /* console busy or not yet initialized */ | 2371 | /* console busy or not yet initialized */ |
2368 | if (!printable || test_and_set_bit(0, &printing)) | 2372 | if (!printable || test_and_set_bit(0, &printing)) |
2369 | return; | 2373 | return; |
2370 | 2374 | ||
2371 | if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) | 2375 | if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) |
2372 | vc = vc_cons[kmsg_redirect - 1].d; | 2376 | vc = vc_cons[kmsg_redirect - 1].d; |
2373 | 2377 | ||
2374 | /* read `x' only after setting currcons properly (otherwise | 2378 | /* read `x' only after setting currcons properly (otherwise |
2375 | the `x' macro will read the x of the foreground console). */ | 2379 | the `x' macro will read the x of the foreground console). */ |
2376 | myx = vc->vc_x; | 2380 | myx = vc->vc_x; |
2377 | 2381 | ||
2378 | if (!vc_cons_allocated(fg_console)) { | 2382 | if (!vc_cons_allocated(fg_console)) { |
2379 | /* impossible */ | 2383 | /* impossible */ |
2380 | /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ | 2384 | /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ |
2381 | goto quit; | 2385 | goto quit; |
2382 | } | 2386 | } |
2383 | 2387 | ||
2384 | if (vc->vc_mode != KD_TEXT) | 2388 | if (vc->vc_mode != KD_TEXT) |
2385 | goto quit; | 2389 | goto quit; |
2386 | 2390 | ||
2387 | /* undraw cursor first */ | 2391 | /* undraw cursor first */ |
2388 | if (IS_FG(vc)) | 2392 | if (IS_FG(vc)) |
2389 | hide_cursor(vc); | 2393 | hide_cursor(vc); |
2390 | 2394 | ||
2391 | start = (ushort *)vc->vc_pos; | 2395 | start = (ushort *)vc->vc_pos; |
2392 | 2396 | ||
2393 | /* Contrived structure to try to emulate original need_wrap behaviour | 2397 | /* Contrived structure to try to emulate original need_wrap behaviour |
2394 | * Problems caused when we have need_wrap set on '\n' character */ | 2398 | * Problems caused when we have need_wrap set on '\n' character */ |
2395 | while (count--) { | 2399 | while (count--) { |
2396 | c = *b++; | 2400 | c = *b++; |
2397 | if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { | 2401 | if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { |
2398 | if (cnt > 0) { | 2402 | if (cnt > 0) { |
2399 | if (CON_IS_VISIBLE(vc)) | 2403 | if (CON_IS_VISIBLE(vc)) |
2400 | vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); | 2404 | vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); |
2401 | vc->vc_x += cnt; | 2405 | vc->vc_x += cnt; |
2402 | if (vc->vc_need_wrap) | 2406 | if (vc->vc_need_wrap) |
2403 | vc->vc_x--; | 2407 | vc->vc_x--; |
2404 | cnt = 0; | 2408 | cnt = 0; |
2405 | } | 2409 | } |
2406 | if (c == 8) { /* backspace */ | 2410 | if (c == 8) { /* backspace */ |
2407 | bs(vc); | 2411 | bs(vc); |
2408 | start = (ushort *)vc->vc_pos; | 2412 | start = (ushort *)vc->vc_pos; |
2409 | myx = vc->vc_x; | 2413 | myx = vc->vc_x; |
2410 | continue; | 2414 | continue; |
2411 | } | 2415 | } |
2412 | if (c != 13) | 2416 | if (c != 13) |
2413 | lf(vc); | 2417 | lf(vc); |
2414 | cr(vc); | 2418 | cr(vc); |
2415 | start = (ushort *)vc->vc_pos; | 2419 | start = (ushort *)vc->vc_pos; |
2416 | myx = vc->vc_x; | 2420 | myx = vc->vc_x; |
2417 | if (c == 10 || c == 13) | 2421 | if (c == 10 || c == 13) |
2418 | continue; | 2422 | continue; |
2419 | } | 2423 | } |
2420 | scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos); | 2424 | scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos); |
2421 | cnt++; | 2425 | cnt++; |
2422 | if (myx == vc->vc_cols - 1) { | 2426 | if (myx == vc->vc_cols - 1) { |
2423 | vc->vc_need_wrap = 1; | 2427 | vc->vc_need_wrap = 1; |
2424 | continue; | 2428 | continue; |
2425 | } | 2429 | } |
2426 | vc->vc_pos += 2; | 2430 | vc->vc_pos += 2; |
2427 | myx++; | 2431 | myx++; |
2428 | } | 2432 | } |
2429 | if (cnt > 0) { | 2433 | if (cnt > 0) { |
2430 | if (CON_IS_VISIBLE(vc)) | 2434 | if (CON_IS_VISIBLE(vc)) |
2431 | vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); | 2435 | vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); |
2432 | vc->vc_x += cnt; | 2436 | vc->vc_x += cnt; |
2433 | if (vc->vc_x == vc->vc_cols) { | 2437 | if (vc->vc_x == vc->vc_cols) { |
2434 | vc->vc_x--; | 2438 | vc->vc_x--; |
2435 | vc->vc_need_wrap = 1; | 2439 | vc->vc_need_wrap = 1; |
2436 | } | 2440 | } |
2437 | } | 2441 | } |
2438 | set_cursor(vc); | 2442 | set_cursor(vc); |
2439 | 2443 | ||
2440 | quit: | 2444 | quit: |
2441 | clear_bit(0, &printing); | 2445 | clear_bit(0, &printing); |
2442 | } | 2446 | } |
2443 | 2447 | ||
2444 | static struct tty_driver *vt_console_device(struct console *c, int *index) | 2448 | static struct tty_driver *vt_console_device(struct console *c, int *index) |
2445 | { | 2449 | { |
2446 | *index = c->index ? c->index-1 : fg_console; | 2450 | *index = c->index ? c->index-1 : fg_console; |
2447 | return console_driver; | 2451 | return console_driver; |
2448 | } | 2452 | } |
2449 | 2453 | ||
2450 | static struct console vt_console_driver = { | 2454 | static struct console vt_console_driver = { |
2451 | .name = "tty", | 2455 | .name = "tty", |
2452 | .write = vt_console_print, | 2456 | .write = vt_console_print, |
2453 | .device = vt_console_device, | 2457 | .device = vt_console_device, |
2454 | .unblank = unblank_screen, | 2458 | .unblank = unblank_screen, |
2455 | .flags = CON_PRINTBUFFER, | 2459 | .flags = CON_PRINTBUFFER, |
2456 | .index = -1, | 2460 | .index = -1, |
2457 | }; | 2461 | }; |
2458 | #endif | 2462 | #endif |
2459 | 2463 | ||
2460 | /* | 2464 | /* |
2461 | * Handling of Linux-specific VC ioctls | 2465 | * Handling of Linux-specific VC ioctls |
2462 | */ | 2466 | */ |
2463 | 2467 | ||
2464 | /* | 2468 | /* |
2465 | * Generally a bit racy with respect to console_sem(). | 2469 | * Generally a bit racy with respect to console_sem(). |
2466 | * | 2470 | * |
2467 | * There are some functions which don't need it. | 2471 | * There are some functions which don't need it. |
2468 | * | 2472 | * |
2469 | * There are some functions which can sleep for arbitrary periods | 2473 | * There are some functions which can sleep for arbitrary periods |
2470 | * (paste_selection) but we don't need the lock there anyway. | 2474 | * (paste_selection) but we don't need the lock there anyway. |
2471 | * | 2475 | * |
2472 | * set_selection has locking, and definitely needs it | 2476 | * set_selection has locking, and definitely needs it |
2473 | */ | 2477 | */ |
2474 | 2478 | ||
2475 | int tioclinux(struct tty_struct *tty, unsigned long arg) | 2479 | int tioclinux(struct tty_struct *tty, unsigned long arg) |
2476 | { | 2480 | { |
2477 | char type, data; | 2481 | char type, data; |
2478 | char __user *p = (char __user *)arg; | 2482 | char __user *p = (char __user *)arg; |
2479 | int lines; | 2483 | int lines; |
2480 | int ret; | 2484 | int ret; |
2481 | 2485 | ||
2482 | if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE) | 2486 | if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE) |
2483 | return -EINVAL; | 2487 | return -EINVAL; |
2484 | if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) | 2488 | if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) |
2485 | return -EPERM; | 2489 | return -EPERM; |
2486 | if (get_user(type, p)) | 2490 | if (get_user(type, p)) |
2487 | return -EFAULT; | 2491 | return -EFAULT; |
2488 | ret = 0; | 2492 | ret = 0; |
2489 | switch (type) | 2493 | switch (type) |
2490 | { | 2494 | { |
2491 | case TIOCL_SETSEL: | 2495 | case TIOCL_SETSEL: |
2492 | acquire_console_sem(); | 2496 | acquire_console_sem(); |
2493 | ret = set_selection((struct tiocl_selection __user *)(p+1), tty); | 2497 | ret = set_selection((struct tiocl_selection __user *)(p+1), tty); |
2494 | release_console_sem(); | 2498 | release_console_sem(); |
2495 | break; | 2499 | break; |
2496 | case TIOCL_PASTESEL: | 2500 | case TIOCL_PASTESEL: |
2497 | ret = paste_selection(tty); | 2501 | ret = paste_selection(tty); |
2498 | break; | 2502 | break; |
2499 | case TIOCL_UNBLANKSCREEN: | 2503 | case TIOCL_UNBLANKSCREEN: |
2500 | acquire_console_sem(); | 2504 | acquire_console_sem(); |
2501 | unblank_screen(); | 2505 | unblank_screen(); |
2502 | release_console_sem(); | 2506 | release_console_sem(); |
2503 | break; | 2507 | break; |
2504 | case TIOCL_SELLOADLUT: | 2508 | case TIOCL_SELLOADLUT: |
2505 | ret = sel_loadlut(p); | 2509 | ret = sel_loadlut(p); |
2506 | break; | 2510 | break; |
2507 | case TIOCL_GETSHIFTSTATE: | 2511 | case TIOCL_GETSHIFTSTATE: |
2508 | 2512 | ||
2509 | /* | 2513 | /* |
2510 | * Make it possible to react to Shift+Mousebutton. | 2514 | * Make it possible to react to Shift+Mousebutton. |
2511 | * Note that 'shift_state' is an undocumented | 2515 | * Note that 'shift_state' is an undocumented |
2512 | * kernel-internal variable; programs not closely | 2516 | * kernel-internal variable; programs not closely |
2513 | * related to the kernel should not use this. | 2517 | * related to the kernel should not use this. |
2514 | */ | 2518 | */ |
2515 | data = shift_state; | 2519 | data = shift_state; |
2516 | ret = __put_user(data, p); | 2520 | ret = __put_user(data, p); |
2517 | break; | 2521 | break; |
2518 | case TIOCL_GETMOUSEREPORTING: | 2522 | case TIOCL_GETMOUSEREPORTING: |
2519 | data = mouse_reporting(); | 2523 | data = mouse_reporting(); |
2520 | ret = __put_user(data, p); | 2524 | ret = __put_user(data, p); |
2521 | break; | 2525 | break; |
2522 | case TIOCL_SETVESABLANK: | 2526 | case TIOCL_SETVESABLANK: |
2523 | ret = set_vesa_blanking(p); | 2527 | ret = set_vesa_blanking(p); |
2524 | break; | 2528 | break; |
2525 | case TIOCL_GETKMSGREDIRECT: | 2529 | case TIOCL_GETKMSGREDIRECT: |
2526 | data = kmsg_redirect; | 2530 | data = kmsg_redirect; |
2527 | ret = __put_user(data, p); | 2531 | ret = __put_user(data, p); |
2528 | break; | 2532 | break; |
2529 | case TIOCL_SETKMSGREDIRECT: | 2533 | case TIOCL_SETKMSGREDIRECT: |
2530 | if (!capable(CAP_SYS_ADMIN)) { | 2534 | if (!capable(CAP_SYS_ADMIN)) { |
2531 | ret = -EPERM; | 2535 | ret = -EPERM; |
2532 | } else { | 2536 | } else { |
2533 | if (get_user(data, p+1)) | 2537 | if (get_user(data, p+1)) |
2534 | ret = -EFAULT; | 2538 | ret = -EFAULT; |
2535 | else | 2539 | else |
2536 | kmsg_redirect = data; | 2540 | kmsg_redirect = data; |
2537 | } | 2541 | } |
2538 | break; | 2542 | break; |
2539 | case TIOCL_GETFGCONSOLE: | 2543 | case TIOCL_GETFGCONSOLE: |
2540 | ret = fg_console; | 2544 | ret = fg_console; |
2541 | break; | 2545 | break; |
2542 | case TIOCL_SCROLLCONSOLE: | 2546 | case TIOCL_SCROLLCONSOLE: |
2543 | if (get_user(lines, (s32 __user *)(p+4))) { | 2547 | if (get_user(lines, (s32 __user *)(p+4))) { |
2544 | ret = -EFAULT; | 2548 | ret = -EFAULT; |
2545 | } else { | 2549 | } else { |
2546 | scrollfront(vc_cons[fg_console].d, lines); | 2550 | scrollfront(vc_cons[fg_console].d, lines); |
2547 | ret = 0; | 2551 | ret = 0; |
2548 | } | 2552 | } |
2549 | break; | 2553 | break; |
2550 | case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ | 2554 | case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ |
2551 | acquire_console_sem(); | 2555 | acquire_console_sem(); |
2552 | ignore_poke = 1; | 2556 | ignore_poke = 1; |
2553 | do_blank_screen(0); | 2557 | do_blank_screen(0); |
2554 | release_console_sem(); | 2558 | release_console_sem(); |
2555 | break; | 2559 | break; |
2556 | case TIOCL_BLANKEDSCREEN: | 2560 | case TIOCL_BLANKEDSCREEN: |
2557 | ret = console_blanked; | 2561 | ret = console_blanked; |
2558 | break; | 2562 | break; |
2559 | default: | 2563 | default: |
2560 | ret = -EINVAL; | 2564 | ret = -EINVAL; |
2561 | break; | 2565 | break; |
2562 | } | 2566 | } |
2563 | return ret; | 2567 | return ret; |
2564 | } | 2568 | } |
2565 | 2569 | ||
2566 | /* | 2570 | /* |
2567 | * /dev/ttyN handling | 2571 | * /dev/ttyN handling |
2568 | */ | 2572 | */ |
2569 | 2573 | ||
2570 | static int con_write(struct tty_struct *tty, const unsigned char *buf, int count) | 2574 | static int con_write(struct tty_struct *tty, const unsigned char *buf, int count) |
2571 | { | 2575 | { |
2572 | int retval; | 2576 | int retval; |
2573 | 2577 | ||
2574 | retval = do_con_write(tty, buf, count); | 2578 | retval = do_con_write(tty, buf, count); |
2575 | con_flush_chars(tty); | 2579 | con_flush_chars(tty); |
2576 | 2580 | ||
2577 | return retval; | 2581 | return retval; |
2578 | } | 2582 | } |
2579 | 2583 | ||
2580 | static void con_put_char(struct tty_struct *tty, unsigned char ch) | 2584 | static void con_put_char(struct tty_struct *tty, unsigned char ch) |
2581 | { | 2585 | { |
2582 | if (in_interrupt()) | 2586 | if (in_interrupt()) |
2583 | return; /* n_r3964 calls put_char() from interrupt context */ | 2587 | return; /* n_r3964 calls put_char() from interrupt context */ |
2584 | do_con_write(tty, &ch, 1); | 2588 | do_con_write(tty, &ch, 1); |
2585 | } | 2589 | } |
2586 | 2590 | ||
2587 | static int con_write_room(struct tty_struct *tty) | 2591 | static int con_write_room(struct tty_struct *tty) |
2588 | { | 2592 | { |
2589 | if (tty->stopped) | 2593 | if (tty->stopped) |
2590 | return 0; | 2594 | return 0; |
2591 | return 4096; /* No limit, really; we're not buffering */ | 2595 | return 4096; /* No limit, really; we're not buffering */ |
2592 | } | 2596 | } |
2593 | 2597 | ||
2594 | static int con_chars_in_buffer(struct tty_struct *tty) | 2598 | static int con_chars_in_buffer(struct tty_struct *tty) |
2595 | { | 2599 | { |
2596 | return 0; /* we're not buffering */ | 2600 | return 0; /* we're not buffering */ |
2597 | } | 2601 | } |
2598 | 2602 | ||
2599 | /* | 2603 | /* |
2600 | * con_throttle and con_unthrottle are only used for | 2604 | * con_throttle and con_unthrottle are only used for |
2601 | * paste_selection(), which has to stuff in a large number of | 2605 | * paste_selection(), which has to stuff in a large number of |
2602 | * characters... | 2606 | * characters... |
2603 | */ | 2607 | */ |
2604 | static void con_throttle(struct tty_struct *tty) | 2608 | static void con_throttle(struct tty_struct *tty) |
2605 | { | 2609 | { |
2606 | } | 2610 | } |
2607 | 2611 | ||
2608 | static void con_unthrottle(struct tty_struct *tty) | 2612 | static void con_unthrottle(struct tty_struct *tty) |
2609 | { | 2613 | { |
2610 | struct vc_data *vc = tty->driver_data; | 2614 | struct vc_data *vc = tty->driver_data; |
2611 | 2615 | ||
2612 | wake_up_interruptible(&vc->paste_wait); | 2616 | wake_up_interruptible(&vc->paste_wait); |
2613 | } | 2617 | } |
2614 | 2618 | ||
2615 | /* | 2619 | /* |
2616 | * Turn the Scroll-Lock LED on when the tty is stopped | 2620 | * Turn the Scroll-Lock LED on when the tty is stopped |
2617 | */ | 2621 | */ |
2618 | static void con_stop(struct tty_struct *tty) | 2622 | static void con_stop(struct tty_struct *tty) |
2619 | { | 2623 | { |
2620 | int console_num; | 2624 | int console_num; |
2621 | if (!tty) | 2625 | if (!tty) |
2622 | return; | 2626 | return; |
2623 | console_num = tty->index; | 2627 | console_num = tty->index; |
2624 | if (!vc_cons_allocated(console_num)) | 2628 | if (!vc_cons_allocated(console_num)) |
2625 | return; | 2629 | return; |
2626 | set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); | 2630 | set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); |
2627 | set_leds(); | 2631 | set_leds(); |
2628 | } | 2632 | } |
2629 | 2633 | ||
2630 | /* | 2634 | /* |
2631 | * Turn the Scroll-Lock LED off when the console is started | 2635 | * Turn the Scroll-Lock LED off when the console is started |
2632 | */ | 2636 | */ |
2633 | static void con_start(struct tty_struct *tty) | 2637 | static void con_start(struct tty_struct *tty) |
2634 | { | 2638 | { |
2635 | int console_num; | 2639 | int console_num; |
2636 | if (!tty) | 2640 | if (!tty) |
2637 | return; | 2641 | return; |
2638 | console_num = tty->index; | 2642 | console_num = tty->index; |
2639 | if (!vc_cons_allocated(console_num)) | 2643 | if (!vc_cons_allocated(console_num)) |
2640 | return; | 2644 | return; |
2641 | clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); | 2645 | clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); |
2642 | set_leds(); | 2646 | set_leds(); |
2643 | } | 2647 | } |
2644 | 2648 | ||
2645 | static void con_flush_chars(struct tty_struct *tty) | 2649 | static void con_flush_chars(struct tty_struct *tty) |
2646 | { | 2650 | { |
2647 | struct vc_data *vc; | 2651 | struct vc_data *vc; |
2648 | 2652 | ||
2649 | if (in_interrupt()) /* from flush_to_ldisc */ | 2653 | if (in_interrupt()) /* from flush_to_ldisc */ |
2650 | return; | 2654 | return; |
2651 | 2655 | ||
2652 | /* if we race with con_close(), vt may be null */ | 2656 | /* if we race with con_close(), vt may be null */ |
2653 | acquire_console_sem(); | 2657 | acquire_console_sem(); |
2654 | vc = tty->driver_data; | 2658 | vc = tty->driver_data; |
2655 | if (vc) | 2659 | if (vc) |
2656 | set_cursor(vc); | 2660 | set_cursor(vc); |
2657 | release_console_sem(); | 2661 | release_console_sem(); |
2658 | } | 2662 | } |
2659 | 2663 | ||
2660 | /* | 2664 | /* |
2661 | * Allocate the console screen memory. | 2665 | * Allocate the console screen memory. |
2662 | */ | 2666 | */ |
2663 | static int con_open(struct tty_struct *tty, struct file *filp) | 2667 | static int con_open(struct tty_struct *tty, struct file *filp) |
2664 | { | 2668 | { |
2665 | unsigned int currcons = tty->index; | 2669 | unsigned int currcons = tty->index; |
2666 | int ret = 0; | 2670 | int ret = 0; |
2667 | 2671 | ||
2668 | acquire_console_sem(); | 2672 | acquire_console_sem(); |
2669 | if (tty->driver_data == NULL) { | 2673 | if (tty->driver_data == NULL) { |
2670 | ret = vc_allocate(currcons); | 2674 | ret = vc_allocate(currcons); |
2671 | if (ret == 0) { | 2675 | if (ret == 0) { |
2672 | struct vc_data *vc = vc_cons[currcons].d; | 2676 | struct vc_data *vc = vc_cons[currcons].d; |
2673 | tty->driver_data = vc; | 2677 | tty->driver_data = vc; |
2674 | vc->vc_tty = tty; | 2678 | vc->vc_tty = tty; |
2675 | 2679 | ||
2676 | if (!tty->winsize.ws_row && !tty->winsize.ws_col) { | 2680 | if (!tty->winsize.ws_row && !tty->winsize.ws_col) { |
2677 | tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; | 2681 | tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; |
2678 | tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; | 2682 | tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; |
2679 | } | 2683 | } |
2680 | release_console_sem(); | 2684 | release_console_sem(); |
2681 | vcs_make_sysfs(tty); | 2685 | vcs_make_sysfs(tty); |
2682 | return ret; | 2686 | return ret; |
2683 | } | 2687 | } |
2684 | } | 2688 | } |
2685 | release_console_sem(); | 2689 | release_console_sem(); |
2686 | return ret; | 2690 | return ret; |
2687 | } | 2691 | } |
2688 | 2692 | ||
2689 | /* | 2693 | /* |
2690 | * We take tty_mutex in here to prevent another thread from coming in via init_dev | 2694 | * We take tty_mutex in here to prevent another thread from coming in via init_dev |
2691 | * and taking a ref against the tty while we're in the process of forgetting | 2695 | * and taking a ref against the tty while we're in the process of forgetting |
2692 | * about it and cleaning things up. | 2696 | * about it and cleaning things up. |
2693 | * | 2697 | * |
2694 | * This is because vcs_remove_sysfs() can sleep and will drop the BKL. | 2698 | * This is because vcs_remove_sysfs() can sleep and will drop the BKL. |
2695 | */ | 2699 | */ |
2696 | static void con_close(struct tty_struct *tty, struct file *filp) | 2700 | static void con_close(struct tty_struct *tty, struct file *filp) |
2697 | { | 2701 | { |
2698 | mutex_lock(&tty_mutex); | 2702 | mutex_lock(&tty_mutex); |
2699 | acquire_console_sem(); | 2703 | acquire_console_sem(); |
2700 | if (tty && tty->count == 1) { | 2704 | if (tty && tty->count == 1) { |
2701 | struct vc_data *vc = tty->driver_data; | 2705 | struct vc_data *vc = tty->driver_data; |
2702 | 2706 | ||
2703 | if (vc) | 2707 | if (vc) |
2704 | vc->vc_tty = NULL; | 2708 | vc->vc_tty = NULL; |
2705 | tty->driver_data = NULL; | 2709 | tty->driver_data = NULL; |
2706 | release_console_sem(); | 2710 | release_console_sem(); |
2707 | vcs_remove_sysfs(tty); | 2711 | vcs_remove_sysfs(tty); |
2708 | mutex_unlock(&tty_mutex); | 2712 | mutex_unlock(&tty_mutex); |
2709 | /* | 2713 | /* |
2710 | * tty_mutex is released, but we still hold BKL, so there is | 2714 | * tty_mutex is released, but we still hold BKL, so there is |
2711 | * still exclusion against init_dev() | 2715 | * still exclusion against init_dev() |
2712 | */ | 2716 | */ |
2713 | return; | 2717 | return; |
2714 | } | 2718 | } |
2715 | release_console_sem(); | 2719 | release_console_sem(); |
2716 | mutex_unlock(&tty_mutex); | 2720 | mutex_unlock(&tty_mutex); |
2717 | } | 2721 | } |
2718 | 2722 | ||
2719 | static int default_italic_color = 2; // green (ASCII) | 2723 | static int default_italic_color = 2; // green (ASCII) |
2720 | static int default_underline_color = 3; // cyan (ASCII) | 2724 | static int default_underline_color = 3; // cyan (ASCII) |
2721 | module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR); | 2725 | module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR); |
2722 | module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR); | 2726 | module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR); |
2723 | 2727 | ||
2724 | static void vc_init(struct vc_data *vc, unsigned int rows, | 2728 | static void vc_init(struct vc_data *vc, unsigned int rows, |
2725 | unsigned int cols, int do_clear) | 2729 | unsigned int cols, int do_clear) |
2726 | { | 2730 | { |
2727 | int j, k ; | 2731 | int j, k ; |
2728 | 2732 | ||
2729 | vc->vc_cols = cols; | 2733 | vc->vc_cols = cols; |
2730 | vc->vc_rows = rows; | 2734 | vc->vc_rows = rows; |
2731 | vc->vc_size_row = cols << 1; | 2735 | vc->vc_size_row = cols << 1; |
2732 | vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row; | 2736 | vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row; |
2733 | 2737 | ||
2734 | set_origin(vc); | 2738 | set_origin(vc); |
2735 | vc->vc_pos = vc->vc_origin; | 2739 | vc->vc_pos = vc->vc_origin; |
2736 | reset_vc(vc); | 2740 | reset_vc(vc); |
2737 | for (j=k=0; j<16; j++) { | 2741 | for (j=k=0; j<16; j++) { |
2738 | vc->vc_palette[k++] = default_red[j] ; | 2742 | vc->vc_palette[k++] = default_red[j] ; |
2739 | vc->vc_palette[k++] = default_grn[j] ; | 2743 | vc->vc_palette[k++] = default_grn[j] ; |
2740 | vc->vc_palette[k++] = default_blu[j] ; | 2744 | vc->vc_palette[k++] = default_blu[j] ; |
2741 | } | 2745 | } |
2742 | vc->vc_def_color = 0x07; /* white */ | 2746 | vc->vc_def_color = 0x07; /* white */ |
2743 | vc->vc_ulcolor = default_underline_color; | 2747 | vc->vc_ulcolor = default_underline_color; |
2744 | vc->vc_itcolor = default_italic_color; | 2748 | vc->vc_itcolor = default_italic_color; |
2745 | vc->vc_halfcolor = 0x08; /* grey */ | 2749 | vc->vc_halfcolor = 0x08; /* grey */ |
2746 | init_waitqueue_head(&vc->paste_wait); | 2750 | init_waitqueue_head(&vc->paste_wait); |
2747 | reset_terminal(vc, do_clear); | 2751 | reset_terminal(vc, do_clear); |
2748 | } | 2752 | } |
2749 | 2753 | ||
2750 | /* | 2754 | /* |
2751 | * This routine initializes console interrupts, and does nothing | 2755 | * This routine initializes console interrupts, and does nothing |
2752 | * else. If you want the screen to clear, call tty_write with | 2756 | * else. If you want the screen to clear, call tty_write with |
2753 | * the appropriate escape-sequence. | 2757 | * the appropriate escape-sequence. |
2754 | */ | 2758 | */ |
2755 | 2759 | ||
2756 | static int __init con_init(void) | 2760 | static int __init con_init(void) |
2757 | { | 2761 | { |
2758 | const char *display_desc = NULL; | 2762 | const char *display_desc = NULL; |
2759 | struct vc_data *vc; | 2763 | struct vc_data *vc; |
2760 | unsigned int currcons = 0, i; | 2764 | unsigned int currcons = 0, i; |
2761 | 2765 | ||
2762 | acquire_console_sem(); | 2766 | acquire_console_sem(); |
2763 | 2767 | ||
2764 | if (conswitchp) | 2768 | if (conswitchp) |
2765 | display_desc = conswitchp->con_startup(); | 2769 | display_desc = conswitchp->con_startup(); |
2766 | if (!display_desc) { | 2770 | if (!display_desc) { |
2767 | fg_console = 0; | 2771 | fg_console = 0; |
2768 | release_console_sem(); | 2772 | release_console_sem(); |
2769 | return 0; | 2773 | return 0; |
2770 | } | 2774 | } |
2771 | 2775 | ||
2772 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 2776 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
2773 | struct con_driver *con_driver = ®istered_con_driver[i]; | 2777 | struct con_driver *con_driver = ®istered_con_driver[i]; |
2774 | 2778 | ||
2775 | if (con_driver->con == NULL) { | 2779 | if (con_driver->con == NULL) { |
2776 | con_driver->con = conswitchp; | 2780 | con_driver->con = conswitchp; |
2777 | con_driver->desc = display_desc; | 2781 | con_driver->desc = display_desc; |
2778 | con_driver->flag = CON_DRIVER_FLAG_INIT; | 2782 | con_driver->flag = CON_DRIVER_FLAG_INIT; |
2779 | con_driver->first = 0; | 2783 | con_driver->first = 0; |
2780 | con_driver->last = MAX_NR_CONSOLES - 1; | 2784 | con_driver->last = MAX_NR_CONSOLES - 1; |
2781 | break; | 2785 | break; |
2782 | } | 2786 | } |
2783 | } | 2787 | } |
2784 | 2788 | ||
2785 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 2789 | for (i = 0; i < MAX_NR_CONSOLES; i++) |
2786 | con_driver_map[i] = conswitchp; | 2790 | con_driver_map[i] = conswitchp; |
2787 | 2791 | ||
2788 | if (blankinterval) { | 2792 | if (blankinterval) { |
2789 | blank_state = blank_normal_wait; | 2793 | blank_state = blank_normal_wait; |
2790 | mod_timer(&console_timer, jiffies + blankinterval); | 2794 | mod_timer(&console_timer, jiffies + blankinterval); |
2791 | } | 2795 | } |
2792 | 2796 | ||
2793 | /* | 2797 | /* |
2794 | * kmalloc is not running yet - we use the bootmem allocator. | 2798 | * kmalloc is not running yet - we use the bootmem allocator. |
2795 | */ | 2799 | */ |
2796 | for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { | 2800 | for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { |
2797 | vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data)); | 2801 | vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data)); |
2798 | INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); | 2802 | INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); |
2799 | visual_init(vc, currcons, 1); | 2803 | visual_init(vc, currcons, 1); |
2800 | vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size); | 2804 | vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size); |
2801 | vc->vc_kmalloced = 0; | 2805 | vc->vc_kmalloced = 0; |
2802 | vc_init(vc, vc->vc_rows, vc->vc_cols, | 2806 | vc_init(vc, vc->vc_rows, vc->vc_cols, |
2803 | currcons || !vc->vc_sw->con_save_screen); | 2807 | currcons || !vc->vc_sw->con_save_screen); |
2804 | } | 2808 | } |
2805 | currcons = fg_console = 0; | 2809 | currcons = fg_console = 0; |
2806 | master_display_fg = vc = vc_cons[currcons].d; | 2810 | master_display_fg = vc = vc_cons[currcons].d; |
2807 | set_origin(vc); | 2811 | set_origin(vc); |
2808 | save_screen(vc); | 2812 | save_screen(vc); |
2809 | gotoxy(vc, vc->vc_x, vc->vc_y); | 2813 | gotoxy(vc, vc->vc_x, vc->vc_y); |
2810 | csi_J(vc, 0); | 2814 | csi_J(vc, 0); |
2811 | update_screen(vc); | 2815 | update_screen(vc); |
2812 | printk("Console: %s %s %dx%d", | 2816 | printk("Console: %s %s %dx%d", |
2813 | vc->vc_can_do_color ? "colour" : "mono", | 2817 | vc->vc_can_do_color ? "colour" : "mono", |
2814 | display_desc, vc->vc_cols, vc->vc_rows); | 2818 | display_desc, vc->vc_cols, vc->vc_rows); |
2815 | printable = 1; | 2819 | printable = 1; |
2816 | printk("\n"); | 2820 | printk("\n"); |
2817 | 2821 | ||
2818 | release_console_sem(); | 2822 | release_console_sem(); |
2819 | 2823 | ||
2820 | #ifdef CONFIG_VT_CONSOLE | 2824 | #ifdef CONFIG_VT_CONSOLE |
2821 | register_console(&vt_console_driver); | 2825 | register_console(&vt_console_driver); |
2822 | #endif | 2826 | #endif |
2823 | return 0; | 2827 | return 0; |
2824 | } | 2828 | } |
2825 | console_initcall(con_init); | 2829 | console_initcall(con_init); |
2826 | 2830 | ||
2827 | static const struct tty_operations con_ops = { | 2831 | static const struct tty_operations con_ops = { |
2828 | .open = con_open, | 2832 | .open = con_open, |
2829 | .close = con_close, | 2833 | .close = con_close, |
2830 | .write = con_write, | 2834 | .write = con_write, |
2831 | .write_room = con_write_room, | 2835 | .write_room = con_write_room, |
2832 | .put_char = con_put_char, | 2836 | .put_char = con_put_char, |
2833 | .flush_chars = con_flush_chars, | 2837 | .flush_chars = con_flush_chars, |
2834 | .chars_in_buffer = con_chars_in_buffer, | 2838 | .chars_in_buffer = con_chars_in_buffer, |
2835 | .ioctl = vt_ioctl, | 2839 | .ioctl = vt_ioctl, |
2836 | .stop = con_stop, | 2840 | .stop = con_stop, |
2837 | .start = con_start, | 2841 | .start = con_start, |
2838 | .throttle = con_throttle, | 2842 | .throttle = con_throttle, |
2839 | .unthrottle = con_unthrottle, | 2843 | .unthrottle = con_unthrottle, |
2840 | }; | 2844 | }; |
2841 | 2845 | ||
2842 | int __init vty_init(void) | 2846 | int __init vty_init(void) |
2843 | { | 2847 | { |
2844 | vcs_init(); | 2848 | vcs_init(); |
2845 | 2849 | ||
2846 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); | 2850 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); |
2847 | if (!console_driver) | 2851 | if (!console_driver) |
2848 | panic("Couldn't allocate console driver\n"); | 2852 | panic("Couldn't allocate console driver\n"); |
2849 | console_driver->owner = THIS_MODULE; | 2853 | console_driver->owner = THIS_MODULE; |
2850 | console_driver->name = "tty"; | 2854 | console_driver->name = "tty"; |
2851 | console_driver->name_base = 1; | 2855 | console_driver->name_base = 1; |
2852 | console_driver->major = TTY_MAJOR; | 2856 | console_driver->major = TTY_MAJOR; |
2853 | console_driver->minor_start = 1; | 2857 | console_driver->minor_start = 1; |
2854 | console_driver->type = TTY_DRIVER_TYPE_CONSOLE; | 2858 | console_driver->type = TTY_DRIVER_TYPE_CONSOLE; |
2855 | console_driver->init_termios = tty_std_termios; | 2859 | console_driver->init_termios = tty_std_termios; |
2856 | console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; | 2860 | console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; |
2857 | tty_set_operations(console_driver, &con_ops); | 2861 | tty_set_operations(console_driver, &con_ops); |
2858 | if (tty_register_driver(console_driver)) | 2862 | if (tty_register_driver(console_driver)) |
2859 | panic("Couldn't register console driver\n"); | 2863 | panic("Couldn't register console driver\n"); |
2860 | 2864 | ||
2861 | kbd_init(); | 2865 | kbd_init(); |
2862 | console_map_init(); | 2866 | console_map_init(); |
2863 | #ifdef CONFIG_PROM_CONSOLE | 2867 | #ifdef CONFIG_PROM_CONSOLE |
2864 | prom_con_init(); | 2868 | prom_con_init(); |
2865 | #endif | 2869 | #endif |
2866 | #ifdef CONFIG_MDA_CONSOLE | 2870 | #ifdef CONFIG_MDA_CONSOLE |
2867 | mda_console_init(); | 2871 | mda_console_init(); |
2868 | #endif | 2872 | #endif |
2869 | return 0; | 2873 | return 0; |
2870 | } | 2874 | } |
2871 | 2875 | ||
2872 | #ifndef VT_SINGLE_DRIVER | 2876 | #ifndef VT_SINGLE_DRIVER |
2873 | #include <linux/device.h> | 2877 | #include <linux/device.h> |
2874 | 2878 | ||
2875 | static struct class *vtconsole_class; | 2879 | static struct class *vtconsole_class; |
2876 | 2880 | ||
2877 | static int bind_con_driver(const struct consw *csw, int first, int last, | 2881 | static int bind_con_driver(const struct consw *csw, int first, int last, |
2878 | int deflt) | 2882 | int deflt) |
2879 | { | 2883 | { |
2880 | struct module *owner = csw->owner; | 2884 | struct module *owner = csw->owner; |
2881 | const char *desc = NULL; | 2885 | const char *desc = NULL; |
2882 | struct con_driver *con_driver; | 2886 | struct con_driver *con_driver; |
2883 | int i, j = -1, k = -1, retval = -ENODEV; | 2887 | int i, j = -1, k = -1, retval = -ENODEV; |
2884 | 2888 | ||
2885 | if (!try_module_get(owner)) | 2889 | if (!try_module_get(owner)) |
2886 | return -ENODEV; | 2890 | return -ENODEV; |
2887 | 2891 | ||
2888 | acquire_console_sem(); | 2892 | acquire_console_sem(); |
2889 | 2893 | ||
2890 | /* check if driver is registered */ | 2894 | /* check if driver is registered */ |
2891 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 2895 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
2892 | con_driver = ®istered_con_driver[i]; | 2896 | con_driver = ®istered_con_driver[i]; |
2893 | 2897 | ||
2894 | if (con_driver->con == csw) { | 2898 | if (con_driver->con == csw) { |
2895 | desc = con_driver->desc; | 2899 | desc = con_driver->desc; |
2896 | retval = 0; | 2900 | retval = 0; |
2897 | break; | 2901 | break; |
2898 | } | 2902 | } |
2899 | } | 2903 | } |
2900 | 2904 | ||
2901 | if (retval) | 2905 | if (retval) |
2902 | goto err; | 2906 | goto err; |
2903 | 2907 | ||
2904 | if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) { | 2908 | if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) { |
2905 | csw->con_startup(); | 2909 | csw->con_startup(); |
2906 | con_driver->flag |= CON_DRIVER_FLAG_INIT; | 2910 | con_driver->flag |= CON_DRIVER_FLAG_INIT; |
2907 | } | 2911 | } |
2908 | 2912 | ||
2909 | if (deflt) { | 2913 | if (deflt) { |
2910 | if (conswitchp) | 2914 | if (conswitchp) |
2911 | module_put(conswitchp->owner); | 2915 | module_put(conswitchp->owner); |
2912 | 2916 | ||
2913 | __module_get(owner); | 2917 | __module_get(owner); |
2914 | conswitchp = csw; | 2918 | conswitchp = csw; |
2915 | } | 2919 | } |
2916 | 2920 | ||
2917 | first = max(first, con_driver->first); | 2921 | first = max(first, con_driver->first); |
2918 | last = min(last, con_driver->last); | 2922 | last = min(last, con_driver->last); |
2919 | 2923 | ||
2920 | for (i = first; i <= last; i++) { | 2924 | for (i = first; i <= last; i++) { |
2921 | int old_was_color; | 2925 | int old_was_color; |
2922 | struct vc_data *vc = vc_cons[i].d; | 2926 | struct vc_data *vc = vc_cons[i].d; |
2923 | 2927 | ||
2924 | if (con_driver_map[i]) | 2928 | if (con_driver_map[i]) |
2925 | module_put(con_driver_map[i]->owner); | 2929 | module_put(con_driver_map[i]->owner); |
2926 | __module_get(owner); | 2930 | __module_get(owner); |
2927 | con_driver_map[i] = csw; | 2931 | con_driver_map[i] = csw; |
2928 | 2932 | ||
2929 | if (!vc || !vc->vc_sw) | 2933 | if (!vc || !vc->vc_sw) |
2930 | continue; | 2934 | continue; |
2931 | 2935 | ||
2932 | j = i; | 2936 | j = i; |
2933 | 2937 | ||
2934 | if (CON_IS_VISIBLE(vc)) { | 2938 | if (CON_IS_VISIBLE(vc)) { |
2935 | k = i; | 2939 | k = i; |
2936 | save_screen(vc); | 2940 | save_screen(vc); |
2937 | } | 2941 | } |
2938 | 2942 | ||
2939 | old_was_color = vc->vc_can_do_color; | 2943 | old_was_color = vc->vc_can_do_color; |
2940 | vc->vc_sw->con_deinit(vc); | 2944 | vc->vc_sw->con_deinit(vc); |
2941 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; | 2945 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; |
2942 | visual_init(vc, i, 0); | 2946 | visual_init(vc, i, 0); |
2943 | set_origin(vc); | 2947 | set_origin(vc); |
2944 | update_attr(vc); | 2948 | update_attr(vc); |
2945 | 2949 | ||
2946 | /* If the console changed between mono <-> color, then | 2950 | /* If the console changed between mono <-> color, then |
2947 | * the attributes in the screenbuf will be wrong. The | 2951 | * the attributes in the screenbuf will be wrong. The |
2948 | * following resets all attributes to something sane. | 2952 | * following resets all attributes to something sane. |
2949 | */ | 2953 | */ |
2950 | if (old_was_color != vc->vc_can_do_color) | 2954 | if (old_was_color != vc->vc_can_do_color) |
2951 | clear_buffer_attributes(vc); | 2955 | clear_buffer_attributes(vc); |
2952 | } | 2956 | } |
2953 | 2957 | ||
2954 | printk("Console: switching "); | 2958 | printk("Console: switching "); |
2955 | if (!deflt) | 2959 | if (!deflt) |
2956 | printk("consoles %d-%d ", first+1, last+1); | 2960 | printk("consoles %d-%d ", first+1, last+1); |
2957 | if (j >= 0) { | 2961 | if (j >= 0) { |
2958 | struct vc_data *vc = vc_cons[j].d; | 2962 | struct vc_data *vc = vc_cons[j].d; |
2959 | 2963 | ||
2960 | printk("to %s %s %dx%d\n", | 2964 | printk("to %s %s %dx%d\n", |
2961 | vc->vc_can_do_color ? "colour" : "mono", | 2965 | vc->vc_can_do_color ? "colour" : "mono", |
2962 | desc, vc->vc_cols, vc->vc_rows); | 2966 | desc, vc->vc_cols, vc->vc_rows); |
2963 | 2967 | ||
2964 | if (k >= 0) { | 2968 | if (k >= 0) { |
2965 | vc = vc_cons[k].d; | 2969 | vc = vc_cons[k].d; |
2966 | update_screen(vc); | 2970 | update_screen(vc); |
2967 | } | 2971 | } |
2968 | } else | 2972 | } else |
2969 | printk("to %s\n", desc); | 2973 | printk("to %s\n", desc); |
2970 | 2974 | ||
2971 | retval = 0; | 2975 | retval = 0; |
2972 | err: | 2976 | err: |
2973 | release_console_sem(); | 2977 | release_console_sem(); |
2974 | module_put(owner); | 2978 | module_put(owner); |
2975 | return retval; | 2979 | return retval; |
2976 | }; | 2980 | }; |
2977 | 2981 | ||
2978 | #ifdef CONFIG_VT_HW_CONSOLE_BINDING | 2982 | #ifdef CONFIG_VT_HW_CONSOLE_BINDING |
2979 | static int con_is_graphics(const struct consw *csw, int first, int last) | 2983 | static int con_is_graphics(const struct consw *csw, int first, int last) |
2980 | { | 2984 | { |
2981 | int i, retval = 0; | 2985 | int i, retval = 0; |
2982 | 2986 | ||
2983 | for (i = first; i <= last; i++) { | 2987 | for (i = first; i <= last; i++) { |
2984 | struct vc_data *vc = vc_cons[i].d; | 2988 | struct vc_data *vc = vc_cons[i].d; |
2985 | 2989 | ||
2986 | if (vc && vc->vc_mode == KD_GRAPHICS) { | 2990 | if (vc && vc->vc_mode == KD_GRAPHICS) { |
2987 | retval = 1; | 2991 | retval = 1; |
2988 | break; | 2992 | break; |
2989 | } | 2993 | } |
2990 | } | 2994 | } |
2991 | 2995 | ||
2992 | return retval; | 2996 | return retval; |
2993 | } | 2997 | } |
2994 | 2998 | ||
2995 | /** | 2999 | /** |
2996 | * unbind_con_driver - unbind a console driver | 3000 | * unbind_con_driver - unbind a console driver |
2997 | * @csw: pointer to console driver to unregister | 3001 | * @csw: pointer to console driver to unregister |
2998 | * @first: first in range of consoles that @csw should be unbound from | 3002 | * @first: first in range of consoles that @csw should be unbound from |
2999 | * @last: last in range of consoles that @csw should be unbound from | 3003 | * @last: last in range of consoles that @csw should be unbound from |
3000 | * @deflt: should next bound console driver be default after @csw is unbound? | 3004 | * @deflt: should next bound console driver be default after @csw is unbound? |
3001 | * | 3005 | * |
3002 | * To unbind a driver from all possible consoles, pass 0 as @first and | 3006 | * To unbind a driver from all possible consoles, pass 0 as @first and |
3003 | * %MAX_NR_CONSOLES as @last. | 3007 | * %MAX_NR_CONSOLES as @last. |
3004 | * | 3008 | * |
3005 | * @deflt controls whether the console that ends up replacing @csw should be | 3009 | * @deflt controls whether the console that ends up replacing @csw should be |
3006 | * the default console. | 3010 | * the default console. |
3007 | * | 3011 | * |
3008 | * RETURNS: | 3012 | * RETURNS: |
3009 | * -ENODEV if @csw isn't a registered console driver or can't be unregistered | 3013 | * -ENODEV if @csw isn't a registered console driver or can't be unregistered |
3010 | * or 0 on success. | 3014 | * or 0 on success. |
3011 | */ | 3015 | */ |
3012 | int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) | 3016 | int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) |
3013 | { | 3017 | { |
3014 | struct module *owner = csw->owner; | 3018 | struct module *owner = csw->owner; |
3015 | const struct consw *defcsw = NULL; | 3019 | const struct consw *defcsw = NULL; |
3016 | struct con_driver *con_driver = NULL, *con_back = NULL; | 3020 | struct con_driver *con_driver = NULL, *con_back = NULL; |
3017 | int i, retval = -ENODEV; | 3021 | int i, retval = -ENODEV; |
3018 | 3022 | ||
3019 | if (!try_module_get(owner)) | 3023 | if (!try_module_get(owner)) |
3020 | return -ENODEV; | 3024 | return -ENODEV; |
3021 | 3025 | ||
3022 | acquire_console_sem(); | 3026 | acquire_console_sem(); |
3023 | 3027 | ||
3024 | /* check if driver is registered and if it is unbindable */ | 3028 | /* check if driver is registered and if it is unbindable */ |
3025 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 3029 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
3026 | con_driver = ®istered_con_driver[i]; | 3030 | con_driver = ®istered_con_driver[i]; |
3027 | 3031 | ||
3028 | if (con_driver->con == csw && | 3032 | if (con_driver->con == csw && |
3029 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { | 3033 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { |
3030 | retval = 0; | 3034 | retval = 0; |
3031 | break; | 3035 | break; |
3032 | } | 3036 | } |
3033 | } | 3037 | } |
3034 | 3038 | ||
3035 | if (retval) { | 3039 | if (retval) { |
3036 | release_console_sem(); | 3040 | release_console_sem(); |
3037 | goto err; | 3041 | goto err; |
3038 | } | 3042 | } |
3039 | 3043 | ||
3040 | retval = -ENODEV; | 3044 | retval = -ENODEV; |
3041 | 3045 | ||
3042 | /* check if backup driver exists */ | 3046 | /* check if backup driver exists */ |
3043 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 3047 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
3044 | con_back = ®istered_con_driver[i]; | 3048 | con_back = ®istered_con_driver[i]; |
3045 | 3049 | ||
3046 | if (con_back->con && | 3050 | if (con_back->con && |
3047 | !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { | 3051 | !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { |
3048 | defcsw = con_back->con; | 3052 | defcsw = con_back->con; |
3049 | retval = 0; | 3053 | retval = 0; |
3050 | break; | 3054 | break; |
3051 | } | 3055 | } |
3052 | } | 3056 | } |
3053 | 3057 | ||
3054 | if (retval) { | 3058 | if (retval) { |
3055 | release_console_sem(); | 3059 | release_console_sem(); |
3056 | goto err; | 3060 | goto err; |
3057 | } | 3061 | } |
3058 | 3062 | ||
3059 | if (!con_is_bound(csw)) { | 3063 | if (!con_is_bound(csw)) { |
3060 | release_console_sem(); | 3064 | release_console_sem(); |
3061 | goto err; | 3065 | goto err; |
3062 | } | 3066 | } |
3063 | 3067 | ||
3064 | first = max(first, con_driver->first); | 3068 | first = max(first, con_driver->first); |
3065 | last = min(last, con_driver->last); | 3069 | last = min(last, con_driver->last); |
3066 | 3070 | ||
3067 | for (i = first; i <= last; i++) { | 3071 | for (i = first; i <= last; i++) { |
3068 | if (con_driver_map[i] == csw) { | 3072 | if (con_driver_map[i] == csw) { |
3069 | module_put(csw->owner); | 3073 | module_put(csw->owner); |
3070 | con_driver_map[i] = NULL; | 3074 | con_driver_map[i] = NULL; |
3071 | } | 3075 | } |
3072 | } | 3076 | } |
3073 | 3077 | ||
3074 | if (!con_is_bound(defcsw)) { | 3078 | if (!con_is_bound(defcsw)) { |
3075 | const struct consw *defconsw = conswitchp; | 3079 | const struct consw *defconsw = conswitchp; |
3076 | 3080 | ||
3077 | defcsw->con_startup(); | 3081 | defcsw->con_startup(); |
3078 | con_back->flag |= CON_DRIVER_FLAG_INIT; | 3082 | con_back->flag |= CON_DRIVER_FLAG_INIT; |
3079 | /* | 3083 | /* |
3080 | * vgacon may change the default driver to point | 3084 | * vgacon may change the default driver to point |
3081 | * to dummycon, we restore it here... | 3085 | * to dummycon, we restore it here... |
3082 | */ | 3086 | */ |
3083 | conswitchp = defconsw; | 3087 | conswitchp = defconsw; |
3084 | } | 3088 | } |
3085 | 3089 | ||
3086 | if (!con_is_bound(csw)) | 3090 | if (!con_is_bound(csw)) |
3087 | con_driver->flag &= ~CON_DRIVER_FLAG_INIT; | 3091 | con_driver->flag &= ~CON_DRIVER_FLAG_INIT; |
3088 | 3092 | ||
3089 | release_console_sem(); | 3093 | release_console_sem(); |
3090 | /* ignore return value, binding should not fail */ | 3094 | /* ignore return value, binding should not fail */ |
3091 | bind_con_driver(defcsw, first, last, deflt); | 3095 | bind_con_driver(defcsw, first, last, deflt); |
3092 | err: | 3096 | err: |
3093 | module_put(owner); | 3097 | module_put(owner); |
3094 | return retval; | 3098 | return retval; |
3095 | 3099 | ||
3096 | } | 3100 | } |
3097 | EXPORT_SYMBOL(unbind_con_driver); | 3101 | EXPORT_SYMBOL(unbind_con_driver); |
3098 | 3102 | ||
3099 | static int vt_bind(struct con_driver *con) | 3103 | static int vt_bind(struct con_driver *con) |
3100 | { | 3104 | { |
3101 | const struct consw *defcsw = NULL, *csw = NULL; | 3105 | const struct consw *defcsw = NULL, *csw = NULL; |
3102 | int i, more = 1, first = -1, last = -1, deflt = 0; | 3106 | int i, more = 1, first = -1, last = -1, deflt = 0; |
3103 | 3107 | ||
3104 | if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || | 3108 | if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || |
3105 | con_is_graphics(con->con, con->first, con->last)) | 3109 | con_is_graphics(con->con, con->first, con->last)) |
3106 | goto err; | 3110 | goto err; |
3107 | 3111 | ||
3108 | csw = con->con; | 3112 | csw = con->con; |
3109 | 3113 | ||
3110 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 3114 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
3111 | struct con_driver *con = ®istered_con_driver[i]; | 3115 | struct con_driver *con = ®istered_con_driver[i]; |
3112 | 3116 | ||
3113 | if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) { | 3117 | if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) { |
3114 | defcsw = con->con; | 3118 | defcsw = con->con; |
3115 | break; | 3119 | break; |
3116 | } | 3120 | } |
3117 | } | 3121 | } |
3118 | 3122 | ||
3119 | if (!defcsw) | 3123 | if (!defcsw) |
3120 | goto err; | 3124 | goto err; |
3121 | 3125 | ||
3122 | while (more) { | 3126 | while (more) { |
3123 | more = 0; | 3127 | more = 0; |
3124 | 3128 | ||
3125 | for (i = con->first; i <= con->last; i++) { | 3129 | for (i = con->first; i <= con->last; i++) { |
3126 | if (con_driver_map[i] == defcsw) { | 3130 | if (con_driver_map[i] == defcsw) { |
3127 | if (first == -1) | 3131 | if (first == -1) |
3128 | first = i; | 3132 | first = i; |
3129 | last = i; | 3133 | last = i; |
3130 | more = 1; | 3134 | more = 1; |
3131 | } else if (first != -1) | 3135 | } else if (first != -1) |
3132 | break; | 3136 | break; |
3133 | } | 3137 | } |
3134 | 3138 | ||
3135 | if (first == 0 && last == MAX_NR_CONSOLES -1) | 3139 | if (first == 0 && last == MAX_NR_CONSOLES -1) |
3136 | deflt = 1; | 3140 | deflt = 1; |
3137 | 3141 | ||
3138 | if (first != -1) | 3142 | if (first != -1) |
3139 | bind_con_driver(csw, first, last, deflt); | 3143 | bind_con_driver(csw, first, last, deflt); |
3140 | 3144 | ||
3141 | first = -1; | 3145 | first = -1; |
3142 | last = -1; | 3146 | last = -1; |
3143 | deflt = 0; | 3147 | deflt = 0; |
3144 | } | 3148 | } |
3145 | 3149 | ||
3146 | err: | 3150 | err: |
3147 | return 0; | 3151 | return 0; |
3148 | } | 3152 | } |
3149 | 3153 | ||
3150 | static int vt_unbind(struct con_driver *con) | 3154 | static int vt_unbind(struct con_driver *con) |
3151 | { | 3155 | { |
3152 | const struct consw *csw = NULL; | 3156 | const struct consw *csw = NULL; |
3153 | int i, more = 1, first = -1, last = -1, deflt = 0; | 3157 | int i, more = 1, first = -1, last = -1, deflt = 0; |
3154 | 3158 | ||
3155 | if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || | 3159 | if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || |
3156 | con_is_graphics(con->con, con->first, con->last)) | 3160 | con_is_graphics(con->con, con->first, con->last)) |
3157 | goto err; | 3161 | goto err; |
3158 | 3162 | ||
3159 | csw = con->con; | 3163 | csw = con->con; |
3160 | 3164 | ||
3161 | while (more) { | 3165 | while (more) { |
3162 | more = 0; | 3166 | more = 0; |
3163 | 3167 | ||
3164 | for (i = con->first; i <= con->last; i++) { | 3168 | for (i = con->first; i <= con->last; i++) { |
3165 | if (con_driver_map[i] == csw) { | 3169 | if (con_driver_map[i] == csw) { |
3166 | if (first == -1) | 3170 | if (first == -1) |
3167 | first = i; | 3171 | first = i; |
3168 | last = i; | 3172 | last = i; |
3169 | more = 1; | 3173 | more = 1; |
3170 | } else if (first != -1) | 3174 | } else if (first != -1) |
3171 | break; | 3175 | break; |
3172 | } | 3176 | } |
3173 | 3177 | ||
3174 | if (first == 0 && last == MAX_NR_CONSOLES -1) | 3178 | if (first == 0 && last == MAX_NR_CONSOLES -1) |
3175 | deflt = 1; | 3179 | deflt = 1; |
3176 | 3180 | ||
3177 | if (first != -1) | 3181 | if (first != -1) |
3178 | unbind_con_driver(csw, first, last, deflt); | 3182 | unbind_con_driver(csw, first, last, deflt); |
3179 | 3183 | ||
3180 | first = -1; | 3184 | first = -1; |
3181 | last = -1; | 3185 | last = -1; |
3182 | deflt = 0; | 3186 | deflt = 0; |
3183 | } | 3187 | } |
3184 | 3188 | ||
3185 | err: | 3189 | err: |
3186 | return 0; | 3190 | return 0; |
3187 | } | 3191 | } |
3188 | #else | 3192 | #else |
3189 | static inline int vt_bind(struct con_driver *con) | 3193 | static inline int vt_bind(struct con_driver *con) |
3190 | { | 3194 | { |
3191 | return 0; | 3195 | return 0; |
3192 | } | 3196 | } |
3193 | static inline int vt_unbind(struct con_driver *con) | 3197 | static inline int vt_unbind(struct con_driver *con) |
3194 | { | 3198 | { |
3195 | return 0; | 3199 | return 0; |
3196 | } | 3200 | } |
3197 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ | 3201 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ |
3198 | 3202 | ||
3199 | static ssize_t store_bind(struct device *dev, struct device_attribute *attr, | 3203 | static ssize_t store_bind(struct device *dev, struct device_attribute *attr, |
3200 | const char *buf, size_t count) | 3204 | const char *buf, size_t count) |
3201 | { | 3205 | { |
3202 | struct con_driver *con = dev_get_drvdata(dev); | 3206 | struct con_driver *con = dev_get_drvdata(dev); |
3203 | int bind = simple_strtoul(buf, NULL, 0); | 3207 | int bind = simple_strtoul(buf, NULL, 0); |
3204 | 3208 | ||
3205 | if (bind) | 3209 | if (bind) |
3206 | vt_bind(con); | 3210 | vt_bind(con); |
3207 | else | 3211 | else |
3208 | vt_unbind(con); | 3212 | vt_unbind(con); |
3209 | 3213 | ||
3210 | return count; | 3214 | return count; |
3211 | } | 3215 | } |
3212 | 3216 | ||
3213 | static ssize_t show_bind(struct device *dev, struct device_attribute *attr, | 3217 | static ssize_t show_bind(struct device *dev, struct device_attribute *attr, |
3214 | char *buf) | 3218 | char *buf) |
3215 | { | 3219 | { |
3216 | struct con_driver *con = dev_get_drvdata(dev); | 3220 | struct con_driver *con = dev_get_drvdata(dev); |
3217 | int bind = con_is_bound(con->con); | 3221 | int bind = con_is_bound(con->con); |
3218 | 3222 | ||
3219 | return snprintf(buf, PAGE_SIZE, "%i\n", bind); | 3223 | return snprintf(buf, PAGE_SIZE, "%i\n", bind); |
3220 | } | 3224 | } |
3221 | 3225 | ||
3222 | static ssize_t show_name(struct device *dev, struct device_attribute *attr, | 3226 | static ssize_t show_name(struct device *dev, struct device_attribute *attr, |
3223 | char *buf) | 3227 | char *buf) |
3224 | { | 3228 | { |
3225 | struct con_driver *con = dev_get_drvdata(dev); | 3229 | struct con_driver *con = dev_get_drvdata(dev); |
3226 | 3230 | ||
3227 | return snprintf(buf, PAGE_SIZE, "%s %s\n", | 3231 | return snprintf(buf, PAGE_SIZE, "%s %s\n", |
3228 | (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", | 3232 | (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", |
3229 | con->desc); | 3233 | con->desc); |
3230 | 3234 | ||
3231 | } | 3235 | } |
3232 | 3236 | ||
3233 | static struct device_attribute device_attrs[] = { | 3237 | static struct device_attribute device_attrs[] = { |
3234 | __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), | 3238 | __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), |
3235 | __ATTR(name, S_IRUGO, show_name, NULL), | 3239 | __ATTR(name, S_IRUGO, show_name, NULL), |
3236 | }; | 3240 | }; |
3237 | 3241 | ||
3238 | static int vtconsole_init_device(struct con_driver *con) | 3242 | static int vtconsole_init_device(struct con_driver *con) |
3239 | { | 3243 | { |
3240 | int i; | 3244 | int i; |
3241 | int error = 0; | 3245 | int error = 0; |
3242 | 3246 | ||
3243 | con->flag |= CON_DRIVER_FLAG_ATTR; | 3247 | con->flag |= CON_DRIVER_FLAG_ATTR; |
3244 | dev_set_drvdata(con->dev, con); | 3248 | dev_set_drvdata(con->dev, con); |
3245 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { | 3249 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { |
3246 | error = device_create_file(con->dev, &device_attrs[i]); | 3250 | error = device_create_file(con->dev, &device_attrs[i]); |
3247 | if (error) | 3251 | if (error) |
3248 | break; | 3252 | break; |
3249 | } | 3253 | } |
3250 | 3254 | ||
3251 | if (error) { | 3255 | if (error) { |
3252 | while (--i >= 0) | 3256 | while (--i >= 0) |
3253 | device_remove_file(con->dev, &device_attrs[i]); | 3257 | device_remove_file(con->dev, &device_attrs[i]); |
3254 | con->flag &= ~CON_DRIVER_FLAG_ATTR; | 3258 | con->flag &= ~CON_DRIVER_FLAG_ATTR; |
3255 | } | 3259 | } |
3256 | 3260 | ||
3257 | return error; | 3261 | return error; |
3258 | } | 3262 | } |
3259 | 3263 | ||
3260 | static void vtconsole_deinit_device(struct con_driver *con) | 3264 | static void vtconsole_deinit_device(struct con_driver *con) |
3261 | { | 3265 | { |
3262 | int i; | 3266 | int i; |
3263 | 3267 | ||
3264 | if (con->flag & CON_DRIVER_FLAG_ATTR) { | 3268 | if (con->flag & CON_DRIVER_FLAG_ATTR) { |
3265 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) | 3269 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) |
3266 | device_remove_file(con->dev, &device_attrs[i]); | 3270 | device_remove_file(con->dev, &device_attrs[i]); |
3267 | con->flag &= ~CON_DRIVER_FLAG_ATTR; | 3271 | con->flag &= ~CON_DRIVER_FLAG_ATTR; |
3268 | } | 3272 | } |
3269 | } | 3273 | } |
3270 | 3274 | ||
3271 | /** | 3275 | /** |
3272 | * con_is_bound - checks if driver is bound to the console | 3276 | * con_is_bound - checks if driver is bound to the console |
3273 | * @csw: console driver | 3277 | * @csw: console driver |
3274 | * | 3278 | * |
3275 | * RETURNS: zero if unbound, nonzero if bound | 3279 | * RETURNS: zero if unbound, nonzero if bound |
3276 | * | 3280 | * |
3277 | * Drivers can call this and if zero, they should release | 3281 | * Drivers can call this and if zero, they should release |
3278 | * all resources allocated on con_startup() | 3282 | * all resources allocated on con_startup() |
3279 | */ | 3283 | */ |
3280 | int con_is_bound(const struct consw *csw) | 3284 | int con_is_bound(const struct consw *csw) |
3281 | { | 3285 | { |
3282 | int i, bound = 0; | 3286 | int i, bound = 0; |
3283 | 3287 | ||
3284 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 3288 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
3285 | if (con_driver_map[i] == csw) { | 3289 | if (con_driver_map[i] == csw) { |
3286 | bound = 1; | 3290 | bound = 1; |
3287 | break; | 3291 | break; |
3288 | } | 3292 | } |
3289 | } | 3293 | } |
3290 | 3294 | ||
3291 | return bound; | 3295 | return bound; |
3292 | } | 3296 | } |
3293 | EXPORT_SYMBOL(con_is_bound); | 3297 | EXPORT_SYMBOL(con_is_bound); |
3294 | 3298 | ||
3295 | /** | 3299 | /** |
3296 | * register_con_driver - register console driver to console layer | 3300 | * register_con_driver - register console driver to console layer |
3297 | * @csw: console driver | 3301 | * @csw: console driver |
3298 | * @first: the first console to take over, minimum value is 0 | 3302 | * @first: the first console to take over, minimum value is 0 |
3299 | * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1 | 3303 | * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1 |
3300 | * | 3304 | * |
3301 | * DESCRIPTION: This function registers a console driver which can later | 3305 | * DESCRIPTION: This function registers a console driver which can later |
3302 | * bind to a range of consoles specified by @first and @last. It will | 3306 | * bind to a range of consoles specified by @first and @last. It will |
3303 | * also initialize the console driver by calling con_startup(). | 3307 | * also initialize the console driver by calling con_startup(). |
3304 | */ | 3308 | */ |
3305 | int register_con_driver(const struct consw *csw, int first, int last) | 3309 | int register_con_driver(const struct consw *csw, int first, int last) |
3306 | { | 3310 | { |
3307 | struct module *owner = csw->owner; | 3311 | struct module *owner = csw->owner; |
3308 | struct con_driver *con_driver; | 3312 | struct con_driver *con_driver; |
3309 | const char *desc; | 3313 | const char *desc; |
3310 | int i, retval = 0; | 3314 | int i, retval = 0; |
3311 | 3315 | ||
3312 | if (!try_module_get(owner)) | 3316 | if (!try_module_get(owner)) |
3313 | return -ENODEV; | 3317 | return -ENODEV; |
3314 | 3318 | ||
3315 | acquire_console_sem(); | 3319 | acquire_console_sem(); |
3316 | 3320 | ||
3317 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 3321 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
3318 | con_driver = ®istered_con_driver[i]; | 3322 | con_driver = ®istered_con_driver[i]; |
3319 | 3323 | ||
3320 | /* already registered */ | 3324 | /* already registered */ |
3321 | if (con_driver->con == csw) | 3325 | if (con_driver->con == csw) |
3322 | retval = -EINVAL; | 3326 | retval = -EINVAL; |
3323 | } | 3327 | } |
3324 | 3328 | ||
3325 | if (retval) | 3329 | if (retval) |
3326 | goto err; | 3330 | goto err; |
3327 | 3331 | ||
3328 | desc = csw->con_startup(); | 3332 | desc = csw->con_startup(); |
3329 | 3333 | ||
3330 | if (!desc) | 3334 | if (!desc) |
3331 | goto err; | 3335 | goto err; |
3332 | 3336 | ||
3333 | retval = -EINVAL; | 3337 | retval = -EINVAL; |
3334 | 3338 | ||
3335 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 3339 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
3336 | con_driver = ®istered_con_driver[i]; | 3340 | con_driver = ®istered_con_driver[i]; |
3337 | 3341 | ||
3338 | if (con_driver->con == NULL) { | 3342 | if (con_driver->con == NULL) { |
3339 | con_driver->con = csw; | 3343 | con_driver->con = csw; |
3340 | con_driver->desc = desc; | 3344 | con_driver->desc = desc; |
3341 | con_driver->node = i; | 3345 | con_driver->node = i; |
3342 | con_driver->flag = CON_DRIVER_FLAG_MODULE | | 3346 | con_driver->flag = CON_DRIVER_FLAG_MODULE | |
3343 | CON_DRIVER_FLAG_INIT; | 3347 | CON_DRIVER_FLAG_INIT; |
3344 | con_driver->first = first; | 3348 | con_driver->first = first; |
3345 | con_driver->last = last; | 3349 | con_driver->last = last; |
3346 | retval = 0; | 3350 | retval = 0; |
3347 | break; | 3351 | break; |
3348 | } | 3352 | } |
3349 | } | 3353 | } |
3350 | 3354 | ||
3351 | if (retval) | 3355 | if (retval) |
3352 | goto err; | 3356 | goto err; |
3353 | 3357 | ||
3354 | con_driver->dev = device_create(vtconsole_class, NULL, | 3358 | con_driver->dev = device_create(vtconsole_class, NULL, |
3355 | MKDEV(0, con_driver->node), | 3359 | MKDEV(0, con_driver->node), |
3356 | "vtcon%i", con_driver->node); | 3360 | "vtcon%i", con_driver->node); |
3357 | 3361 | ||
3358 | if (IS_ERR(con_driver->dev)) { | 3362 | if (IS_ERR(con_driver->dev)) { |
3359 | printk(KERN_WARNING "Unable to create device for %s; " | 3363 | printk(KERN_WARNING "Unable to create device for %s; " |
3360 | "errno = %ld\n", con_driver->desc, | 3364 | "errno = %ld\n", con_driver->desc, |
3361 | PTR_ERR(con_driver->dev)); | 3365 | PTR_ERR(con_driver->dev)); |
3362 | con_driver->dev = NULL; | 3366 | con_driver->dev = NULL; |
3363 | } else { | 3367 | } else { |
3364 | vtconsole_init_device(con_driver); | 3368 | vtconsole_init_device(con_driver); |
3365 | } | 3369 | } |
3366 | 3370 | ||
3367 | err: | 3371 | err: |
3368 | release_console_sem(); | 3372 | release_console_sem(); |
3369 | module_put(owner); | 3373 | module_put(owner); |
3370 | return retval; | 3374 | return retval; |
3371 | } | 3375 | } |
3372 | EXPORT_SYMBOL(register_con_driver); | 3376 | EXPORT_SYMBOL(register_con_driver); |
3373 | 3377 | ||
3374 | /** | 3378 | /** |
3375 | * unregister_con_driver - unregister console driver from console layer | 3379 | * unregister_con_driver - unregister console driver from console layer |
3376 | * @csw: console driver | 3380 | * @csw: console driver |
3377 | * | 3381 | * |
3378 | * DESCRIPTION: All drivers that registers to the console layer must | 3382 | * DESCRIPTION: All drivers that registers to the console layer must |
3379 | * call this function upon exit, or if the console driver is in a state | 3383 | * call this function upon exit, or if the console driver is in a state |
3380 | * where it won't be able to handle console services, such as the | 3384 | * where it won't be able to handle console services, such as the |
3381 | * framebuffer console without loaded framebuffer drivers. | 3385 | * framebuffer console without loaded framebuffer drivers. |
3382 | * | 3386 | * |
3383 | * The driver must unbind first prior to unregistration. | 3387 | * The driver must unbind first prior to unregistration. |
3384 | */ | 3388 | */ |
3385 | int unregister_con_driver(const struct consw *csw) | 3389 | int unregister_con_driver(const struct consw *csw) |
3386 | { | 3390 | { |
3387 | int i, retval = -ENODEV; | 3391 | int i, retval = -ENODEV; |
3388 | 3392 | ||
3389 | acquire_console_sem(); | 3393 | acquire_console_sem(); |
3390 | 3394 | ||
3391 | /* cannot unregister a bound driver */ | 3395 | /* cannot unregister a bound driver */ |
3392 | if (con_is_bound(csw)) | 3396 | if (con_is_bound(csw)) |
3393 | goto err; | 3397 | goto err; |
3394 | 3398 | ||
3395 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 3399 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
3396 | struct con_driver *con_driver = ®istered_con_driver[i]; | 3400 | struct con_driver *con_driver = ®istered_con_driver[i]; |
3397 | 3401 | ||
3398 | if (con_driver->con == csw && | 3402 | if (con_driver->con == csw && |
3399 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { | 3403 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { |
3400 | vtconsole_deinit_device(con_driver); | 3404 | vtconsole_deinit_device(con_driver); |
3401 | device_destroy(vtconsole_class, | 3405 | device_destroy(vtconsole_class, |
3402 | MKDEV(0, con_driver->node)); | 3406 | MKDEV(0, con_driver->node)); |
3403 | con_driver->con = NULL; | 3407 | con_driver->con = NULL; |
3404 | con_driver->desc = NULL; | 3408 | con_driver->desc = NULL; |
3405 | con_driver->dev = NULL; | 3409 | con_driver->dev = NULL; |
3406 | con_driver->node = 0; | 3410 | con_driver->node = 0; |
3407 | con_driver->flag = 0; | 3411 | con_driver->flag = 0; |
3408 | con_driver->first = 0; | 3412 | con_driver->first = 0; |
3409 | con_driver->last = 0; | 3413 | con_driver->last = 0; |
3410 | retval = 0; | 3414 | retval = 0; |
3411 | break; | 3415 | break; |
3412 | } | 3416 | } |
3413 | } | 3417 | } |
3414 | err: | 3418 | err: |
3415 | release_console_sem(); | 3419 | release_console_sem(); |
3416 | return retval; | 3420 | return retval; |
3417 | } | 3421 | } |
3418 | EXPORT_SYMBOL(unregister_con_driver); | 3422 | EXPORT_SYMBOL(unregister_con_driver); |
3419 | 3423 | ||
3420 | /* | 3424 | /* |
3421 | * If we support more console drivers, this function is used | 3425 | * If we support more console drivers, this function is used |
3422 | * when a driver wants to take over some existing consoles | 3426 | * when a driver wants to take over some existing consoles |
3423 | * and become default driver for newly opened ones. | 3427 | * and become default driver for newly opened ones. |
3424 | * | 3428 | * |
3425 | * take_over_console is basically a register followed by unbind | 3429 | * take_over_console is basically a register followed by unbind |
3426 | */ | 3430 | */ |
3427 | int take_over_console(const struct consw *csw, int first, int last, int deflt) | 3431 | int take_over_console(const struct consw *csw, int first, int last, int deflt) |
3428 | { | 3432 | { |
3429 | int err; | 3433 | int err; |
3430 | 3434 | ||
3431 | err = register_con_driver(csw, first, last); | 3435 | err = register_con_driver(csw, first, last); |
3432 | 3436 | ||
3433 | if (!err) | 3437 | if (!err) |
3434 | bind_con_driver(csw, first, last, deflt); | 3438 | bind_con_driver(csw, first, last, deflt); |
3435 | 3439 | ||
3436 | return err; | 3440 | return err; |
3437 | } | 3441 | } |
3438 | 3442 | ||
3439 | /* | 3443 | /* |
3440 | * give_up_console is a wrapper to unregister_con_driver. It will only | 3444 | * give_up_console is a wrapper to unregister_con_driver. It will only |
3441 | * work if driver is fully unbound. | 3445 | * work if driver is fully unbound. |
3442 | */ | 3446 | */ |
3443 | void give_up_console(const struct consw *csw) | 3447 | void give_up_console(const struct consw *csw) |
3444 | { | 3448 | { |
3445 | unregister_con_driver(csw); | 3449 | unregister_con_driver(csw); |
3446 | } | 3450 | } |
3447 | 3451 | ||
3448 | static int __init vtconsole_class_init(void) | 3452 | static int __init vtconsole_class_init(void) |
3449 | { | 3453 | { |
3450 | int i; | 3454 | int i; |
3451 | 3455 | ||
3452 | vtconsole_class = class_create(THIS_MODULE, "vtconsole"); | 3456 | vtconsole_class = class_create(THIS_MODULE, "vtconsole"); |
3453 | if (IS_ERR(vtconsole_class)) { | 3457 | if (IS_ERR(vtconsole_class)) { |
3454 | printk(KERN_WARNING "Unable to create vt console class; " | 3458 | printk(KERN_WARNING "Unable to create vt console class; " |
3455 | "errno = %ld\n", PTR_ERR(vtconsole_class)); | 3459 | "errno = %ld\n", PTR_ERR(vtconsole_class)); |
3456 | vtconsole_class = NULL; | 3460 | vtconsole_class = NULL; |
3457 | } | 3461 | } |
3458 | 3462 | ||
3459 | /* Add system drivers to sysfs */ | 3463 | /* Add system drivers to sysfs */ |
3460 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 3464 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
3461 | struct con_driver *con = ®istered_con_driver[i]; | 3465 | struct con_driver *con = ®istered_con_driver[i]; |
3462 | 3466 | ||
3463 | if (con->con && !con->dev) { | 3467 | if (con->con && !con->dev) { |
3464 | con->dev = device_create(vtconsole_class, NULL, | 3468 | con->dev = device_create(vtconsole_class, NULL, |
3465 | MKDEV(0, con->node), | 3469 | MKDEV(0, con->node), |
3466 | "vtcon%i", con->node); | 3470 | "vtcon%i", con->node); |
3467 | 3471 | ||
3468 | if (IS_ERR(con->dev)) { | 3472 | if (IS_ERR(con->dev)) { |
3469 | printk(KERN_WARNING "Unable to create " | 3473 | printk(KERN_WARNING "Unable to create " |
3470 | "device for %s; errno = %ld\n", | 3474 | "device for %s; errno = %ld\n", |
3471 | con->desc, PTR_ERR(con->dev)); | 3475 | con->desc, PTR_ERR(con->dev)); |
3472 | con->dev = NULL; | 3476 | con->dev = NULL; |
3473 | } else { | 3477 | } else { |
3474 | vtconsole_init_device(con); | 3478 | vtconsole_init_device(con); |
3475 | } | 3479 | } |
3476 | } | 3480 | } |
3477 | } | 3481 | } |
3478 | 3482 | ||
3479 | return 0; | 3483 | return 0; |
3480 | } | 3484 | } |
3481 | postcore_initcall(vtconsole_class_init); | 3485 | postcore_initcall(vtconsole_class_init); |
3482 | 3486 | ||
3483 | #endif | 3487 | #endif |
3484 | 3488 | ||
3485 | /* | 3489 | /* |
3486 | * Screen blanking | 3490 | * Screen blanking |
3487 | */ | 3491 | */ |
3488 | 3492 | ||
3489 | static int set_vesa_blanking(char __user *p) | 3493 | static int set_vesa_blanking(char __user *p) |
3490 | { | 3494 | { |
3491 | unsigned int mode; | 3495 | unsigned int mode; |
3492 | 3496 | ||
3493 | if (get_user(mode, p + 1)) | 3497 | if (get_user(mode, p + 1)) |
3494 | return -EFAULT; | 3498 | return -EFAULT; |
3495 | 3499 | ||
3496 | vesa_blank_mode = (mode < 4) ? mode : 0; | 3500 | vesa_blank_mode = (mode < 4) ? mode : 0; |
3497 | return 0; | 3501 | return 0; |
3498 | } | 3502 | } |
3499 | 3503 | ||
3500 | void do_blank_screen(int entering_gfx) | 3504 | void do_blank_screen(int entering_gfx) |
3501 | { | 3505 | { |
3502 | struct vc_data *vc = vc_cons[fg_console].d; | 3506 | struct vc_data *vc = vc_cons[fg_console].d; |
3503 | int i; | 3507 | int i; |
3504 | 3508 | ||
3505 | WARN_CONSOLE_UNLOCKED(); | 3509 | WARN_CONSOLE_UNLOCKED(); |
3506 | 3510 | ||
3507 | if (console_blanked) { | 3511 | if (console_blanked) { |
3508 | if (blank_state == blank_vesa_wait) { | 3512 | if (blank_state == blank_vesa_wait) { |
3509 | blank_state = blank_off; | 3513 | blank_state = blank_off; |
3510 | vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0); | 3514 | vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0); |
3511 | } | 3515 | } |
3512 | return; | 3516 | return; |
3513 | } | 3517 | } |
3514 | 3518 | ||
3515 | /* entering graphics mode? */ | 3519 | /* entering graphics mode? */ |
3516 | if (entering_gfx) { | 3520 | if (entering_gfx) { |
3517 | hide_cursor(vc); | 3521 | hide_cursor(vc); |
3518 | save_screen(vc); | 3522 | save_screen(vc); |
3519 | vc->vc_sw->con_blank(vc, -1, 1); | 3523 | vc->vc_sw->con_blank(vc, -1, 1); |
3520 | console_blanked = fg_console + 1; | 3524 | console_blanked = fg_console + 1; |
3521 | blank_state = blank_off; | 3525 | blank_state = blank_off; |
3522 | set_origin(vc); | 3526 | set_origin(vc); |
3523 | return; | 3527 | return; |
3524 | } | 3528 | } |
3525 | 3529 | ||
3526 | if (blank_state != blank_normal_wait) | 3530 | if (blank_state != blank_normal_wait) |
3527 | return; | 3531 | return; |
3528 | blank_state = blank_off; | 3532 | blank_state = blank_off; |
3529 | 3533 | ||
3530 | /* don't blank graphics */ | 3534 | /* don't blank graphics */ |
3531 | if (vc->vc_mode != KD_TEXT) { | 3535 | if (vc->vc_mode != KD_TEXT) { |
3532 | console_blanked = fg_console + 1; | 3536 | console_blanked = fg_console + 1; |
3533 | return; | 3537 | return; |
3534 | } | 3538 | } |
3535 | 3539 | ||
3536 | hide_cursor(vc); | 3540 | hide_cursor(vc); |
3537 | del_timer_sync(&console_timer); | 3541 | del_timer_sync(&console_timer); |
3538 | blank_timer_expired = 0; | 3542 | blank_timer_expired = 0; |
3539 | 3543 | ||
3540 | save_screen(vc); | 3544 | save_screen(vc); |
3541 | /* In case we need to reset origin, blanking hook returns 1 */ | 3545 | /* In case we need to reset origin, blanking hook returns 1 */ |
3542 | i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0); | 3546 | i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0); |
3543 | console_blanked = fg_console + 1; | 3547 | console_blanked = fg_console + 1; |
3544 | if (i) | 3548 | if (i) |
3545 | set_origin(vc); | 3549 | set_origin(vc); |
3546 | 3550 | ||
3547 | if (console_blank_hook && console_blank_hook(1)) | 3551 | if (console_blank_hook && console_blank_hook(1)) |
3548 | return; | 3552 | return; |
3549 | 3553 | ||
3550 | if (vesa_off_interval && vesa_blank_mode) { | 3554 | if (vesa_off_interval && vesa_blank_mode) { |
3551 | blank_state = blank_vesa_wait; | 3555 | blank_state = blank_vesa_wait; |
3552 | mod_timer(&console_timer, jiffies + vesa_off_interval); | 3556 | mod_timer(&console_timer, jiffies + vesa_off_interval); |
3553 | } | 3557 | } |
3554 | } | 3558 | } |
3555 | EXPORT_SYMBOL(do_blank_screen); | 3559 | EXPORT_SYMBOL(do_blank_screen); |
3556 | 3560 | ||
3557 | /* | 3561 | /* |
3558 | * Called by timer as well as from vt_console_driver | 3562 | * Called by timer as well as from vt_console_driver |
3559 | */ | 3563 | */ |
3560 | void do_unblank_screen(int leaving_gfx) | 3564 | void do_unblank_screen(int leaving_gfx) |
3561 | { | 3565 | { |
3562 | struct vc_data *vc; | 3566 | struct vc_data *vc; |
3563 | 3567 | ||
3564 | /* This should now always be called from a "sane" (read: can schedule) | 3568 | /* This should now always be called from a "sane" (read: can schedule) |
3565 | * context for the sake of the low level drivers, except in the special | 3569 | * context for the sake of the low level drivers, except in the special |
3566 | * case of oops_in_progress | 3570 | * case of oops_in_progress |
3567 | */ | 3571 | */ |
3568 | if (!oops_in_progress) | 3572 | if (!oops_in_progress) |
3569 | might_sleep(); | 3573 | might_sleep(); |
3570 | 3574 | ||
3571 | WARN_CONSOLE_UNLOCKED(); | 3575 | WARN_CONSOLE_UNLOCKED(); |
3572 | 3576 | ||
3573 | ignore_poke = 0; | 3577 | ignore_poke = 0; |
3574 | if (!console_blanked) | 3578 | if (!console_blanked) |
3575 | return; | 3579 | return; |
3576 | if (!vc_cons_allocated(fg_console)) { | 3580 | if (!vc_cons_allocated(fg_console)) { |
3577 | /* impossible */ | 3581 | /* impossible */ |
3578 | printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); | 3582 | printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); |
3579 | return; | 3583 | return; |
3580 | } | 3584 | } |
3581 | vc = vc_cons[fg_console].d; | 3585 | vc = vc_cons[fg_console].d; |
3582 | if (vc->vc_mode != KD_TEXT) | 3586 | if (vc->vc_mode != KD_TEXT) |
3583 | return; /* but leave console_blanked != 0 */ | 3587 | return; /* but leave console_blanked != 0 */ |
3584 | 3588 | ||
3585 | if (blankinterval) { | 3589 | if (blankinterval) { |
3586 | mod_timer(&console_timer, jiffies + blankinterval); | 3590 | mod_timer(&console_timer, jiffies + blankinterval); |
3587 | blank_state = blank_normal_wait; | 3591 | blank_state = blank_normal_wait; |
3588 | } | 3592 | } |
3589 | 3593 | ||
3590 | console_blanked = 0; | 3594 | console_blanked = 0; |
3591 | if (vc->vc_sw->con_blank(vc, 0, leaving_gfx)) | 3595 | if (vc->vc_sw->con_blank(vc, 0, leaving_gfx)) |
3592 | /* Low-level driver cannot restore -> do it ourselves */ | 3596 | /* Low-level driver cannot restore -> do it ourselves */ |
3593 | update_screen(vc); | 3597 | update_screen(vc); |
3594 | if (console_blank_hook) | 3598 | if (console_blank_hook) |
3595 | console_blank_hook(0); | 3599 | console_blank_hook(0); |
3596 | set_palette(vc); | 3600 | set_palette(vc); |
3597 | set_cursor(vc); | 3601 | set_cursor(vc); |
3598 | } | 3602 | } |
3599 | EXPORT_SYMBOL(do_unblank_screen); | 3603 | EXPORT_SYMBOL(do_unblank_screen); |
3600 | 3604 | ||
3601 | /* | 3605 | /* |
3602 | * This is called by the outside world to cause a forced unblank, mostly for | 3606 | * This is called by the outside world to cause a forced unblank, mostly for |
3603 | * oopses. Currently, I just call do_unblank_screen(0), but we could eventually | 3607 | * oopses. Currently, I just call do_unblank_screen(0), but we could eventually |
3604 | * call it with 1 as an argument and so force a mode restore... that may kill | 3608 | * call it with 1 as an argument and so force a mode restore... that may kill |
3605 | * X or at least garbage the screen but would also make the Oops visible... | 3609 | * X or at least garbage the screen but would also make the Oops visible... |
3606 | */ | 3610 | */ |
3607 | void unblank_screen(void) | 3611 | void unblank_screen(void) |
3608 | { | 3612 | { |
3609 | do_unblank_screen(0); | 3613 | do_unblank_screen(0); |
3610 | } | 3614 | } |
3611 | 3615 | ||
3612 | /* | 3616 | /* |
3613 | * We defer the timer blanking to work queue so it can take the console mutex | 3617 | * We defer the timer blanking to work queue so it can take the console mutex |
3614 | * (console operations can still happen at irq time, but only from printk which | 3618 | * (console operations can still happen at irq time, but only from printk which |
3615 | * has the console mutex. Not perfect yet, but better than no locking | 3619 | * has the console mutex. Not perfect yet, but better than no locking |
3616 | */ | 3620 | */ |
3617 | static void blank_screen_t(unsigned long dummy) | 3621 | static void blank_screen_t(unsigned long dummy) |
3618 | { | 3622 | { |
3619 | if (unlikely(!keventd_up())) { | 3623 | if (unlikely(!keventd_up())) { |
3620 | mod_timer(&console_timer, jiffies + blankinterval); | 3624 | mod_timer(&console_timer, jiffies + blankinterval); |
3621 | return; | 3625 | return; |
3622 | } | 3626 | } |
3623 | blank_timer_expired = 1; | 3627 | blank_timer_expired = 1; |
3624 | schedule_work(&console_work); | 3628 | schedule_work(&console_work); |
3625 | } | 3629 | } |
3626 | 3630 | ||
3627 | void poke_blanked_console(void) | 3631 | void poke_blanked_console(void) |
3628 | { | 3632 | { |
3629 | WARN_CONSOLE_UNLOCKED(); | 3633 | WARN_CONSOLE_UNLOCKED(); |
3630 | 3634 | ||
3631 | /* Add this so we quickly catch whoever might call us in a non | 3635 | /* Add this so we quickly catch whoever might call us in a non |
3632 | * safe context. Nowadays, unblank_screen() isn't to be called in | 3636 | * safe context. Nowadays, unblank_screen() isn't to be called in |
3633 | * atomic contexts and is allowed to schedule (with the special case | 3637 | * atomic contexts and is allowed to schedule (with the special case |
3634 | * of oops_in_progress, but that isn't of any concern for this | 3638 | * of oops_in_progress, but that isn't of any concern for this |
3635 | * function. --BenH. | 3639 | * function. --BenH. |
3636 | */ | 3640 | */ |
3637 | might_sleep(); | 3641 | might_sleep(); |
3638 | 3642 | ||
3639 | /* This isn't perfectly race free, but a race here would be mostly harmless, | 3643 | /* This isn't perfectly race free, but a race here would be mostly harmless, |
3640 | * at worse, we'll do a spurrious blank and it's unlikely | 3644 | * at worse, we'll do a spurrious blank and it's unlikely |
3641 | */ | 3645 | */ |
3642 | del_timer(&console_timer); | 3646 | del_timer(&console_timer); |
3643 | blank_timer_expired = 0; | 3647 | blank_timer_expired = 0; |
3644 | 3648 | ||
3645 | if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS) | 3649 | if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS) |
3646 | return; | 3650 | return; |
3647 | if (console_blanked) | 3651 | if (console_blanked) |
3648 | unblank_screen(); | 3652 | unblank_screen(); |
3649 | else if (blankinterval) { | 3653 | else if (blankinterval) { |
3650 | mod_timer(&console_timer, jiffies + blankinterval); | 3654 | mod_timer(&console_timer, jiffies + blankinterval); |
3651 | blank_state = blank_normal_wait; | 3655 | blank_state = blank_normal_wait; |
3652 | } | 3656 | } |
3653 | } | 3657 | } |
3654 | 3658 | ||
3655 | /* | 3659 | /* |
3656 | * Palettes | 3660 | * Palettes |
3657 | */ | 3661 | */ |
3658 | 3662 | ||
3659 | static void set_palette(struct vc_data *vc) | 3663 | static void set_palette(struct vc_data *vc) |
3660 | { | 3664 | { |
3661 | WARN_CONSOLE_UNLOCKED(); | 3665 | WARN_CONSOLE_UNLOCKED(); |
3662 | 3666 | ||
3663 | if (vc->vc_mode != KD_GRAPHICS) | 3667 | if (vc->vc_mode != KD_GRAPHICS) |
3664 | vc->vc_sw->con_set_palette(vc, color_table); | 3668 | vc->vc_sw->con_set_palette(vc, color_table); |
3665 | } | 3669 | } |
3666 | 3670 | ||
3667 | static int set_get_cmap(unsigned char __user *arg, int set) | 3671 | static int set_get_cmap(unsigned char __user *arg, int set) |
3668 | { | 3672 | { |
3669 | int i, j, k; | 3673 | int i, j, k; |
3670 | 3674 | ||
3671 | WARN_CONSOLE_UNLOCKED(); | 3675 | WARN_CONSOLE_UNLOCKED(); |
3672 | 3676 | ||
3673 | for (i = 0; i < 16; i++) | 3677 | for (i = 0; i < 16; i++) |
3674 | if (set) { | 3678 | if (set) { |
3675 | get_user(default_red[i], arg++); | 3679 | get_user(default_red[i], arg++); |
3676 | get_user(default_grn[i], arg++); | 3680 | get_user(default_grn[i], arg++); |
3677 | get_user(default_blu[i], arg++); | 3681 | get_user(default_blu[i], arg++); |
3678 | } else { | 3682 | } else { |
3679 | put_user(default_red[i], arg++); | 3683 | put_user(default_red[i], arg++); |
3680 | put_user(default_grn[i], arg++); | 3684 | put_user(default_grn[i], arg++); |
3681 | put_user(default_blu[i], arg++); | 3685 | put_user(default_blu[i], arg++); |
3682 | } | 3686 | } |
3683 | if (set) { | 3687 | if (set) { |
3684 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 3688 | for (i = 0; i < MAX_NR_CONSOLES; i++) |
3685 | if (vc_cons_allocated(i)) { | 3689 | if (vc_cons_allocated(i)) { |
3686 | for (j = k = 0; j < 16; j++) { | 3690 | for (j = k = 0; j < 16; j++) { |
3687 | vc_cons[i].d->vc_palette[k++] = default_red[j]; | 3691 | vc_cons[i].d->vc_palette[k++] = default_red[j]; |
3688 | vc_cons[i].d->vc_palette[k++] = default_grn[j]; | 3692 | vc_cons[i].d->vc_palette[k++] = default_grn[j]; |
3689 | vc_cons[i].d->vc_palette[k++] = default_blu[j]; | 3693 | vc_cons[i].d->vc_palette[k++] = default_blu[j]; |
3690 | } | 3694 | } |
3691 | set_palette(vc_cons[i].d); | 3695 | set_palette(vc_cons[i].d); |
3692 | } | 3696 | } |
3693 | } | 3697 | } |
3694 | return 0; | 3698 | return 0; |
3695 | } | 3699 | } |
3696 | 3700 | ||
3697 | /* | 3701 | /* |
3698 | * Load palette into the DAC registers. arg points to a colour | 3702 | * Load palette into the DAC registers. arg points to a colour |
3699 | * map, 3 bytes per colour, 16 colours, range from 0 to 255. | 3703 | * map, 3 bytes per colour, 16 colours, range from 0 to 255. |
3700 | */ | 3704 | */ |
3701 | 3705 | ||
3702 | int con_set_cmap(unsigned char __user *arg) | 3706 | int con_set_cmap(unsigned char __user *arg) |
3703 | { | 3707 | { |
3704 | int rc; | 3708 | int rc; |
3705 | 3709 | ||
3706 | acquire_console_sem(); | 3710 | acquire_console_sem(); |
3707 | rc = set_get_cmap (arg,1); | 3711 | rc = set_get_cmap (arg,1); |
3708 | release_console_sem(); | 3712 | release_console_sem(); |
3709 | 3713 | ||
3710 | return rc; | 3714 | return rc; |
3711 | } | 3715 | } |
3712 | 3716 | ||
3713 | int con_get_cmap(unsigned char __user *arg) | 3717 | int con_get_cmap(unsigned char __user *arg) |
3714 | { | 3718 | { |
3715 | int rc; | 3719 | int rc; |
3716 | 3720 | ||
3717 | acquire_console_sem(); | 3721 | acquire_console_sem(); |
3718 | rc = set_get_cmap (arg,0); | 3722 | rc = set_get_cmap (arg,0); |
3719 | release_console_sem(); | 3723 | release_console_sem(); |
3720 | 3724 | ||
3721 | return rc; | 3725 | return rc; |
3722 | } | 3726 | } |
3723 | 3727 | ||
3724 | void reset_palette(struct vc_data *vc) | 3728 | void reset_palette(struct vc_data *vc) |
3725 | { | 3729 | { |
3726 | int j, k; | 3730 | int j, k; |
3727 | for (j=k=0; j<16; j++) { | 3731 | for (j=k=0; j<16; j++) { |
3728 | vc->vc_palette[k++] = default_red[j]; | 3732 | vc->vc_palette[k++] = default_red[j]; |
3729 | vc->vc_palette[k++] = default_grn[j]; | 3733 | vc->vc_palette[k++] = default_grn[j]; |
3730 | vc->vc_palette[k++] = default_blu[j]; | 3734 | vc->vc_palette[k++] = default_blu[j]; |
3731 | } | 3735 | } |
3732 | set_palette(vc); | 3736 | set_palette(vc); |
3733 | } | 3737 | } |
3734 | 3738 | ||
3735 | /* | 3739 | /* |
3736 | * Font switching | 3740 | * Font switching |
3737 | * | 3741 | * |
3738 | * Currently we only support fonts up to 32 pixels wide, at a maximum height | 3742 | * Currently we only support fonts up to 32 pixels wide, at a maximum height |
3739 | * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, | 3743 | * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, |
3740 | * depending on width) reserved for each character which is kinda wasty, but | 3744 | * depending on width) reserved for each character which is kinda wasty, but |
3741 | * this is done in order to maintain compatibility with the EGA/VGA fonts. It | 3745 | * this is done in order to maintain compatibility with the EGA/VGA fonts. It |
3742 | * is upto the actual low-level console-driver convert data into its favorite | 3746 | * is upto the actual low-level console-driver convert data into its favorite |
3743 | * format (maybe we should add a `fontoffset' field to the `display' | 3747 | * format (maybe we should add a `fontoffset' field to the `display' |
3744 | * structure so we won't have to convert the fontdata all the time. | 3748 | * structure so we won't have to convert the fontdata all the time. |
3745 | * /Jes | 3749 | * /Jes |
3746 | */ | 3750 | */ |
3747 | 3751 | ||
3748 | #define max_font_size 65536 | 3752 | #define max_font_size 65536 |
3749 | 3753 | ||
3750 | static int con_font_get(struct vc_data *vc, struct console_font_op *op) | 3754 | static int con_font_get(struct vc_data *vc, struct console_font_op *op) |
3751 | { | 3755 | { |
3752 | struct console_font font; | 3756 | struct console_font font; |
3753 | int rc = -EINVAL; | 3757 | int rc = -EINVAL; |
3754 | int c; | 3758 | int c; |
3755 | 3759 | ||
3756 | if (vc->vc_mode != KD_TEXT) | 3760 | if (vc->vc_mode != KD_TEXT) |
3757 | return -EINVAL; | 3761 | return -EINVAL; |
3758 | 3762 | ||
3759 | if (op->data) { | 3763 | if (op->data) { |
3760 | font.data = kmalloc(max_font_size, GFP_KERNEL); | 3764 | font.data = kmalloc(max_font_size, GFP_KERNEL); |
3761 | if (!font.data) | 3765 | if (!font.data) |
3762 | return -ENOMEM; | 3766 | return -ENOMEM; |
3763 | } else | 3767 | } else |
3764 | font.data = NULL; | 3768 | font.data = NULL; |
3765 | 3769 | ||
3766 | acquire_console_sem(); | 3770 | acquire_console_sem(); |
3767 | if (vc->vc_sw->con_font_get) | 3771 | if (vc->vc_sw->con_font_get) |
3768 | rc = vc->vc_sw->con_font_get(vc, &font); | 3772 | rc = vc->vc_sw->con_font_get(vc, &font); |
3769 | else | 3773 | else |
3770 | rc = -ENOSYS; | 3774 | rc = -ENOSYS; |
3771 | release_console_sem(); | 3775 | release_console_sem(); |
3772 | 3776 | ||
3773 | if (rc) | 3777 | if (rc) |
3774 | goto out; | 3778 | goto out; |
3775 | 3779 | ||
3776 | c = (font.width+7)/8 * 32 * font.charcount; | 3780 | c = (font.width+7)/8 * 32 * font.charcount; |
3777 | 3781 | ||
3778 | if (op->data && font.charcount > op->charcount) | 3782 | if (op->data && font.charcount > op->charcount) |
3779 | rc = -ENOSPC; | 3783 | rc = -ENOSPC; |
3780 | if (!(op->flags & KD_FONT_FLAG_OLD)) { | 3784 | if (!(op->flags & KD_FONT_FLAG_OLD)) { |
3781 | if (font.width > op->width || font.height > op->height) | 3785 | if (font.width > op->width || font.height > op->height) |
3782 | rc = -ENOSPC; | 3786 | rc = -ENOSPC; |
3783 | } else { | 3787 | } else { |
3784 | if (font.width != 8) | 3788 | if (font.width != 8) |
3785 | rc = -EIO; | 3789 | rc = -EIO; |
3786 | else if ((op->height && font.height > op->height) || | 3790 | else if ((op->height && font.height > op->height) || |
3787 | font.height > 32) | 3791 | font.height > 32) |
3788 | rc = -ENOSPC; | 3792 | rc = -ENOSPC; |
3789 | } | 3793 | } |
3790 | if (rc) | 3794 | if (rc) |
3791 | goto out; | 3795 | goto out; |
3792 | 3796 | ||
3793 | op->height = font.height; | 3797 | op->height = font.height; |
3794 | op->width = font.width; | 3798 | op->width = font.width; |
3795 | op->charcount = font.charcount; | 3799 | op->charcount = font.charcount; |
3796 | 3800 | ||
3797 | if (op->data && copy_to_user(op->data, font.data, c)) | 3801 | if (op->data && copy_to_user(op->data, font.data, c)) |
3798 | rc = -EFAULT; | 3802 | rc = -EFAULT; |
3799 | 3803 | ||
3800 | out: | 3804 | out: |
3801 | kfree(font.data); | 3805 | kfree(font.data); |
3802 | return rc; | 3806 | return rc; |
3803 | } | 3807 | } |
3804 | 3808 | ||
3805 | static int con_font_set(struct vc_data *vc, struct console_font_op *op) | 3809 | static int con_font_set(struct vc_data *vc, struct console_font_op *op) |
3806 | { | 3810 | { |
3807 | struct console_font font; | 3811 | struct console_font font; |
3808 | int rc = -EINVAL; | 3812 | int rc = -EINVAL; |
3809 | int size; | 3813 | int size; |
3810 | 3814 | ||
3811 | if (vc->vc_mode != KD_TEXT) | 3815 | if (vc->vc_mode != KD_TEXT) |
3812 | return -EINVAL; | 3816 | return -EINVAL; |
3813 | if (!op->data) | 3817 | if (!op->data) |
3814 | return -EINVAL; | 3818 | return -EINVAL; |
3815 | if (op->charcount > 512) | 3819 | if (op->charcount > 512) |
3816 | return -EINVAL; | 3820 | return -EINVAL; |
3817 | if (!op->height) { /* Need to guess font height [compat] */ | 3821 | if (!op->height) { /* Need to guess font height [compat] */ |
3818 | int h, i; | 3822 | int h, i; |
3819 | u8 __user *charmap = op->data; | 3823 | u8 __user *charmap = op->data; |
3820 | u8 tmp; | 3824 | u8 tmp; |
3821 | 3825 | ||
3822 | /* If from KDFONTOP ioctl, don't allow things which can be done in userland, | 3826 | /* If from KDFONTOP ioctl, don't allow things which can be done in userland, |
3823 | so that we can get rid of this soon */ | 3827 | so that we can get rid of this soon */ |
3824 | if (!(op->flags & KD_FONT_FLAG_OLD)) | 3828 | if (!(op->flags & KD_FONT_FLAG_OLD)) |
3825 | return -EINVAL; | 3829 | return -EINVAL; |
3826 | for (h = 32; h > 0; h--) | 3830 | for (h = 32; h > 0; h--) |
3827 | for (i = 0; i < op->charcount; i++) { | 3831 | for (i = 0; i < op->charcount; i++) { |
3828 | if (get_user(tmp, &charmap[32*i+h-1])) | 3832 | if (get_user(tmp, &charmap[32*i+h-1])) |
3829 | return -EFAULT; | 3833 | return -EFAULT; |
3830 | if (tmp) | 3834 | if (tmp) |
3831 | goto nonzero; | 3835 | goto nonzero; |
3832 | } | 3836 | } |
3833 | return -EINVAL; | 3837 | return -EINVAL; |
3834 | nonzero: | 3838 | nonzero: |
3835 | op->height = h; | 3839 | op->height = h; |
3836 | } | 3840 | } |
3837 | if (op->width <= 0 || op->width > 32 || op->height > 32) | 3841 | if (op->width <= 0 || op->width > 32 || op->height > 32) |
3838 | return -EINVAL; | 3842 | return -EINVAL; |
3839 | size = (op->width+7)/8 * 32 * op->charcount; | 3843 | size = (op->width+7)/8 * 32 * op->charcount; |
3840 | if (size > max_font_size) | 3844 | if (size > max_font_size) |
3841 | return -ENOSPC; | 3845 | return -ENOSPC; |
3842 | font.charcount = op->charcount; | 3846 | font.charcount = op->charcount; |
3843 | font.height = op->height; | 3847 | font.height = op->height; |
3844 | font.width = op->width; | 3848 | font.width = op->width; |
3845 | font.data = kmalloc(size, GFP_KERNEL); | 3849 | font.data = kmalloc(size, GFP_KERNEL); |
3846 | if (!font.data) | 3850 | if (!font.data) |
3847 | return -ENOMEM; | 3851 | return -ENOMEM; |
3848 | if (copy_from_user(font.data, op->data, size)) { | 3852 | if (copy_from_user(font.data, op->data, size)) { |
3849 | kfree(font.data); | 3853 | kfree(font.data); |
3850 | return -EFAULT; | 3854 | return -EFAULT; |
3851 | } | 3855 | } |
3852 | acquire_console_sem(); | 3856 | acquire_console_sem(); |
3853 | if (vc->vc_sw->con_font_set) | 3857 | if (vc->vc_sw->con_font_set) |
3854 | rc = vc->vc_sw->con_font_set(vc, &font, op->flags); | 3858 | rc = vc->vc_sw->con_font_set(vc, &font, op->flags); |
3855 | else | 3859 | else |
3856 | rc = -ENOSYS; | 3860 | rc = -ENOSYS; |
3857 | release_console_sem(); | 3861 | release_console_sem(); |
3858 | kfree(font.data); | 3862 | kfree(font.data); |
3859 | return rc; | 3863 | return rc; |
3860 | } | 3864 | } |
3861 | 3865 | ||
3862 | static int con_font_default(struct vc_data *vc, struct console_font_op *op) | 3866 | static int con_font_default(struct vc_data *vc, struct console_font_op *op) |
3863 | { | 3867 | { |
3864 | struct console_font font = {.width = op->width, .height = op->height}; | 3868 | struct console_font font = {.width = op->width, .height = op->height}; |
3865 | char name[MAX_FONT_NAME]; | 3869 | char name[MAX_FONT_NAME]; |
3866 | char *s = name; | 3870 | char *s = name; |
3867 | int rc; | 3871 | int rc; |
3868 | 3872 | ||
3869 | if (vc->vc_mode != KD_TEXT) | 3873 | if (vc->vc_mode != KD_TEXT) |
3870 | return -EINVAL; | 3874 | return -EINVAL; |
3871 | 3875 | ||
3872 | if (!op->data) | 3876 | if (!op->data) |
3873 | s = NULL; | 3877 | s = NULL; |
3874 | else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0) | 3878 | else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0) |
3875 | return -EFAULT; | 3879 | return -EFAULT; |
3876 | else | 3880 | else |
3877 | name[MAX_FONT_NAME - 1] = 0; | 3881 | name[MAX_FONT_NAME - 1] = 0; |
3878 | 3882 | ||
3879 | acquire_console_sem(); | 3883 | acquire_console_sem(); |
3880 | if (vc->vc_sw->con_font_default) | 3884 | if (vc->vc_sw->con_font_default) |
3881 | rc = vc->vc_sw->con_font_default(vc, &font, s); | 3885 | rc = vc->vc_sw->con_font_default(vc, &font, s); |
3882 | else | 3886 | else |
3883 | rc = -ENOSYS; | 3887 | rc = -ENOSYS; |
3884 | release_console_sem(); | 3888 | release_console_sem(); |
3885 | if (!rc) { | 3889 | if (!rc) { |
3886 | op->width = font.width; | 3890 | op->width = font.width; |
3887 | op->height = font.height; | 3891 | op->height = font.height; |
3888 | } | 3892 | } |
3889 | return rc; | 3893 | return rc; |
3890 | } | 3894 | } |
3891 | 3895 | ||
3892 | static int con_font_copy(struct vc_data *vc, struct console_font_op *op) | 3896 | static int con_font_copy(struct vc_data *vc, struct console_font_op *op) |
3893 | { | 3897 | { |
3894 | int con = op->height; | 3898 | int con = op->height; |
3895 | int rc; | 3899 | int rc; |
3896 | 3900 | ||
3897 | if (vc->vc_mode != KD_TEXT) | 3901 | if (vc->vc_mode != KD_TEXT) |
3898 | return -EINVAL; | 3902 | return -EINVAL; |
3899 | 3903 | ||
3900 | acquire_console_sem(); | 3904 | acquire_console_sem(); |
3901 | if (!vc->vc_sw->con_font_copy) | 3905 | if (!vc->vc_sw->con_font_copy) |
3902 | rc = -ENOSYS; | 3906 | rc = -ENOSYS; |
3903 | else if (con < 0 || !vc_cons_allocated(con)) | 3907 | else if (con < 0 || !vc_cons_allocated(con)) |
3904 | rc = -ENOTTY; | 3908 | rc = -ENOTTY; |
3905 | else if (con == vc->vc_num) /* nothing to do */ | 3909 | else if (con == vc->vc_num) /* nothing to do */ |
3906 | rc = 0; | 3910 | rc = 0; |
3907 | else | 3911 | else |
3908 | rc = vc->vc_sw->con_font_copy(vc, con); | 3912 | rc = vc->vc_sw->con_font_copy(vc, con); |
3909 | release_console_sem(); | 3913 | release_console_sem(); |
3910 | return rc; | 3914 | return rc; |
3911 | } | 3915 | } |
3912 | 3916 | ||
3913 | int con_font_op(struct vc_data *vc, struct console_font_op *op) | 3917 | int con_font_op(struct vc_data *vc, struct console_font_op *op) |
3914 | { | 3918 | { |
3915 | switch (op->op) { | 3919 | switch (op->op) { |
3916 | case KD_FONT_OP_SET: | 3920 | case KD_FONT_OP_SET: |
3917 | return con_font_set(vc, op); | 3921 | return con_font_set(vc, op); |
3918 | case KD_FONT_OP_GET: | 3922 | case KD_FONT_OP_GET: |
3919 | return con_font_get(vc, op); | 3923 | return con_font_get(vc, op); |
3920 | case KD_FONT_OP_SET_DEFAULT: | 3924 | case KD_FONT_OP_SET_DEFAULT: |
3921 | return con_font_default(vc, op); | 3925 | return con_font_default(vc, op); |
3922 | case KD_FONT_OP_COPY: | 3926 | case KD_FONT_OP_COPY: |
3923 | return con_font_copy(vc, op); | 3927 | return con_font_copy(vc, op); |
3924 | } | 3928 | } |
3925 | return -ENOSYS; | 3929 | return -ENOSYS; |
3926 | } | 3930 | } |
3927 | 3931 | ||
3928 | /* | 3932 | /* |
3929 | * Interface exported to selection and vcs. | 3933 | * Interface exported to selection and vcs. |
3930 | */ | 3934 | */ |
3931 | 3935 | ||
3932 | /* used by selection */ | 3936 | /* used by selection */ |
3933 | u16 screen_glyph(struct vc_data *vc, int offset) | 3937 | u16 screen_glyph(struct vc_data *vc, int offset) |
3934 | { | 3938 | { |
3935 | u16 w = scr_readw(screenpos(vc, offset, 1)); | 3939 | u16 w = scr_readw(screenpos(vc, offset, 1)); |
3936 | u16 c = w & 0xff; | 3940 | u16 c = w & 0xff; |
3937 | 3941 | ||
3938 | if (w & vc->vc_hi_font_mask) | 3942 | if (w & vc->vc_hi_font_mask) |
3939 | c |= 0x100; | 3943 | c |= 0x100; |
3940 | return c; | 3944 | return c; |
3941 | } | 3945 | } |
3942 | 3946 | ||
3943 | /* used by vcs - note the word offset */ | 3947 | /* used by vcs - note the word offset */ |
3944 | unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) | 3948 | unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) |
3945 | { | 3949 | { |
3946 | return screenpos(vc, 2 * w_offset, viewed); | 3950 | return screenpos(vc, 2 * w_offset, viewed); |
3947 | } | 3951 | } |
3948 | 3952 | ||
3949 | void getconsxy(struct vc_data *vc, unsigned char *p) | 3953 | void getconsxy(struct vc_data *vc, unsigned char *p) |
3950 | { | 3954 | { |
3951 | p[0] = vc->vc_x; | 3955 | p[0] = vc->vc_x; |
3952 | p[1] = vc->vc_y; | 3956 | p[1] = vc->vc_y; |
3953 | } | 3957 | } |
3954 | 3958 | ||
3955 | void putconsxy(struct vc_data *vc, unsigned char *p) | 3959 | void putconsxy(struct vc_data *vc, unsigned char *p) |
3956 | { | 3960 | { |
3957 | hide_cursor(vc); | 3961 | hide_cursor(vc); |
3958 | gotoxy(vc, p[0], p[1]); | 3962 | gotoxy(vc, p[0], p[1]); |
3959 | set_cursor(vc); | 3963 | set_cursor(vc); |
3960 | } | 3964 | } |
3961 | 3965 | ||
3962 | u16 vcs_scr_readw(struct vc_data *vc, const u16 *org) | 3966 | u16 vcs_scr_readw(struct vc_data *vc, const u16 *org) |
3963 | { | 3967 | { |
3964 | if ((unsigned long)org == vc->vc_pos && softcursor_original != -1) | 3968 | if ((unsigned long)org == vc->vc_pos && softcursor_original != -1) |
3965 | return softcursor_original; | 3969 | return softcursor_original; |
3966 | return scr_readw(org); | 3970 | return scr_readw(org); |
3967 | } | 3971 | } |
3968 | 3972 | ||
3969 | void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) | 3973 | void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) |
3970 | { | 3974 | { |
3971 | scr_writew(val, org); | 3975 | scr_writew(val, org); |
3972 | if ((unsigned long)org == vc->vc_pos) { | 3976 | if ((unsigned long)org == vc->vc_pos) { |
3973 | softcursor_original = -1; | 3977 | softcursor_original = -1; |
3974 | add_softcursor(vc); | 3978 | add_softcursor(vc); |
3975 | } | 3979 | } |
3976 | } | 3980 | } |
3977 | 3981 | ||
3978 | /* | 3982 | /* |
3979 | * Visible symbols for modules | 3983 | * Visible symbols for modules |
3980 | */ | 3984 | */ |
3981 | 3985 | ||
3982 | EXPORT_SYMBOL(color_table); | 3986 | EXPORT_SYMBOL(color_table); |
3983 | EXPORT_SYMBOL(default_red); | 3987 | EXPORT_SYMBOL(default_red); |
3984 | EXPORT_SYMBOL(default_grn); | 3988 | EXPORT_SYMBOL(default_grn); |
3985 | EXPORT_SYMBOL(default_blu); | 3989 | EXPORT_SYMBOL(default_blu); |
3986 | EXPORT_SYMBOL(update_region); | 3990 | EXPORT_SYMBOL(update_region); |
3987 | EXPORT_SYMBOL(redraw_screen); | 3991 | EXPORT_SYMBOL(redraw_screen); |
3988 | EXPORT_SYMBOL(vc_resize); | 3992 | EXPORT_SYMBOL(vc_resize); |
3989 | EXPORT_SYMBOL(vc_lock_resize); | 3993 | EXPORT_SYMBOL(vc_lock_resize); |
3990 | EXPORT_SYMBOL(fg_console); | 3994 | EXPORT_SYMBOL(fg_console); |
3991 | EXPORT_SYMBOL(console_blank_hook); | 3995 | EXPORT_SYMBOL(console_blank_hook); |
3992 | EXPORT_SYMBOL(console_blanked); | 3996 | EXPORT_SYMBOL(console_blanked); |
3993 | EXPORT_SYMBOL(vc_cons); | 3997 | EXPORT_SYMBOL(vc_cons); |
3994 | #ifndef VT_SINGLE_DRIVER | 3998 | #ifndef VT_SINGLE_DRIVER |
3995 | EXPORT_SYMBOL(take_over_console); | 3999 | EXPORT_SYMBOL(take_over_console); |
3996 | EXPORT_SYMBOL(give_up_console); | 4000 | EXPORT_SYMBOL(give_up_console); |
3997 | #endif | 4001 | #endif |
3998 | 4002 |
drivers/char/vt_ioctl.c
1 | /* | 1 | /* |
2 | * linux/drivers/char/vt_ioctl.c | 2 | * linux/drivers/char/vt_ioctl.c |
3 | * | 3 | * |
4 | * Copyright (C) 1992 obz under the linux copyright | 4 | * Copyright (C) 1992 obz under the linux copyright |
5 | * | 5 | * |
6 | * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 | 6 | * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 |
7 | * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 | 7 | * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 |
8 | * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 | 8 | * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 |
9 | * Some code moved for less code duplication - Andi Kleen - Mar 1997 | 9 | * Some code moved for less code duplication - Andi Kleen - Mar 1997 |
10 | * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 | 10 | * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/tty.h> | 16 | #include <linux/tty.h> |
17 | #include <linux/timer.h> | 17 | #include <linux/timer.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/kd.h> | 19 | #include <linux/kd.h> |
20 | #include <linux/vt.h> | 20 | #include <linux/vt.h> |
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/major.h> | 23 | #include <linux/major.h> |
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/console.h> | 25 | #include <linux/console.h> |
26 | #include <linux/consolemap.h> | 26 | #include <linux/consolemap.h> |
27 | #include <linux/signal.h> | 27 | #include <linux/signal.h> |
28 | #include <linux/timex.h> | 28 | #include <linux/timex.h> |
29 | 29 | ||
30 | #include <asm/io.h> | 30 | #include <asm/io.h> |
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | 32 | ||
33 | #include <linux/kbd_kern.h> | 33 | #include <linux/kbd_kern.h> |
34 | #include <linux/vt_kern.h> | 34 | #include <linux/vt_kern.h> |
35 | #include <linux/kbd_diacr.h> | 35 | #include <linux/kbd_diacr.h> |
36 | #include <linux/selection.h> | 36 | #include <linux/selection.h> |
37 | 37 | ||
38 | char vt_dont_switch; | 38 | char vt_dont_switch; |
39 | extern struct tty_driver *console_driver; | 39 | extern struct tty_driver *console_driver; |
40 | 40 | ||
41 | #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) | 41 | #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) |
42 | #define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons) | 42 | #define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons) |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Console (vt and kd) routines, as defined by USL SVR4 manual, and by | 45 | * Console (vt and kd) routines, as defined by USL SVR4 manual, and by |
46 | * experimentation and study of X386 SYSV handling. | 46 | * experimentation and study of X386 SYSV handling. |
47 | * | 47 | * |
48 | * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and | 48 | * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and |
49 | * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, | 49 | * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, |
50 | * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will | 50 | * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will |
51 | * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to | 51 | * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to |
52 | * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using | 52 | * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using |
53 | * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing | 53 | * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing |
54 | * to the current console is done by the main ioctl code. | 54 | * to the current console is done by the main ioctl code. |
55 | */ | 55 | */ |
56 | 56 | ||
57 | #ifdef CONFIG_X86 | 57 | #ifdef CONFIG_X86 |
58 | #include <linux/syscalls.h> | 58 | #include <linux/syscalls.h> |
59 | #endif | 59 | #endif |
60 | 60 | ||
61 | static void complete_change_console(struct vc_data *vc); | 61 | static void complete_change_console(struct vc_data *vc); |
62 | 62 | ||
63 | /* | 63 | /* |
64 | * these are the valid i/o ports we're allowed to change. they map all the | 64 | * these are the valid i/o ports we're allowed to change. they map all the |
65 | * video ports | 65 | * video ports |
66 | */ | 66 | */ |
67 | #define GPFIRST 0x3b4 | 67 | #define GPFIRST 0x3b4 |
68 | #define GPLAST 0x3df | 68 | #define GPLAST 0x3df |
69 | #define GPNUM (GPLAST - GPFIRST + 1) | 69 | #define GPNUM (GPLAST - GPFIRST + 1) |
70 | 70 | ||
71 | #define i (tmp.kb_index) | 71 | #define i (tmp.kb_index) |
72 | #define s (tmp.kb_table) | 72 | #define s (tmp.kb_table) |
73 | #define v (tmp.kb_value) | 73 | #define v (tmp.kb_value) |
74 | static inline int | 74 | static inline int |
75 | do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) | 75 | do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) |
76 | { | 76 | { |
77 | struct kbentry tmp; | 77 | struct kbentry tmp; |
78 | ushort *key_map, val, ov; | 78 | ushort *key_map, val, ov; |
79 | 79 | ||
80 | if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) | 80 | if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) |
81 | return -EFAULT; | 81 | return -EFAULT; |
82 | 82 | ||
83 | if (!capable(CAP_SYS_TTY_CONFIG)) | 83 | if (!capable(CAP_SYS_TTY_CONFIG)) |
84 | perm = 0; | 84 | perm = 0; |
85 | 85 | ||
86 | switch (cmd) { | 86 | switch (cmd) { |
87 | case KDGKBENT: | 87 | case KDGKBENT: |
88 | key_map = key_maps[s]; | 88 | key_map = key_maps[s]; |
89 | if (key_map) { | 89 | if (key_map) { |
90 | val = U(key_map[i]); | 90 | val = U(key_map[i]); |
91 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) | 91 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) |
92 | val = K_HOLE; | 92 | val = K_HOLE; |
93 | } else | 93 | } else |
94 | val = (i ? K_HOLE : K_NOSUCHMAP); | 94 | val = (i ? K_HOLE : K_NOSUCHMAP); |
95 | return put_user(val, &user_kbe->kb_value); | 95 | return put_user(val, &user_kbe->kb_value); |
96 | case KDSKBENT: | 96 | case KDSKBENT: |
97 | if (!perm) | 97 | if (!perm) |
98 | return -EPERM; | 98 | return -EPERM; |
99 | if (!i && v == K_NOSUCHMAP) { | 99 | if (!i && v == K_NOSUCHMAP) { |
100 | /* deallocate map */ | 100 | /* deallocate map */ |
101 | key_map = key_maps[s]; | 101 | key_map = key_maps[s]; |
102 | if (s && key_map) { | 102 | if (s && key_map) { |
103 | key_maps[s] = NULL; | 103 | key_maps[s] = NULL; |
104 | if (key_map[0] == U(K_ALLOCATED)) { | 104 | if (key_map[0] == U(K_ALLOCATED)) { |
105 | kfree(key_map); | 105 | kfree(key_map); |
106 | keymap_count--; | 106 | keymap_count--; |
107 | } | 107 | } |
108 | } | 108 | } |
109 | break; | 109 | break; |
110 | } | 110 | } |
111 | 111 | ||
112 | if (KTYP(v) < NR_TYPES) { | 112 | if (KTYP(v) < NR_TYPES) { |
113 | if (KVAL(v) > max_vals[KTYP(v)]) | 113 | if (KVAL(v) > max_vals[KTYP(v)]) |
114 | return -EINVAL; | 114 | return -EINVAL; |
115 | } else | 115 | } else |
116 | if (kbd->kbdmode != VC_UNICODE) | 116 | if (kbd->kbdmode != VC_UNICODE) |
117 | return -EINVAL; | 117 | return -EINVAL; |
118 | 118 | ||
119 | /* ++Geert: non-PC keyboards may generate keycode zero */ | 119 | /* ++Geert: non-PC keyboards may generate keycode zero */ |
120 | #if !defined(__mc68000__) && !defined(__powerpc__) | 120 | #if !defined(__mc68000__) && !defined(__powerpc__) |
121 | /* assignment to entry 0 only tests validity of args */ | 121 | /* assignment to entry 0 only tests validity of args */ |
122 | if (!i) | 122 | if (!i) |
123 | break; | 123 | break; |
124 | #endif | 124 | #endif |
125 | 125 | ||
126 | if (!(key_map = key_maps[s])) { | 126 | if (!(key_map = key_maps[s])) { |
127 | int j; | 127 | int j; |
128 | 128 | ||
129 | if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && | 129 | if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && |
130 | !capable(CAP_SYS_RESOURCE)) | 130 | !capable(CAP_SYS_RESOURCE)) |
131 | return -EPERM; | 131 | return -EPERM; |
132 | 132 | ||
133 | key_map = kmalloc(sizeof(plain_map), | 133 | key_map = kmalloc(sizeof(plain_map), |
134 | GFP_KERNEL); | 134 | GFP_KERNEL); |
135 | if (!key_map) | 135 | if (!key_map) |
136 | return -ENOMEM; | 136 | return -ENOMEM; |
137 | key_maps[s] = key_map; | 137 | key_maps[s] = key_map; |
138 | key_map[0] = U(K_ALLOCATED); | 138 | key_map[0] = U(K_ALLOCATED); |
139 | for (j = 1; j < NR_KEYS; j++) | 139 | for (j = 1; j < NR_KEYS; j++) |
140 | key_map[j] = U(K_HOLE); | 140 | key_map[j] = U(K_HOLE); |
141 | keymap_count++; | 141 | keymap_count++; |
142 | } | 142 | } |
143 | ov = U(key_map[i]); | 143 | ov = U(key_map[i]); |
144 | if (v == ov) | 144 | if (v == ov) |
145 | break; /* nothing to do */ | 145 | break; /* nothing to do */ |
146 | /* | 146 | /* |
147 | * Attention Key. | 147 | * Attention Key. |
148 | */ | 148 | */ |
149 | if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) | 149 | if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) |
150 | return -EPERM; | 150 | return -EPERM; |
151 | key_map[i] = U(v); | 151 | key_map[i] = U(v); |
152 | if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) | 152 | if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) |
153 | compute_shiftstate(); | 153 | compute_shiftstate(); |
154 | break; | 154 | break; |
155 | } | 155 | } |
156 | return 0; | 156 | return 0; |
157 | } | 157 | } |
158 | #undef i | 158 | #undef i |
159 | #undef s | 159 | #undef s |
160 | #undef v | 160 | #undef v |
161 | 161 | ||
162 | static inline int | 162 | static inline int |
163 | do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) | 163 | do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) |
164 | { | 164 | { |
165 | struct kbkeycode tmp; | 165 | struct kbkeycode tmp; |
166 | int kc = 0; | 166 | int kc = 0; |
167 | 167 | ||
168 | if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) | 168 | if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) |
169 | return -EFAULT; | 169 | return -EFAULT; |
170 | switch (cmd) { | 170 | switch (cmd) { |
171 | case KDGETKEYCODE: | 171 | case KDGETKEYCODE: |
172 | kc = getkeycode(tmp.scancode); | 172 | kc = getkeycode(tmp.scancode); |
173 | if (kc >= 0) | 173 | if (kc >= 0) |
174 | kc = put_user(kc, &user_kbkc->keycode); | 174 | kc = put_user(kc, &user_kbkc->keycode); |
175 | break; | 175 | break; |
176 | case KDSETKEYCODE: | 176 | case KDSETKEYCODE: |
177 | if (!perm) | 177 | if (!perm) |
178 | return -EPERM; | 178 | return -EPERM; |
179 | kc = setkeycode(tmp.scancode, tmp.keycode); | 179 | kc = setkeycode(tmp.scancode, tmp.keycode); |
180 | break; | 180 | break; |
181 | } | 181 | } |
182 | return kc; | 182 | return kc; |
183 | } | 183 | } |
184 | 184 | ||
185 | static inline int | 185 | static inline int |
186 | do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) | 186 | do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) |
187 | { | 187 | { |
188 | struct kbsentry *kbs; | 188 | struct kbsentry *kbs; |
189 | char *p; | 189 | char *p; |
190 | u_char *q; | 190 | u_char *q; |
191 | u_char __user *up; | 191 | u_char __user *up; |
192 | int sz; | 192 | int sz; |
193 | int delta; | 193 | int delta; |
194 | char *first_free, *fj, *fnw; | 194 | char *first_free, *fj, *fnw; |
195 | int i, j, k; | 195 | int i, j, k; |
196 | int ret; | 196 | int ret; |
197 | 197 | ||
198 | if (!capable(CAP_SYS_TTY_CONFIG)) | 198 | if (!capable(CAP_SYS_TTY_CONFIG)) |
199 | perm = 0; | 199 | perm = 0; |
200 | 200 | ||
201 | kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); | 201 | kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); |
202 | if (!kbs) { | 202 | if (!kbs) { |
203 | ret = -ENOMEM; | 203 | ret = -ENOMEM; |
204 | goto reterr; | 204 | goto reterr; |
205 | } | 205 | } |
206 | 206 | ||
207 | /* we mostly copy too much here (512bytes), but who cares ;) */ | 207 | /* we mostly copy too much here (512bytes), but who cares ;) */ |
208 | if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { | 208 | if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { |
209 | ret = -EFAULT; | 209 | ret = -EFAULT; |
210 | goto reterr; | 210 | goto reterr; |
211 | } | 211 | } |
212 | kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; | 212 | kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; |
213 | i = kbs->kb_func; | 213 | i = kbs->kb_func; |
214 | 214 | ||
215 | switch (cmd) { | 215 | switch (cmd) { |
216 | case KDGKBSENT: | 216 | case KDGKBSENT: |
217 | sz = sizeof(kbs->kb_string) - 1; /* sz should have been | 217 | sz = sizeof(kbs->kb_string) - 1; /* sz should have been |
218 | a struct member */ | 218 | a struct member */ |
219 | up = user_kdgkb->kb_string; | 219 | up = user_kdgkb->kb_string; |
220 | p = func_table[i]; | 220 | p = func_table[i]; |
221 | if(p) | 221 | if(p) |
222 | for ( ; *p && sz; p++, sz--) | 222 | for ( ; *p && sz; p++, sz--) |
223 | if (put_user(*p, up++)) { | 223 | if (put_user(*p, up++)) { |
224 | ret = -EFAULT; | 224 | ret = -EFAULT; |
225 | goto reterr; | 225 | goto reterr; |
226 | } | 226 | } |
227 | if (put_user('\0', up)) { | 227 | if (put_user('\0', up)) { |
228 | ret = -EFAULT; | 228 | ret = -EFAULT; |
229 | goto reterr; | 229 | goto reterr; |
230 | } | 230 | } |
231 | kfree(kbs); | 231 | kfree(kbs); |
232 | return ((p && *p) ? -EOVERFLOW : 0); | 232 | return ((p && *p) ? -EOVERFLOW : 0); |
233 | case KDSKBSENT: | 233 | case KDSKBSENT: |
234 | if (!perm) { | 234 | if (!perm) { |
235 | ret = -EPERM; | 235 | ret = -EPERM; |
236 | goto reterr; | 236 | goto reterr; |
237 | } | 237 | } |
238 | 238 | ||
239 | q = func_table[i]; | 239 | q = func_table[i]; |
240 | first_free = funcbufptr + (funcbufsize - funcbufleft); | 240 | first_free = funcbufptr + (funcbufsize - funcbufleft); |
241 | for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) | 241 | for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) |
242 | ; | 242 | ; |
243 | if (j < MAX_NR_FUNC) | 243 | if (j < MAX_NR_FUNC) |
244 | fj = func_table[j]; | 244 | fj = func_table[j]; |
245 | else | 245 | else |
246 | fj = first_free; | 246 | fj = first_free; |
247 | 247 | ||
248 | delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); | 248 | delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); |
249 | if (delta <= funcbufleft) { /* it fits in current buf */ | 249 | if (delta <= funcbufleft) { /* it fits in current buf */ |
250 | if (j < MAX_NR_FUNC) { | 250 | if (j < MAX_NR_FUNC) { |
251 | memmove(fj + delta, fj, first_free - fj); | 251 | memmove(fj + delta, fj, first_free - fj); |
252 | for (k = j; k < MAX_NR_FUNC; k++) | 252 | for (k = j; k < MAX_NR_FUNC; k++) |
253 | if (func_table[k]) | 253 | if (func_table[k]) |
254 | func_table[k] += delta; | 254 | func_table[k] += delta; |
255 | } | 255 | } |
256 | if (!q) | 256 | if (!q) |
257 | func_table[i] = fj; | 257 | func_table[i] = fj; |
258 | funcbufleft -= delta; | 258 | funcbufleft -= delta; |
259 | } else { /* allocate a larger buffer */ | 259 | } else { /* allocate a larger buffer */ |
260 | sz = 256; | 260 | sz = 256; |
261 | while (sz < funcbufsize - funcbufleft + delta) | 261 | while (sz < funcbufsize - funcbufleft + delta) |
262 | sz <<= 1; | 262 | sz <<= 1; |
263 | fnw = kmalloc(sz, GFP_KERNEL); | 263 | fnw = kmalloc(sz, GFP_KERNEL); |
264 | if(!fnw) { | 264 | if(!fnw) { |
265 | ret = -ENOMEM; | 265 | ret = -ENOMEM; |
266 | goto reterr; | 266 | goto reterr; |
267 | } | 267 | } |
268 | 268 | ||
269 | if (!q) | 269 | if (!q) |
270 | func_table[i] = fj; | 270 | func_table[i] = fj; |
271 | if (fj > funcbufptr) | 271 | if (fj > funcbufptr) |
272 | memmove(fnw, funcbufptr, fj - funcbufptr); | 272 | memmove(fnw, funcbufptr, fj - funcbufptr); |
273 | for (k = 0; k < j; k++) | 273 | for (k = 0; k < j; k++) |
274 | if (func_table[k]) | 274 | if (func_table[k]) |
275 | func_table[k] = fnw + (func_table[k] - funcbufptr); | 275 | func_table[k] = fnw + (func_table[k] - funcbufptr); |
276 | 276 | ||
277 | if (first_free > fj) { | 277 | if (first_free > fj) { |
278 | memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); | 278 | memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); |
279 | for (k = j; k < MAX_NR_FUNC; k++) | 279 | for (k = j; k < MAX_NR_FUNC; k++) |
280 | if (func_table[k]) | 280 | if (func_table[k]) |
281 | func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; | 281 | func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; |
282 | } | 282 | } |
283 | if (funcbufptr != func_buf) | 283 | if (funcbufptr != func_buf) |
284 | kfree(funcbufptr); | 284 | kfree(funcbufptr); |
285 | funcbufptr = fnw; | 285 | funcbufptr = fnw; |
286 | funcbufleft = funcbufleft - delta + sz - funcbufsize; | 286 | funcbufleft = funcbufleft - delta + sz - funcbufsize; |
287 | funcbufsize = sz; | 287 | funcbufsize = sz; |
288 | } | 288 | } |
289 | strcpy(func_table[i], kbs->kb_string); | 289 | strcpy(func_table[i], kbs->kb_string); |
290 | break; | 290 | break; |
291 | } | 291 | } |
292 | ret = 0; | 292 | ret = 0; |
293 | reterr: | 293 | reterr: |
294 | kfree(kbs); | 294 | kfree(kbs); |
295 | return ret; | 295 | return ret; |
296 | } | 296 | } |
297 | 297 | ||
298 | static inline int | 298 | static inline int |
299 | do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) | 299 | do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) |
300 | { | 300 | { |
301 | struct consolefontdesc cfdarg; | 301 | struct consolefontdesc cfdarg; |
302 | int i; | 302 | int i; |
303 | 303 | ||
304 | if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) | 304 | if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) |
305 | return -EFAULT; | 305 | return -EFAULT; |
306 | 306 | ||
307 | switch (cmd) { | 307 | switch (cmd) { |
308 | case PIO_FONTX: | 308 | case PIO_FONTX: |
309 | if (!perm) | 309 | if (!perm) |
310 | return -EPERM; | 310 | return -EPERM; |
311 | op->op = KD_FONT_OP_SET; | 311 | op->op = KD_FONT_OP_SET; |
312 | op->flags = KD_FONT_FLAG_OLD; | 312 | op->flags = KD_FONT_FLAG_OLD; |
313 | op->width = 8; | 313 | op->width = 8; |
314 | op->height = cfdarg.charheight; | 314 | op->height = cfdarg.charheight; |
315 | op->charcount = cfdarg.charcount; | 315 | op->charcount = cfdarg.charcount; |
316 | op->data = cfdarg.chardata; | 316 | op->data = cfdarg.chardata; |
317 | return con_font_op(vc_cons[fg_console].d, op); | 317 | return con_font_op(vc_cons[fg_console].d, op); |
318 | case GIO_FONTX: { | 318 | case GIO_FONTX: { |
319 | op->op = KD_FONT_OP_GET; | 319 | op->op = KD_FONT_OP_GET; |
320 | op->flags = KD_FONT_FLAG_OLD; | 320 | op->flags = KD_FONT_FLAG_OLD; |
321 | op->width = 8; | 321 | op->width = 8; |
322 | op->height = cfdarg.charheight; | 322 | op->height = cfdarg.charheight; |
323 | op->charcount = cfdarg.charcount; | 323 | op->charcount = cfdarg.charcount; |
324 | op->data = cfdarg.chardata; | 324 | op->data = cfdarg.chardata; |
325 | i = con_font_op(vc_cons[fg_console].d, op); | 325 | i = con_font_op(vc_cons[fg_console].d, op); |
326 | if (i) | 326 | if (i) |
327 | return i; | 327 | return i; |
328 | cfdarg.charheight = op->height; | 328 | cfdarg.charheight = op->height; |
329 | cfdarg.charcount = op->charcount; | 329 | cfdarg.charcount = op->charcount; |
330 | if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) | 330 | if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) |
331 | return -EFAULT; | 331 | return -EFAULT; |
332 | return 0; | 332 | return 0; |
333 | } | 333 | } |
334 | } | 334 | } |
335 | return -EINVAL; | 335 | return -EINVAL; |
336 | } | 336 | } |
337 | 337 | ||
338 | static inline int | 338 | static inline int |
339 | do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc) | 339 | do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc) |
340 | { | 340 | { |
341 | struct unimapdesc tmp; | 341 | struct unimapdesc tmp; |
342 | 342 | ||
343 | if (copy_from_user(&tmp, user_ud, sizeof tmp)) | 343 | if (copy_from_user(&tmp, user_ud, sizeof tmp)) |
344 | return -EFAULT; | 344 | return -EFAULT; |
345 | if (tmp.entries) | 345 | if (tmp.entries) |
346 | if (!access_ok(VERIFY_WRITE, tmp.entries, | 346 | if (!access_ok(VERIFY_WRITE, tmp.entries, |
347 | tmp.entry_ct*sizeof(struct unipair))) | 347 | tmp.entry_ct*sizeof(struct unipair))) |
348 | return -EFAULT; | 348 | return -EFAULT; |
349 | switch (cmd) { | 349 | switch (cmd) { |
350 | case PIO_UNIMAP: | 350 | case PIO_UNIMAP: |
351 | if (!perm) | 351 | if (!perm) |
352 | return -EPERM; | 352 | return -EPERM; |
353 | return con_set_unimap(vc, tmp.entry_ct, tmp.entries); | 353 | return con_set_unimap(vc, tmp.entry_ct, tmp.entries); |
354 | case GIO_UNIMAP: | 354 | case GIO_UNIMAP: |
355 | if (!perm && fg_console != vc->vc_num) | 355 | if (!perm && fg_console != vc->vc_num) |
356 | return -EPERM; | 356 | return -EPERM; |
357 | return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); | 357 | return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); |
358 | } | 358 | } |
359 | return 0; | 359 | return 0; |
360 | } | 360 | } |
361 | 361 | ||
362 | /* | 362 | /* |
363 | * We handle the console-specific ioctl's here. We allow the | 363 | * We handle the console-specific ioctl's here. We allow the |
364 | * capability to modify any console, not just the fg_console. | 364 | * capability to modify any console, not just the fg_console. |
365 | */ | 365 | */ |
366 | int vt_ioctl(struct tty_struct *tty, struct file * file, | 366 | int vt_ioctl(struct tty_struct *tty, struct file * file, |
367 | unsigned int cmd, unsigned long arg) | 367 | unsigned int cmd, unsigned long arg) |
368 | { | 368 | { |
369 | struct vc_data *vc = (struct vc_data *)tty->driver_data; | 369 | struct vc_data *vc = (struct vc_data *)tty->driver_data; |
370 | struct console_font_op op; /* used in multiple places here */ | 370 | struct console_font_op op; /* used in multiple places here */ |
371 | struct kbd_struct * kbd; | 371 | struct kbd_struct * kbd; |
372 | unsigned int console; | 372 | unsigned int console; |
373 | unsigned char ucval; | 373 | unsigned char ucval; |
374 | void __user *up = (void __user *)arg; | 374 | void __user *up = (void __user *)arg; |
375 | int i, perm; | 375 | int i, perm; |
376 | 376 | ||
377 | console = vc->vc_num; | 377 | console = vc->vc_num; |
378 | 378 | ||
379 | if (!vc_cons_allocated(console)) /* impossible? */ | 379 | if (!vc_cons_allocated(console)) /* impossible? */ |
380 | return -ENOIOCTLCMD; | 380 | return -ENOIOCTLCMD; |
381 | 381 | ||
382 | /* | 382 | /* |
383 | * To have permissions to do most of the vt ioctls, we either have | 383 | * To have permissions to do most of the vt ioctls, we either have |
384 | * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. | 384 | * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. |
385 | */ | 385 | */ |
386 | perm = 0; | 386 | perm = 0; |
387 | if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) | 387 | if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) |
388 | perm = 1; | 388 | perm = 1; |
389 | 389 | ||
390 | kbd = kbd_table + console; | 390 | kbd = kbd_table + console; |
391 | switch (cmd) { | 391 | switch (cmd) { |
392 | case KIOCSOUND: | 392 | case KIOCSOUND: |
393 | if (!perm) | 393 | if (!perm) |
394 | return -EPERM; | 394 | return -EPERM; |
395 | if (arg) | 395 | if (arg) |
396 | arg = CLOCK_TICK_RATE / arg; | 396 | arg = CLOCK_TICK_RATE / arg; |
397 | kd_mksound(arg, 0); | 397 | kd_mksound(arg, 0); |
398 | return 0; | 398 | return 0; |
399 | 399 | ||
400 | case KDMKTONE: | 400 | case KDMKTONE: |
401 | if (!perm) | 401 | if (!perm) |
402 | return -EPERM; | 402 | return -EPERM; |
403 | { | 403 | { |
404 | unsigned int ticks, count; | 404 | unsigned int ticks, count; |
405 | 405 | ||
406 | /* | 406 | /* |
407 | * Generate the tone for the appropriate number of ticks. | 407 | * Generate the tone for the appropriate number of ticks. |
408 | * If the time is zero, turn off sound ourselves. | 408 | * If the time is zero, turn off sound ourselves. |
409 | */ | 409 | */ |
410 | ticks = HZ * ((arg >> 16) & 0xffff) / 1000; | 410 | ticks = HZ * ((arg >> 16) & 0xffff) / 1000; |
411 | count = ticks ? (arg & 0xffff) : 0; | 411 | count = ticks ? (arg & 0xffff) : 0; |
412 | if (count) | 412 | if (count) |
413 | count = CLOCK_TICK_RATE / count; | 413 | count = CLOCK_TICK_RATE / count; |
414 | kd_mksound(count, ticks); | 414 | kd_mksound(count, ticks); |
415 | return 0; | 415 | return 0; |
416 | } | 416 | } |
417 | 417 | ||
418 | case KDGKBTYPE: | 418 | case KDGKBTYPE: |
419 | /* | 419 | /* |
420 | * this is naive. | 420 | * this is naive. |
421 | */ | 421 | */ |
422 | ucval = KB_101; | 422 | ucval = KB_101; |
423 | goto setchar; | 423 | goto setchar; |
424 | 424 | ||
425 | /* | 425 | /* |
426 | * These cannot be implemented on any machine that implements | 426 | * These cannot be implemented on any machine that implements |
427 | * ioperm() in user level (such as Alpha PCs) or not at all. | 427 | * ioperm() in user level (such as Alpha PCs) or not at all. |
428 | * | 428 | * |
429 | * XXX: you should never use these, just call ioperm directly.. | 429 | * XXX: you should never use these, just call ioperm directly.. |
430 | */ | 430 | */ |
431 | #ifdef CONFIG_X86 | 431 | #ifdef CONFIG_X86 |
432 | case KDADDIO: | 432 | case KDADDIO: |
433 | case KDDELIO: | 433 | case KDDELIO: |
434 | /* | 434 | /* |
435 | * KDADDIO and KDDELIO may be able to add ports beyond what | 435 | * KDADDIO and KDDELIO may be able to add ports beyond what |
436 | * we reject here, but to be safe... | 436 | * we reject here, but to be safe... |
437 | */ | 437 | */ |
438 | if (arg < GPFIRST || arg > GPLAST) | 438 | if (arg < GPFIRST || arg > GPLAST) |
439 | return -EINVAL; | 439 | return -EINVAL; |
440 | return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; | 440 | return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; |
441 | 441 | ||
442 | case KDENABIO: | 442 | case KDENABIO: |
443 | case KDDISABIO: | 443 | case KDDISABIO: |
444 | return sys_ioperm(GPFIRST, GPNUM, | 444 | return sys_ioperm(GPFIRST, GPNUM, |
445 | (cmd == KDENABIO)) ? -ENXIO : 0; | 445 | (cmd == KDENABIO)) ? -ENXIO : 0; |
446 | #endif | 446 | #endif |
447 | 447 | ||
448 | /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ | 448 | /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ |
449 | 449 | ||
450 | case KDKBDREP: | 450 | case KDKBDREP: |
451 | { | 451 | { |
452 | struct kbd_repeat kbrep; | 452 | struct kbd_repeat kbrep; |
453 | int err; | 453 | int err; |
454 | 454 | ||
455 | if (!capable(CAP_SYS_TTY_CONFIG)) | 455 | if (!capable(CAP_SYS_TTY_CONFIG)) |
456 | return -EPERM; | 456 | return -EPERM; |
457 | 457 | ||
458 | if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) | 458 | if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) |
459 | return -EFAULT; | 459 | return -EFAULT; |
460 | err = kbd_rate(&kbrep); | 460 | err = kbd_rate(&kbrep); |
461 | if (err) | 461 | if (err) |
462 | return err; | 462 | return err; |
463 | if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat))) | 463 | if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat))) |
464 | return -EFAULT; | 464 | return -EFAULT; |
465 | return 0; | 465 | return 0; |
466 | } | 466 | } |
467 | 467 | ||
468 | case KDSETMODE: | 468 | case KDSETMODE: |
469 | /* | 469 | /* |
470 | * currently, setting the mode from KD_TEXT to KD_GRAPHICS | 470 | * currently, setting the mode from KD_TEXT to KD_GRAPHICS |
471 | * doesn't do a whole lot. i'm not sure if it should do any | 471 | * doesn't do a whole lot. i'm not sure if it should do any |
472 | * restoration of modes or what... | 472 | * restoration of modes or what... |
473 | * | 473 | * |
474 | * XXX It should at least call into the driver, fbdev's definitely | 474 | * XXX It should at least call into the driver, fbdev's definitely |
475 | * need to restore their engine state. --BenH | 475 | * need to restore their engine state. --BenH |
476 | */ | 476 | */ |
477 | if (!perm) | 477 | if (!perm) |
478 | return -EPERM; | 478 | return -EPERM; |
479 | switch (arg) { | 479 | switch (arg) { |
480 | case KD_GRAPHICS: | 480 | case KD_GRAPHICS: |
481 | break; | 481 | break; |
482 | case KD_TEXT0: | 482 | case KD_TEXT0: |
483 | case KD_TEXT1: | 483 | case KD_TEXT1: |
484 | arg = KD_TEXT; | 484 | arg = KD_TEXT; |
485 | case KD_TEXT: | 485 | case KD_TEXT: |
486 | break; | 486 | break; |
487 | default: | 487 | default: |
488 | return -EINVAL; | 488 | return -EINVAL; |
489 | } | 489 | } |
490 | if (vc->vc_mode == (unsigned char) arg) | 490 | if (vc->vc_mode == (unsigned char) arg) |
491 | return 0; | 491 | return 0; |
492 | vc->vc_mode = (unsigned char) arg; | 492 | vc->vc_mode = (unsigned char) arg; |
493 | if (console != fg_console) | 493 | if (console != fg_console) |
494 | return 0; | 494 | return 0; |
495 | /* | 495 | /* |
496 | * explicitly blank/unblank the screen if switching modes | 496 | * explicitly blank/unblank the screen if switching modes |
497 | */ | 497 | */ |
498 | acquire_console_sem(); | 498 | acquire_console_sem(); |
499 | if (arg == KD_TEXT) | 499 | if (arg == KD_TEXT) |
500 | do_unblank_screen(1); | 500 | do_unblank_screen(1); |
501 | else | 501 | else |
502 | do_blank_screen(1); | 502 | do_blank_screen(1); |
503 | release_console_sem(); | 503 | release_console_sem(); |
504 | return 0; | 504 | return 0; |
505 | 505 | ||
506 | case KDGETMODE: | 506 | case KDGETMODE: |
507 | ucval = vc->vc_mode; | 507 | ucval = vc->vc_mode; |
508 | goto setint; | 508 | goto setint; |
509 | 509 | ||
510 | case KDMAPDISP: | 510 | case KDMAPDISP: |
511 | case KDUNMAPDISP: | 511 | case KDUNMAPDISP: |
512 | /* | 512 | /* |
513 | * these work like a combination of mmap and KDENABIO. | 513 | * these work like a combination of mmap and KDENABIO. |
514 | * this could be easily finished. | 514 | * this could be easily finished. |
515 | */ | 515 | */ |
516 | return -EINVAL; | 516 | return -EINVAL; |
517 | 517 | ||
518 | case KDSKBMODE: | 518 | case KDSKBMODE: |
519 | if (!perm) | 519 | if (!perm) |
520 | return -EPERM; | 520 | return -EPERM; |
521 | switch(arg) { | 521 | switch(arg) { |
522 | case K_RAW: | 522 | case K_RAW: |
523 | kbd->kbdmode = VC_RAW; | 523 | kbd->kbdmode = VC_RAW; |
524 | break; | 524 | break; |
525 | case K_MEDIUMRAW: | 525 | case K_MEDIUMRAW: |
526 | kbd->kbdmode = VC_MEDIUMRAW; | 526 | kbd->kbdmode = VC_MEDIUMRAW; |
527 | break; | 527 | break; |
528 | case K_XLATE: | 528 | case K_XLATE: |
529 | kbd->kbdmode = VC_XLATE; | 529 | kbd->kbdmode = VC_XLATE; |
530 | compute_shiftstate(); | 530 | compute_shiftstate(); |
531 | break; | 531 | break; |
532 | case K_UNICODE: | 532 | case K_UNICODE: |
533 | kbd->kbdmode = VC_UNICODE; | 533 | kbd->kbdmode = VC_UNICODE; |
534 | compute_shiftstate(); | 534 | compute_shiftstate(); |
535 | break; | 535 | break; |
536 | default: | 536 | default: |
537 | return -EINVAL; | 537 | return -EINVAL; |
538 | } | 538 | } |
539 | tty_ldisc_flush(tty); | 539 | tty_ldisc_flush(tty); |
540 | return 0; | 540 | return 0; |
541 | 541 | ||
542 | case KDGKBMODE: | 542 | case KDGKBMODE: |
543 | ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : | 543 | ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : |
544 | (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : | 544 | (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : |
545 | (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : | 545 | (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : |
546 | K_XLATE); | 546 | K_XLATE); |
547 | goto setint; | 547 | goto setint; |
548 | 548 | ||
549 | /* this could be folded into KDSKBMODE, but for compatibility | 549 | /* this could be folded into KDSKBMODE, but for compatibility |
550 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ | 550 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ |
551 | case KDSKBMETA: | 551 | case KDSKBMETA: |
552 | switch(arg) { | 552 | switch(arg) { |
553 | case K_METABIT: | 553 | case K_METABIT: |
554 | clr_vc_kbd_mode(kbd, VC_META); | 554 | clr_vc_kbd_mode(kbd, VC_META); |
555 | break; | 555 | break; |
556 | case K_ESCPREFIX: | 556 | case K_ESCPREFIX: |
557 | set_vc_kbd_mode(kbd, VC_META); | 557 | set_vc_kbd_mode(kbd, VC_META); |
558 | break; | 558 | break; |
559 | default: | 559 | default: |
560 | return -EINVAL; | 560 | return -EINVAL; |
561 | } | 561 | } |
562 | return 0; | 562 | return 0; |
563 | 563 | ||
564 | case KDGKBMETA: | 564 | case KDGKBMETA: |
565 | ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); | 565 | ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); |
566 | setint: | 566 | setint: |
567 | return put_user(ucval, (int __user *)arg); | 567 | return put_user(ucval, (int __user *)arg); |
568 | 568 | ||
569 | case KDGETKEYCODE: | 569 | case KDGETKEYCODE: |
570 | case KDSETKEYCODE: | 570 | case KDSETKEYCODE: |
571 | if(!capable(CAP_SYS_TTY_CONFIG)) | 571 | if(!capable(CAP_SYS_TTY_CONFIG)) |
572 | perm=0; | 572 | perm=0; |
573 | return do_kbkeycode_ioctl(cmd, up, perm); | 573 | return do_kbkeycode_ioctl(cmd, up, perm); |
574 | 574 | ||
575 | case KDGKBENT: | 575 | case KDGKBENT: |
576 | case KDSKBENT: | 576 | case KDSKBENT: |
577 | return do_kdsk_ioctl(cmd, up, perm, kbd); | 577 | return do_kdsk_ioctl(cmd, up, perm, kbd); |
578 | 578 | ||
579 | case KDGKBSENT: | 579 | case KDGKBSENT: |
580 | case KDSKBSENT: | 580 | case KDSKBSENT: |
581 | return do_kdgkb_ioctl(cmd, up, perm); | 581 | return do_kdgkb_ioctl(cmd, up, perm); |
582 | 582 | ||
583 | case KDGKBDIACR: | 583 | case KDGKBDIACR: |
584 | { | 584 | { |
585 | struct kbdiacrs __user *a = up; | 585 | struct kbdiacrs __user *a = up; |
586 | struct kbdiacr diacr; | 586 | struct kbdiacr diacr; |
587 | int i; | 587 | int i; |
588 | 588 | ||
589 | if (put_user(accent_table_size, &a->kb_cnt)) | 589 | if (put_user(accent_table_size, &a->kb_cnt)) |
590 | return -EFAULT; | 590 | return -EFAULT; |
591 | for (i = 0; i < accent_table_size; i++) { | 591 | for (i = 0; i < accent_table_size; i++) { |
592 | diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); | 592 | diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); |
593 | diacr.base = conv_uni_to_8bit(accent_table[i].base); | 593 | diacr.base = conv_uni_to_8bit(accent_table[i].base); |
594 | diacr.result = conv_uni_to_8bit(accent_table[i].result); | 594 | diacr.result = conv_uni_to_8bit(accent_table[i].result); |
595 | if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) | 595 | if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) |
596 | return -EFAULT; | 596 | return -EFAULT; |
597 | } | 597 | } |
598 | return 0; | 598 | return 0; |
599 | } | 599 | } |
600 | case KDGKBDIACRUC: | 600 | case KDGKBDIACRUC: |
601 | { | 601 | { |
602 | struct kbdiacrsuc __user *a = up; | 602 | struct kbdiacrsuc __user *a = up; |
603 | 603 | ||
604 | if (put_user(accent_table_size, &a->kb_cnt)) | 604 | if (put_user(accent_table_size, &a->kb_cnt)) |
605 | return -EFAULT; | 605 | return -EFAULT; |
606 | if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc))) | 606 | if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc))) |
607 | return -EFAULT; | 607 | return -EFAULT; |
608 | return 0; | 608 | return 0; |
609 | } | 609 | } |
610 | 610 | ||
611 | case KDSKBDIACR: | 611 | case KDSKBDIACR: |
612 | { | 612 | { |
613 | struct kbdiacrs __user *a = up; | 613 | struct kbdiacrs __user *a = up; |
614 | struct kbdiacr diacr; | 614 | struct kbdiacr diacr; |
615 | unsigned int ct; | 615 | unsigned int ct; |
616 | int i; | 616 | int i; |
617 | 617 | ||
618 | if (!perm) | 618 | if (!perm) |
619 | return -EPERM; | 619 | return -EPERM; |
620 | if (get_user(ct,&a->kb_cnt)) | 620 | if (get_user(ct,&a->kb_cnt)) |
621 | return -EFAULT; | 621 | return -EFAULT; |
622 | if (ct >= MAX_DIACR) | 622 | if (ct >= MAX_DIACR) |
623 | return -EINVAL; | 623 | return -EINVAL; |
624 | accent_table_size = ct; | 624 | accent_table_size = ct; |
625 | for (i = 0; i < ct; i++) { | 625 | for (i = 0; i < ct; i++) { |
626 | if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) | 626 | if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) |
627 | return -EFAULT; | 627 | return -EFAULT; |
628 | accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); | 628 | accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); |
629 | accent_table[i].base = conv_8bit_to_uni(diacr.base); | 629 | accent_table[i].base = conv_8bit_to_uni(diacr.base); |
630 | accent_table[i].result = conv_8bit_to_uni(diacr.result); | 630 | accent_table[i].result = conv_8bit_to_uni(diacr.result); |
631 | } | 631 | } |
632 | return 0; | 632 | return 0; |
633 | } | 633 | } |
634 | 634 | ||
635 | case KDSKBDIACRUC: | 635 | case KDSKBDIACRUC: |
636 | { | 636 | { |
637 | struct kbdiacrsuc __user *a = up; | 637 | struct kbdiacrsuc __user *a = up; |
638 | unsigned int ct; | 638 | unsigned int ct; |
639 | 639 | ||
640 | if (!perm) | 640 | if (!perm) |
641 | return -EPERM; | 641 | return -EPERM; |
642 | if (get_user(ct,&a->kb_cnt)) | 642 | if (get_user(ct,&a->kb_cnt)) |
643 | return -EFAULT; | 643 | return -EFAULT; |
644 | if (ct >= MAX_DIACR) | 644 | if (ct >= MAX_DIACR) |
645 | return -EINVAL; | 645 | return -EINVAL; |
646 | accent_table_size = ct; | 646 | accent_table_size = ct; |
647 | if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) | 647 | if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) |
648 | return -EFAULT; | 648 | return -EFAULT; |
649 | return 0; | 649 | return 0; |
650 | } | 650 | } |
651 | 651 | ||
652 | /* the ioctls below read/set the flags usually shown in the leds */ | 652 | /* the ioctls below read/set the flags usually shown in the leds */ |
653 | /* don't use them - they will go away without warning */ | 653 | /* don't use them - they will go away without warning */ |
654 | case KDGKBLED: | 654 | case KDGKBLED: |
655 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); | 655 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); |
656 | goto setchar; | 656 | goto setchar; |
657 | 657 | ||
658 | case KDSKBLED: | 658 | case KDSKBLED: |
659 | if (!perm) | 659 | if (!perm) |
660 | return -EPERM; | 660 | return -EPERM; |
661 | if (arg & ~0x77) | 661 | if (arg & ~0x77) |
662 | return -EINVAL; | 662 | return -EINVAL; |
663 | kbd->ledflagstate = (arg & 7); | 663 | kbd->ledflagstate = (arg & 7); |
664 | kbd->default_ledflagstate = ((arg >> 4) & 7); | 664 | kbd->default_ledflagstate = ((arg >> 4) & 7); |
665 | set_leds(); | 665 | set_leds(); |
666 | return 0; | 666 | return 0; |
667 | 667 | ||
668 | /* the ioctls below only set the lights, not the functions */ | 668 | /* the ioctls below only set the lights, not the functions */ |
669 | /* for those, see KDGKBLED and KDSKBLED above */ | 669 | /* for those, see KDGKBLED and KDSKBLED above */ |
670 | case KDGETLED: | 670 | case KDGETLED: |
671 | ucval = getledstate(); | 671 | ucval = getledstate(); |
672 | setchar: | 672 | setchar: |
673 | return put_user(ucval, (char __user *)arg); | 673 | return put_user(ucval, (char __user *)arg); |
674 | 674 | ||
675 | case KDSETLED: | 675 | case KDSETLED: |
676 | if (!perm) | 676 | if (!perm) |
677 | return -EPERM; | 677 | return -EPERM; |
678 | setledstate(kbd, arg); | 678 | setledstate(kbd, arg); |
679 | return 0; | 679 | return 0; |
680 | 680 | ||
681 | /* | 681 | /* |
682 | * A process can indicate its willingness to accept signals | 682 | * A process can indicate its willingness to accept signals |
683 | * generated by pressing an appropriate key combination. | 683 | * generated by pressing an appropriate key combination. |
684 | * Thus, one can have a daemon that e.g. spawns a new console | 684 | * Thus, one can have a daemon that e.g. spawns a new console |
685 | * upon a keypress and then changes to it. | 685 | * upon a keypress and then changes to it. |
686 | * See also the kbrequest field of inittab(5). | 686 | * See also the kbrequest field of inittab(5). |
687 | */ | 687 | */ |
688 | case KDSIGACCEPT: | 688 | case KDSIGACCEPT: |
689 | { | 689 | { |
690 | if (!perm || !capable(CAP_KILL)) | 690 | if (!perm || !capable(CAP_KILL)) |
691 | return -EPERM; | 691 | return -EPERM; |
692 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) | 692 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) |
693 | return -EINVAL; | 693 | return -EINVAL; |
694 | 694 | ||
695 | spin_lock_irq(&vt_spawn_con.lock); | 695 | spin_lock_irq(&vt_spawn_con.lock); |
696 | put_pid(vt_spawn_con.pid); | 696 | put_pid(vt_spawn_con.pid); |
697 | vt_spawn_con.pid = get_pid(task_pid(current)); | 697 | vt_spawn_con.pid = get_pid(task_pid(current)); |
698 | vt_spawn_con.sig = arg; | 698 | vt_spawn_con.sig = arg; |
699 | spin_unlock_irq(&vt_spawn_con.lock); | 699 | spin_unlock_irq(&vt_spawn_con.lock); |
700 | return 0; | 700 | return 0; |
701 | } | 701 | } |
702 | 702 | ||
703 | case VT_SETMODE: | 703 | case VT_SETMODE: |
704 | { | 704 | { |
705 | struct vt_mode tmp; | 705 | struct vt_mode tmp; |
706 | 706 | ||
707 | if (!perm) | 707 | if (!perm) |
708 | return -EPERM; | 708 | return -EPERM; |
709 | if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) | 709 | if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) |
710 | return -EFAULT; | 710 | return -EFAULT; |
711 | if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) | 711 | if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) |
712 | return -EINVAL; | 712 | return -EINVAL; |
713 | acquire_console_sem(); | 713 | acquire_console_sem(); |
714 | vc->vt_mode = tmp; | 714 | vc->vt_mode = tmp; |
715 | /* the frsig is ignored, so we set it to 0 */ | 715 | /* the frsig is ignored, so we set it to 0 */ |
716 | vc->vt_mode.frsig = 0; | 716 | vc->vt_mode.frsig = 0; |
717 | put_pid(vc->vt_pid); | 717 | put_pid(vc->vt_pid); |
718 | vc->vt_pid = get_pid(task_pid(current)); | 718 | vc->vt_pid = get_pid(task_pid(current)); |
719 | /* no switch is required -- saw@shade.msu.ru */ | 719 | /* no switch is required -- saw@shade.msu.ru */ |
720 | vc->vt_newvt = -1; | 720 | vc->vt_newvt = -1; |
721 | release_console_sem(); | 721 | release_console_sem(); |
722 | return 0; | 722 | return 0; |
723 | } | 723 | } |
724 | 724 | ||
725 | case VT_GETMODE: | 725 | case VT_GETMODE: |
726 | { | 726 | { |
727 | struct vt_mode tmp; | 727 | struct vt_mode tmp; |
728 | int rc; | 728 | int rc; |
729 | 729 | ||
730 | acquire_console_sem(); | 730 | acquire_console_sem(); |
731 | memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); | 731 | memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); |
732 | release_console_sem(); | 732 | release_console_sem(); |
733 | 733 | ||
734 | rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); | 734 | rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); |
735 | return rc ? -EFAULT : 0; | 735 | return rc ? -EFAULT : 0; |
736 | } | 736 | } |
737 | 737 | ||
738 | /* | 738 | /* |
739 | * Returns global vt state. Note that VT 0 is always open, since | 739 | * Returns global vt state. Note that VT 0 is always open, since |
740 | * it's an alias for the current VT, and people can't use it here. | 740 | * it's an alias for the current VT, and people can't use it here. |
741 | * We cannot return state for more than 16 VTs, since v_state is short. | 741 | * We cannot return state for more than 16 VTs, since v_state is short. |
742 | */ | 742 | */ |
743 | case VT_GETSTATE: | 743 | case VT_GETSTATE: |
744 | { | 744 | { |
745 | struct vt_stat __user *vtstat = up; | 745 | struct vt_stat __user *vtstat = up; |
746 | unsigned short state, mask; | 746 | unsigned short state, mask; |
747 | 747 | ||
748 | if (put_user(fg_console + 1, &vtstat->v_active)) | 748 | if (put_user(fg_console + 1, &vtstat->v_active)) |
749 | return -EFAULT; | 749 | return -EFAULT; |
750 | state = 1; /* /dev/tty0 is always open */ | 750 | state = 1; /* /dev/tty0 is always open */ |
751 | for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) | 751 | for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) |
752 | if (VT_IS_IN_USE(i)) | 752 | if (VT_IS_IN_USE(i)) |
753 | state |= mask; | 753 | state |= mask; |
754 | return put_user(state, &vtstat->v_state); | 754 | return put_user(state, &vtstat->v_state); |
755 | } | 755 | } |
756 | 756 | ||
757 | /* | 757 | /* |
758 | * Returns the first available (non-opened) console. | 758 | * Returns the first available (non-opened) console. |
759 | */ | 759 | */ |
760 | case VT_OPENQRY: | 760 | case VT_OPENQRY: |
761 | for (i = 0; i < MAX_NR_CONSOLES; ++i) | 761 | for (i = 0; i < MAX_NR_CONSOLES; ++i) |
762 | if (! VT_IS_IN_USE(i)) | 762 | if (! VT_IS_IN_USE(i)) |
763 | break; | 763 | break; |
764 | ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; | 764 | ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; |
765 | goto setint; | 765 | goto setint; |
766 | 766 | ||
767 | /* | 767 | /* |
768 | * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, | 768 | * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, |
769 | * with num >= 1 (switches to vt 0, our console, are not allowed, just | 769 | * with num >= 1 (switches to vt 0, our console, are not allowed, just |
770 | * to preserve sanity). | 770 | * to preserve sanity). |
771 | */ | 771 | */ |
772 | case VT_ACTIVATE: | 772 | case VT_ACTIVATE: |
773 | if (!perm) | 773 | if (!perm) |
774 | return -EPERM; | 774 | return -EPERM; |
775 | if (arg == 0 || arg > MAX_NR_CONSOLES) | 775 | if (arg == 0 || arg > MAX_NR_CONSOLES) |
776 | return -ENXIO; | 776 | return -ENXIO; |
777 | arg--; | 777 | arg--; |
778 | acquire_console_sem(); | 778 | acquire_console_sem(); |
779 | i = vc_allocate(arg); | 779 | i = vc_allocate(arg); |
780 | release_console_sem(); | 780 | release_console_sem(); |
781 | if (i) | 781 | if (i) |
782 | return i; | 782 | return i; |
783 | set_console(arg); | 783 | set_console(arg); |
784 | return 0; | 784 | return 0; |
785 | 785 | ||
786 | /* | 786 | /* |
787 | * wait until the specified VT has been activated | 787 | * wait until the specified VT has been activated |
788 | */ | 788 | */ |
789 | case VT_WAITACTIVE: | 789 | case VT_WAITACTIVE: |
790 | if (!perm) | 790 | if (!perm) |
791 | return -EPERM; | 791 | return -EPERM; |
792 | if (arg == 0 || arg > MAX_NR_CONSOLES) | 792 | if (arg == 0 || arg > MAX_NR_CONSOLES) |
793 | return -ENXIO; | 793 | return -ENXIO; |
794 | return vt_waitactive(arg-1); | 794 | return vt_waitactive(arg-1); |
795 | 795 | ||
796 | /* | 796 | /* |
797 | * If a vt is under process control, the kernel will not switch to it | 797 | * If a vt is under process control, the kernel will not switch to it |
798 | * immediately, but postpone the operation until the process calls this | 798 | * immediately, but postpone the operation until the process calls this |
799 | * ioctl, allowing the switch to complete. | 799 | * ioctl, allowing the switch to complete. |
800 | * | 800 | * |
801 | * According to the X sources this is the behavior: | 801 | * According to the X sources this is the behavior: |
802 | * 0: pending switch-from not OK | 802 | * 0: pending switch-from not OK |
803 | * 1: pending switch-from OK | 803 | * 1: pending switch-from OK |
804 | * 2: completed switch-to OK | 804 | * 2: completed switch-to OK |
805 | */ | 805 | */ |
806 | case VT_RELDISP: | 806 | case VT_RELDISP: |
807 | if (!perm) | 807 | if (!perm) |
808 | return -EPERM; | 808 | return -EPERM; |
809 | if (vc->vt_mode.mode != VT_PROCESS) | 809 | if (vc->vt_mode.mode != VT_PROCESS) |
810 | return -EINVAL; | 810 | return -EINVAL; |
811 | 811 | ||
812 | /* | 812 | /* |
813 | * Switching-from response | 813 | * Switching-from response |
814 | */ | 814 | */ |
815 | acquire_console_sem(); | 815 | acquire_console_sem(); |
816 | if (vc->vt_newvt >= 0) { | 816 | if (vc->vt_newvt >= 0) { |
817 | if (arg == 0) | 817 | if (arg == 0) |
818 | /* | 818 | /* |
819 | * Switch disallowed, so forget we were trying | 819 | * Switch disallowed, so forget we were trying |
820 | * to do it. | 820 | * to do it. |
821 | */ | 821 | */ |
822 | vc->vt_newvt = -1; | 822 | vc->vt_newvt = -1; |
823 | 823 | ||
824 | else { | 824 | else { |
825 | /* | 825 | /* |
826 | * The current vt has been released, so | 826 | * The current vt has been released, so |
827 | * complete the switch. | 827 | * complete the switch. |
828 | */ | 828 | */ |
829 | int newvt; | 829 | int newvt; |
830 | newvt = vc->vt_newvt; | 830 | newvt = vc->vt_newvt; |
831 | vc->vt_newvt = -1; | 831 | vc->vt_newvt = -1; |
832 | i = vc_allocate(newvt); | 832 | i = vc_allocate(newvt); |
833 | if (i) { | 833 | if (i) { |
834 | release_console_sem(); | 834 | release_console_sem(); |
835 | return i; | 835 | return i; |
836 | } | 836 | } |
837 | /* | 837 | /* |
838 | * When we actually do the console switch, | 838 | * When we actually do the console switch, |
839 | * make sure we are atomic with respect to | 839 | * make sure we are atomic with respect to |
840 | * other console switches.. | 840 | * other console switches.. |
841 | */ | 841 | */ |
842 | complete_change_console(vc_cons[newvt].d); | 842 | complete_change_console(vc_cons[newvt].d); |
843 | } | 843 | } |
844 | } | 844 | } |
845 | 845 | ||
846 | /* | 846 | /* |
847 | * Switched-to response | 847 | * Switched-to response |
848 | */ | 848 | */ |
849 | else | 849 | else |
850 | { | 850 | { |
851 | /* | 851 | /* |
852 | * If it's just an ACK, ignore it | 852 | * If it's just an ACK, ignore it |
853 | */ | 853 | */ |
854 | if (arg != VT_ACKACQ) { | 854 | if (arg != VT_ACKACQ) { |
855 | release_console_sem(); | 855 | release_console_sem(); |
856 | return -EINVAL; | 856 | return -EINVAL; |
857 | } | 857 | } |
858 | } | 858 | } |
859 | release_console_sem(); | 859 | release_console_sem(); |
860 | 860 | ||
861 | return 0; | 861 | return 0; |
862 | 862 | ||
863 | /* | 863 | /* |
864 | * Disallocate memory associated to VT (but leave VT1) | 864 | * Disallocate memory associated to VT (but leave VT1) |
865 | */ | 865 | */ |
866 | case VT_DISALLOCATE: | 866 | case VT_DISALLOCATE: |
867 | if (arg > MAX_NR_CONSOLES) | 867 | if (arg > MAX_NR_CONSOLES) |
868 | return -ENXIO; | 868 | return -ENXIO; |
869 | if (arg == 0) { | 869 | if (arg == 0) { |
870 | /* deallocate all unused consoles, but leave 0 */ | 870 | /* deallocate all unused consoles, but leave 0 */ |
871 | acquire_console_sem(); | 871 | acquire_console_sem(); |
872 | for (i=1; i<MAX_NR_CONSOLES; i++) | 872 | for (i=1; i<MAX_NR_CONSOLES; i++) |
873 | if (! VT_BUSY(i)) | 873 | if (! VT_BUSY(i)) |
874 | vc_deallocate(i); | 874 | vc_deallocate(i); |
875 | release_console_sem(); | 875 | release_console_sem(); |
876 | } else { | 876 | } else { |
877 | /* deallocate a single console, if possible */ | 877 | /* deallocate a single console, if possible */ |
878 | arg--; | 878 | arg--; |
879 | if (VT_BUSY(arg)) | 879 | if (VT_BUSY(arg)) |
880 | return -EBUSY; | 880 | return -EBUSY; |
881 | if (arg) { /* leave 0 */ | 881 | if (arg) { /* leave 0 */ |
882 | acquire_console_sem(); | 882 | acquire_console_sem(); |
883 | vc_deallocate(arg); | 883 | vc_deallocate(arg); |
884 | release_console_sem(); | 884 | release_console_sem(); |
885 | } | 885 | } |
886 | } | 886 | } |
887 | return 0; | 887 | return 0; |
888 | 888 | ||
889 | case VT_RESIZE: | 889 | case VT_RESIZE: |
890 | { | 890 | { |
891 | struct vt_sizes __user *vtsizes = up; | 891 | struct vt_sizes __user *vtsizes = up; |
892 | struct vc_data *vc; | 892 | struct vc_data *vc; |
893 | 893 | ||
894 | ushort ll,cc; | 894 | ushort ll,cc; |
895 | if (!perm) | 895 | if (!perm) |
896 | return -EPERM; | 896 | return -EPERM; |
897 | if (get_user(ll, &vtsizes->v_rows) || | 897 | if (get_user(ll, &vtsizes->v_rows) || |
898 | get_user(cc, &vtsizes->v_cols)) | 898 | get_user(cc, &vtsizes->v_cols)) |
899 | return -EFAULT; | 899 | return -EFAULT; |
900 | 900 | ||
901 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 901 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
902 | vc = vc_cons[i].d; | 902 | vc = vc_cons[i].d; |
903 | 903 | ||
904 | if (vc) { | 904 | if (vc) { |
905 | vc->vc_resize_user = 1; | 905 | vc->vc_resize_user = 1; |
906 | vc_lock_resize(vc_cons[i].d, cc, ll); | 906 | vc_lock_resize(vc_cons[i].d, cc, ll); |
907 | } | 907 | } |
908 | } | 908 | } |
909 | 909 | ||
910 | return 0; | 910 | return 0; |
911 | } | 911 | } |
912 | 912 | ||
913 | case VT_RESIZEX: | 913 | case VT_RESIZEX: |
914 | { | 914 | { |
915 | struct vt_consize __user *vtconsize = up; | 915 | struct vt_consize __user *vtconsize = up; |
916 | ushort ll,cc,vlin,clin,vcol,ccol; | 916 | ushort ll,cc,vlin,clin,vcol,ccol; |
917 | if (!perm) | 917 | if (!perm) |
918 | return -EPERM; | 918 | return -EPERM; |
919 | if (!access_ok(VERIFY_READ, vtconsize, | 919 | if (!access_ok(VERIFY_READ, vtconsize, |
920 | sizeof(struct vt_consize))) | 920 | sizeof(struct vt_consize))) |
921 | return -EFAULT; | 921 | return -EFAULT; |
922 | __get_user(ll, &vtconsize->v_rows); | 922 | __get_user(ll, &vtconsize->v_rows); |
923 | __get_user(cc, &vtconsize->v_cols); | 923 | __get_user(cc, &vtconsize->v_cols); |
924 | __get_user(vlin, &vtconsize->v_vlin); | 924 | __get_user(vlin, &vtconsize->v_vlin); |
925 | __get_user(clin, &vtconsize->v_clin); | 925 | __get_user(clin, &vtconsize->v_clin); |
926 | __get_user(vcol, &vtconsize->v_vcol); | 926 | __get_user(vcol, &vtconsize->v_vcol); |
927 | __get_user(ccol, &vtconsize->v_ccol); | 927 | __get_user(ccol, &vtconsize->v_ccol); |
928 | vlin = vlin ? vlin : vc->vc_scan_lines; | 928 | vlin = vlin ? vlin : vc->vc_scan_lines; |
929 | if (clin) { | 929 | if (clin) { |
930 | if (ll) { | 930 | if (ll) { |
931 | if (ll != vlin/clin) | 931 | if (ll != vlin/clin) |
932 | return -EINVAL; /* Parameters don't add up */ | 932 | return -EINVAL; /* Parameters don't add up */ |
933 | } else | 933 | } else |
934 | ll = vlin/clin; | 934 | ll = vlin/clin; |
935 | } | 935 | } |
936 | if (vcol && ccol) { | 936 | if (vcol && ccol) { |
937 | if (cc) { | 937 | if (cc) { |
938 | if (cc != vcol/ccol) | 938 | if (cc != vcol/ccol) |
939 | return -EINVAL; | 939 | return -EINVAL; |
940 | } else | 940 | } else |
941 | cc = vcol/ccol; | 941 | cc = vcol/ccol; |
942 | } | 942 | } |
943 | 943 | ||
944 | if (clin > 32) | 944 | if (clin > 32) |
945 | return -EINVAL; | 945 | return -EINVAL; |
946 | 946 | ||
947 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 947 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
948 | if (!vc_cons[i].d) | 948 | if (!vc_cons[i].d) |
949 | continue; | 949 | continue; |
950 | acquire_console_sem(); | 950 | acquire_console_sem(); |
951 | if (vlin) | 951 | if (vlin) |
952 | vc_cons[i].d->vc_scan_lines = vlin; | 952 | vc_cons[i].d->vc_scan_lines = vlin; |
953 | if (clin) | 953 | if (clin) |
954 | vc_cons[i].d->vc_font.height = clin; | 954 | vc_cons[i].d->vc_font.height = clin; |
955 | vc_cons[i].d->vc_resize_user = 1; | 955 | vc_cons[i].d->vc_resize_user = 1; |
956 | vc_resize(vc_cons[i].d, cc, ll); | 956 | vc_resize(vc_cons[i].d, cc, ll); |
957 | release_console_sem(); | 957 | release_console_sem(); |
958 | } | 958 | } |
959 | return 0; | 959 | return 0; |
960 | } | 960 | } |
961 | 961 | ||
962 | case PIO_FONT: { | 962 | case PIO_FONT: { |
963 | if (!perm) | 963 | if (!perm) |
964 | return -EPERM; | 964 | return -EPERM; |
965 | op.op = KD_FONT_OP_SET; | 965 | op.op = KD_FONT_OP_SET; |
966 | op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ | 966 | op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ |
967 | op.width = 8; | 967 | op.width = 8; |
968 | op.height = 0; | 968 | op.height = 0; |
969 | op.charcount = 256; | 969 | op.charcount = 256; |
970 | op.data = up; | 970 | op.data = up; |
971 | return con_font_op(vc_cons[fg_console].d, &op); | 971 | return con_font_op(vc_cons[fg_console].d, &op); |
972 | } | 972 | } |
973 | 973 | ||
974 | case GIO_FONT: { | 974 | case GIO_FONT: { |
975 | op.op = KD_FONT_OP_GET; | 975 | op.op = KD_FONT_OP_GET; |
976 | op.flags = KD_FONT_FLAG_OLD; | 976 | op.flags = KD_FONT_FLAG_OLD; |
977 | op.width = 8; | 977 | op.width = 8; |
978 | op.height = 32; | 978 | op.height = 32; |
979 | op.charcount = 256; | 979 | op.charcount = 256; |
980 | op.data = up; | 980 | op.data = up; |
981 | return con_font_op(vc_cons[fg_console].d, &op); | 981 | return con_font_op(vc_cons[fg_console].d, &op); |
982 | } | 982 | } |
983 | 983 | ||
984 | case PIO_CMAP: | 984 | case PIO_CMAP: |
985 | if (!perm) | 985 | if (!perm) |
986 | return -EPERM; | 986 | return -EPERM; |
987 | return con_set_cmap(up); | 987 | return con_set_cmap(up); |
988 | 988 | ||
989 | case GIO_CMAP: | 989 | case GIO_CMAP: |
990 | return con_get_cmap(up); | 990 | return con_get_cmap(up); |
991 | 991 | ||
992 | case PIO_FONTX: | 992 | case PIO_FONTX: |
993 | case GIO_FONTX: | 993 | case GIO_FONTX: |
994 | return do_fontx_ioctl(cmd, up, perm, &op); | 994 | return do_fontx_ioctl(cmd, up, perm, &op); |
995 | 995 | ||
996 | case PIO_FONTRESET: | 996 | case PIO_FONTRESET: |
997 | { | 997 | { |
998 | if (!perm) | 998 | if (!perm) |
999 | return -EPERM; | 999 | return -EPERM; |
1000 | 1000 | ||
1001 | #ifdef BROKEN_GRAPHICS_PROGRAMS | 1001 | #ifdef BROKEN_GRAPHICS_PROGRAMS |
1002 | /* With BROKEN_GRAPHICS_PROGRAMS defined, the default | 1002 | /* With BROKEN_GRAPHICS_PROGRAMS defined, the default |
1003 | font is not saved. */ | 1003 | font is not saved. */ |
1004 | return -ENOSYS; | 1004 | return -ENOSYS; |
1005 | #else | 1005 | #else |
1006 | { | 1006 | { |
1007 | op.op = KD_FONT_OP_SET_DEFAULT; | 1007 | op.op = KD_FONT_OP_SET_DEFAULT; |
1008 | op.data = NULL; | 1008 | op.data = NULL; |
1009 | i = con_font_op(vc_cons[fg_console].d, &op); | 1009 | i = con_font_op(vc_cons[fg_console].d, &op); |
1010 | if (i) | 1010 | if (i) |
1011 | return i; | 1011 | return i; |
1012 | con_set_default_unimap(vc_cons[fg_console].d); | 1012 | con_set_default_unimap(vc_cons[fg_console].d); |
1013 | return 0; | 1013 | return 0; |
1014 | } | 1014 | } |
1015 | #endif | 1015 | #endif |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | case KDFONTOP: { | 1018 | case KDFONTOP: { |
1019 | if (copy_from_user(&op, up, sizeof(op))) | 1019 | if (copy_from_user(&op, up, sizeof(op))) |
1020 | return -EFAULT; | 1020 | return -EFAULT; |
1021 | if (!perm && op.op != KD_FONT_OP_GET) | 1021 | if (!perm && op.op != KD_FONT_OP_GET) |
1022 | return -EPERM; | 1022 | return -EPERM; |
1023 | i = con_font_op(vc, &op); | 1023 | i = con_font_op(vc, &op); |
1024 | if (i) return i; | 1024 | if (i) return i; |
1025 | if (copy_to_user(up, &op, sizeof(op))) | 1025 | if (copy_to_user(up, &op, sizeof(op))) |
1026 | return -EFAULT; | 1026 | return -EFAULT; |
1027 | return 0; | 1027 | return 0; |
1028 | } | 1028 | } |
1029 | 1029 | ||
1030 | case PIO_SCRNMAP: | 1030 | case PIO_SCRNMAP: |
1031 | if (!perm) | 1031 | if (!perm) |
1032 | return -EPERM; | 1032 | return -EPERM; |
1033 | return con_set_trans_old(up); | 1033 | return con_set_trans_old(up); |
1034 | 1034 | ||
1035 | case GIO_SCRNMAP: | 1035 | case GIO_SCRNMAP: |
1036 | return con_get_trans_old(up); | 1036 | return con_get_trans_old(up); |
1037 | 1037 | ||
1038 | case PIO_UNISCRNMAP: | 1038 | case PIO_UNISCRNMAP: |
1039 | if (!perm) | 1039 | if (!perm) |
1040 | return -EPERM; | 1040 | return -EPERM; |
1041 | return con_set_trans_new(up); | 1041 | return con_set_trans_new(up); |
1042 | 1042 | ||
1043 | case GIO_UNISCRNMAP: | 1043 | case GIO_UNISCRNMAP: |
1044 | return con_get_trans_new(up); | 1044 | return con_get_trans_new(up); |
1045 | 1045 | ||
1046 | case PIO_UNIMAPCLR: | 1046 | case PIO_UNIMAPCLR: |
1047 | { struct unimapinit ui; | 1047 | { struct unimapinit ui; |
1048 | if (!perm) | 1048 | if (!perm) |
1049 | return -EPERM; | 1049 | return -EPERM; |
1050 | i = copy_from_user(&ui, up, sizeof(struct unimapinit)); | 1050 | i = copy_from_user(&ui, up, sizeof(struct unimapinit)); |
1051 | if (i) return -EFAULT; | 1051 | if (i) return -EFAULT; |
1052 | con_clear_unimap(vc, &ui); | 1052 | con_clear_unimap(vc, &ui); |
1053 | return 0; | 1053 | return 0; |
1054 | } | 1054 | } |
1055 | 1055 | ||
1056 | case PIO_UNIMAP: | 1056 | case PIO_UNIMAP: |
1057 | case GIO_UNIMAP: | 1057 | case GIO_UNIMAP: |
1058 | return do_unimap_ioctl(cmd, up, perm, vc); | 1058 | return do_unimap_ioctl(cmd, up, perm, vc); |
1059 | 1059 | ||
1060 | case VT_LOCKSWITCH: | 1060 | case VT_LOCKSWITCH: |
1061 | if (!capable(CAP_SYS_TTY_CONFIG)) | 1061 | if (!capable(CAP_SYS_TTY_CONFIG)) |
1062 | return -EPERM; | 1062 | return -EPERM; |
1063 | vt_dont_switch = 1; | 1063 | vt_dont_switch = 1; |
1064 | return 0; | 1064 | return 0; |
1065 | case VT_UNLOCKSWITCH: | 1065 | case VT_UNLOCKSWITCH: |
1066 | if (!capable(CAP_SYS_TTY_CONFIG)) | 1066 | if (!capable(CAP_SYS_TTY_CONFIG)) |
1067 | return -EPERM; | 1067 | return -EPERM; |
1068 | vt_dont_switch = 0; | 1068 | vt_dont_switch = 0; |
1069 | return 0; | 1069 | return 0; |
1070 | case VT_GETHIFONTMASK: | 1070 | case VT_GETHIFONTMASK: |
1071 | return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg); | 1071 | return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg); |
1072 | default: | 1072 | default: |
1073 | return -ENOIOCTLCMD; | 1073 | return -ENOIOCTLCMD; |
1074 | } | 1074 | } |
1075 | } | 1075 | } |
1076 | 1076 | ||
1077 | /* | 1077 | /* |
1078 | * Sometimes we want to wait until a particular VT has been activated. We | 1078 | * Sometimes we want to wait until a particular VT has been activated. We |
1079 | * do it in a very simple manner. Everybody waits on a single queue and | 1079 | * do it in a very simple manner. Everybody waits on a single queue and |
1080 | * get woken up at once. Those that are satisfied go on with their business, | 1080 | * get woken up at once. Those that are satisfied go on with their business, |
1081 | * while those not ready go back to sleep. Seems overkill to add a wait | 1081 | * while those not ready go back to sleep. Seems overkill to add a wait |
1082 | * to each vt just for this - usually this does nothing! | 1082 | * to each vt just for this - usually this does nothing! |
1083 | */ | 1083 | */ |
1084 | static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); | 1084 | static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); |
1085 | 1085 | ||
1086 | /* | 1086 | /* |
1087 | * Sleeps until a vt is activated, or the task is interrupted. Returns | 1087 | * Sleeps until a vt is activated, or the task is interrupted. Returns |
1088 | * 0 if activation, -EINTR if interrupted by a signal handler. | 1088 | * 0 if activation, -EINTR if interrupted by a signal handler. |
1089 | */ | 1089 | */ |
1090 | int vt_waitactive(int vt) | 1090 | int vt_waitactive(int vt) |
1091 | { | 1091 | { |
1092 | int retval; | 1092 | int retval; |
1093 | DECLARE_WAITQUEUE(wait, current); | 1093 | DECLARE_WAITQUEUE(wait, current); |
1094 | 1094 | ||
1095 | add_wait_queue(&vt_activate_queue, &wait); | 1095 | add_wait_queue(&vt_activate_queue, &wait); |
1096 | for (;;) { | 1096 | for (;;) { |
1097 | retval = 0; | 1097 | retval = 0; |
1098 | 1098 | ||
1099 | /* | 1099 | /* |
1100 | * Synchronize with redraw_screen(). By acquiring the console | 1100 | * Synchronize with redraw_screen(). By acquiring the console |
1101 | * semaphore we make sure that the console switch is completed | 1101 | * semaphore we make sure that the console switch is completed |
1102 | * before we return. If we didn't wait for the semaphore, we | 1102 | * before we return. If we didn't wait for the semaphore, we |
1103 | * could return at a point where fg_console has already been | 1103 | * could return at a point where fg_console has already been |
1104 | * updated, but the console switch hasn't been completed. | 1104 | * updated, but the console switch hasn't been completed. |
1105 | */ | 1105 | */ |
1106 | acquire_console_sem(); | 1106 | acquire_console_sem(); |
1107 | set_current_state(TASK_INTERRUPTIBLE); | 1107 | set_current_state(TASK_INTERRUPTIBLE); |
1108 | if (vt == fg_console) { | 1108 | if (vt == fg_console) { |
1109 | release_console_sem(); | 1109 | release_console_sem(); |
1110 | break; | 1110 | break; |
1111 | } | 1111 | } |
1112 | release_console_sem(); | 1112 | release_console_sem(); |
1113 | retval = -ERESTARTNOHAND; | 1113 | retval = -ERESTARTNOHAND; |
1114 | if (signal_pending(current)) | 1114 | if (signal_pending(current)) |
1115 | break; | 1115 | break; |
1116 | schedule(); | 1116 | schedule(); |
1117 | } | 1117 | } |
1118 | remove_wait_queue(&vt_activate_queue, &wait); | 1118 | remove_wait_queue(&vt_activate_queue, &wait); |
1119 | __set_current_state(TASK_RUNNING); | 1119 | __set_current_state(TASK_RUNNING); |
1120 | return retval; | 1120 | return retval; |
1121 | } | 1121 | } |
1122 | 1122 | ||
1123 | #define vt_wake_waitactive() wake_up(&vt_activate_queue) | 1123 | #define vt_wake_waitactive() wake_up(&vt_activate_queue) |
1124 | 1124 | ||
1125 | void reset_vc(struct vc_data *vc) | 1125 | void reset_vc(struct vc_data *vc) |
1126 | { | 1126 | { |
1127 | vc->vc_mode = KD_TEXT; | 1127 | vc->vc_mode = KD_TEXT; |
1128 | kbd_table[vc->vc_num].kbdmode = VC_XLATE; | 1128 | kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; |
1129 | vc->vt_mode.mode = VT_AUTO; | 1129 | vc->vt_mode.mode = VT_AUTO; |
1130 | vc->vt_mode.waitv = 0; | 1130 | vc->vt_mode.waitv = 0; |
1131 | vc->vt_mode.relsig = 0; | 1131 | vc->vt_mode.relsig = 0; |
1132 | vc->vt_mode.acqsig = 0; | 1132 | vc->vt_mode.acqsig = 0; |
1133 | vc->vt_mode.frsig = 0; | 1133 | vc->vt_mode.frsig = 0; |
1134 | put_pid(vc->vt_pid); | 1134 | put_pid(vc->vt_pid); |
1135 | vc->vt_pid = NULL; | 1135 | vc->vt_pid = NULL; |
1136 | vc->vt_newvt = -1; | 1136 | vc->vt_newvt = -1; |
1137 | if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ | 1137 | if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ |
1138 | reset_palette(vc); | 1138 | reset_palette(vc); |
1139 | } | 1139 | } |
1140 | 1140 | ||
1141 | void vc_SAK(struct work_struct *work) | 1141 | void vc_SAK(struct work_struct *work) |
1142 | { | 1142 | { |
1143 | struct vc *vc_con = | 1143 | struct vc *vc_con = |
1144 | container_of(work, struct vc, SAK_work); | 1144 | container_of(work, struct vc, SAK_work); |
1145 | struct vc_data *vc; | 1145 | struct vc_data *vc; |
1146 | struct tty_struct *tty; | 1146 | struct tty_struct *tty; |
1147 | 1147 | ||
1148 | acquire_console_sem(); | 1148 | acquire_console_sem(); |
1149 | vc = vc_con->d; | 1149 | vc = vc_con->d; |
1150 | if (vc) { | 1150 | if (vc) { |
1151 | tty = vc->vc_tty; | 1151 | tty = vc->vc_tty; |
1152 | /* | 1152 | /* |
1153 | * SAK should also work in all raw modes and reset | 1153 | * SAK should also work in all raw modes and reset |
1154 | * them properly. | 1154 | * them properly. |
1155 | */ | 1155 | */ |
1156 | if (tty) | 1156 | if (tty) |
1157 | __do_SAK(tty); | 1157 | __do_SAK(tty); |
1158 | reset_vc(vc); | 1158 | reset_vc(vc); |
1159 | } | 1159 | } |
1160 | release_console_sem(); | 1160 | release_console_sem(); |
1161 | } | 1161 | } |
1162 | 1162 | ||
1163 | /* | 1163 | /* |
1164 | * Performs the back end of a vt switch | 1164 | * Performs the back end of a vt switch |
1165 | */ | 1165 | */ |
1166 | static void complete_change_console(struct vc_data *vc) | 1166 | static void complete_change_console(struct vc_data *vc) |
1167 | { | 1167 | { |
1168 | unsigned char old_vc_mode; | 1168 | unsigned char old_vc_mode; |
1169 | 1169 | ||
1170 | last_console = fg_console; | 1170 | last_console = fg_console; |
1171 | 1171 | ||
1172 | /* | 1172 | /* |
1173 | * If we're switching, we could be going from KD_GRAPHICS to | 1173 | * If we're switching, we could be going from KD_GRAPHICS to |
1174 | * KD_TEXT mode or vice versa, which means we need to blank or | 1174 | * KD_TEXT mode or vice versa, which means we need to blank or |
1175 | * unblank the screen later. | 1175 | * unblank the screen later. |
1176 | */ | 1176 | */ |
1177 | old_vc_mode = vc_cons[fg_console].d->vc_mode; | 1177 | old_vc_mode = vc_cons[fg_console].d->vc_mode; |
1178 | switch_screen(vc); | 1178 | switch_screen(vc); |
1179 | 1179 | ||
1180 | /* | 1180 | /* |
1181 | * This can't appear below a successful kill_pid(). If it did, | 1181 | * This can't appear below a successful kill_pid(). If it did, |
1182 | * then the *blank_screen operation could occur while X, having | 1182 | * then the *blank_screen operation could occur while X, having |
1183 | * received acqsig, is waking up on another processor. This | 1183 | * received acqsig, is waking up on another processor. This |
1184 | * condition can lead to overlapping accesses to the VGA range | 1184 | * condition can lead to overlapping accesses to the VGA range |
1185 | * and the framebuffer (causing system lockups). | 1185 | * and the framebuffer (causing system lockups). |
1186 | * | 1186 | * |
1187 | * To account for this we duplicate this code below only if the | 1187 | * To account for this we duplicate this code below only if the |
1188 | * controlling process is gone and we've called reset_vc. | 1188 | * controlling process is gone and we've called reset_vc. |
1189 | */ | 1189 | */ |
1190 | if (old_vc_mode != vc->vc_mode) { | 1190 | if (old_vc_mode != vc->vc_mode) { |
1191 | if (vc->vc_mode == KD_TEXT) | 1191 | if (vc->vc_mode == KD_TEXT) |
1192 | do_unblank_screen(1); | 1192 | do_unblank_screen(1); |
1193 | else | 1193 | else |
1194 | do_blank_screen(1); | 1194 | do_blank_screen(1); |
1195 | } | 1195 | } |
1196 | 1196 | ||
1197 | /* | 1197 | /* |
1198 | * If this new console is under process control, send it a signal | 1198 | * If this new console is under process control, send it a signal |
1199 | * telling it that it has acquired. Also check if it has died and | 1199 | * telling it that it has acquired. Also check if it has died and |
1200 | * clean up (similar to logic employed in change_console()) | 1200 | * clean up (similar to logic employed in change_console()) |
1201 | */ | 1201 | */ |
1202 | if (vc->vt_mode.mode == VT_PROCESS) { | 1202 | if (vc->vt_mode.mode == VT_PROCESS) { |
1203 | /* | 1203 | /* |
1204 | * Send the signal as privileged - kill_pid() will | 1204 | * Send the signal as privileged - kill_pid() will |
1205 | * tell us if the process has gone or something else | 1205 | * tell us if the process has gone or something else |
1206 | * is awry | 1206 | * is awry |
1207 | */ | 1207 | */ |
1208 | if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { | 1208 | if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { |
1209 | /* | 1209 | /* |
1210 | * The controlling process has died, so we revert back to | 1210 | * The controlling process has died, so we revert back to |
1211 | * normal operation. In this case, we'll also change back | 1211 | * normal operation. In this case, we'll also change back |
1212 | * to KD_TEXT mode. I'm not sure if this is strictly correct | 1212 | * to KD_TEXT mode. I'm not sure if this is strictly correct |
1213 | * but it saves the agony when the X server dies and the screen | 1213 | * but it saves the agony when the X server dies and the screen |
1214 | * remains blanked due to KD_GRAPHICS! It would be nice to do | 1214 | * remains blanked due to KD_GRAPHICS! It would be nice to do |
1215 | * this outside of VT_PROCESS but there is no single process | 1215 | * this outside of VT_PROCESS but there is no single process |
1216 | * to account for and tracking tty count may be undesirable. | 1216 | * to account for and tracking tty count may be undesirable. |
1217 | */ | 1217 | */ |
1218 | reset_vc(vc); | 1218 | reset_vc(vc); |
1219 | 1219 | ||
1220 | if (old_vc_mode != vc->vc_mode) { | 1220 | if (old_vc_mode != vc->vc_mode) { |
1221 | if (vc->vc_mode == KD_TEXT) | 1221 | if (vc->vc_mode == KD_TEXT) |
1222 | do_unblank_screen(1); | 1222 | do_unblank_screen(1); |
1223 | else | 1223 | else |
1224 | do_blank_screen(1); | 1224 | do_blank_screen(1); |
1225 | } | 1225 | } |
1226 | } | 1226 | } |
1227 | } | 1227 | } |
1228 | 1228 | ||
1229 | /* | 1229 | /* |
1230 | * Wake anyone waiting for their VT to activate | 1230 | * Wake anyone waiting for their VT to activate |
1231 | */ | 1231 | */ |
1232 | vt_wake_waitactive(); | 1232 | vt_wake_waitactive(); |
1233 | return; | 1233 | return; |
1234 | } | 1234 | } |
1235 | 1235 | ||
1236 | /* | 1236 | /* |
1237 | * Performs the front-end of a vt switch | 1237 | * Performs the front-end of a vt switch |
1238 | */ | 1238 | */ |
1239 | void change_console(struct vc_data *new_vc) | 1239 | void change_console(struct vc_data *new_vc) |
1240 | { | 1240 | { |
1241 | struct vc_data *vc; | 1241 | struct vc_data *vc; |
1242 | 1242 | ||
1243 | if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch) | 1243 | if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch) |
1244 | return; | 1244 | return; |
1245 | 1245 | ||
1246 | /* | 1246 | /* |
1247 | * If this vt is in process mode, then we need to handshake with | 1247 | * If this vt is in process mode, then we need to handshake with |
1248 | * that process before switching. Essentially, we store where that | 1248 | * that process before switching. Essentially, we store where that |
1249 | * vt wants to switch to and wait for it to tell us when it's done | 1249 | * vt wants to switch to and wait for it to tell us when it's done |
1250 | * (via VT_RELDISP ioctl). | 1250 | * (via VT_RELDISP ioctl). |
1251 | * | 1251 | * |
1252 | * We also check to see if the controlling process still exists. | 1252 | * We also check to see if the controlling process still exists. |
1253 | * If it doesn't, we reset this vt to auto mode and continue. | 1253 | * If it doesn't, we reset this vt to auto mode and continue. |
1254 | * This is a cheap way to track process control. The worst thing | 1254 | * This is a cheap way to track process control. The worst thing |
1255 | * that can happen is: we send a signal to a process, it dies, and | 1255 | * that can happen is: we send a signal to a process, it dies, and |
1256 | * the switch gets "lost" waiting for a response; hopefully, the | 1256 | * the switch gets "lost" waiting for a response; hopefully, the |
1257 | * user will try again, we'll detect the process is gone (unless | 1257 | * user will try again, we'll detect the process is gone (unless |
1258 | * the user waits just the right amount of time :-) and revert the | 1258 | * the user waits just the right amount of time :-) and revert the |
1259 | * vt to auto control. | 1259 | * vt to auto control. |
1260 | */ | 1260 | */ |
1261 | vc = vc_cons[fg_console].d; | 1261 | vc = vc_cons[fg_console].d; |
1262 | if (vc->vt_mode.mode == VT_PROCESS) { | 1262 | if (vc->vt_mode.mode == VT_PROCESS) { |
1263 | /* | 1263 | /* |
1264 | * Send the signal as privileged - kill_pid() will | 1264 | * Send the signal as privileged - kill_pid() will |
1265 | * tell us if the process has gone or something else | 1265 | * tell us if the process has gone or something else |
1266 | * is awry. | 1266 | * is awry. |
1267 | * | 1267 | * |
1268 | * We need to set vt_newvt *before* sending the signal or we | 1268 | * We need to set vt_newvt *before* sending the signal or we |
1269 | * have a race. | 1269 | * have a race. |
1270 | */ | 1270 | */ |
1271 | vc->vt_newvt = new_vc->vc_num; | 1271 | vc->vt_newvt = new_vc->vc_num; |
1272 | if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { | 1272 | if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { |
1273 | /* | 1273 | /* |
1274 | * It worked. Mark the vt to switch to and | 1274 | * It worked. Mark the vt to switch to and |
1275 | * return. The process needs to send us a | 1275 | * return. The process needs to send us a |
1276 | * VT_RELDISP ioctl to complete the switch. | 1276 | * VT_RELDISP ioctl to complete the switch. |
1277 | */ | 1277 | */ |
1278 | return; | 1278 | return; |
1279 | } | 1279 | } |
1280 | 1280 | ||
1281 | /* | 1281 | /* |
1282 | * The controlling process has died, so we revert back to | 1282 | * The controlling process has died, so we revert back to |
1283 | * normal operation. In this case, we'll also change back | 1283 | * normal operation. In this case, we'll also change back |
1284 | * to KD_TEXT mode. I'm not sure if this is strictly correct | 1284 | * to KD_TEXT mode. I'm not sure if this is strictly correct |
1285 | * but it saves the agony when the X server dies and the screen | 1285 | * but it saves the agony when the X server dies and the screen |
1286 | * remains blanked due to KD_GRAPHICS! It would be nice to do | 1286 | * remains blanked due to KD_GRAPHICS! It would be nice to do |
1287 | * this outside of VT_PROCESS but there is no single process | 1287 | * this outside of VT_PROCESS but there is no single process |
1288 | * to account for and tracking tty count may be undesirable. | 1288 | * to account for and tracking tty count may be undesirable. |
1289 | */ | 1289 | */ |
1290 | reset_vc(vc); | 1290 | reset_vc(vc); |
1291 | 1291 | ||
1292 | /* | 1292 | /* |
1293 | * Fall through to normal (VT_AUTO) handling of the switch... | 1293 | * Fall through to normal (VT_AUTO) handling of the switch... |
1294 | */ | 1294 | */ |
1295 | } | 1295 | } |
1296 | 1296 | ||
1297 | /* | 1297 | /* |
1298 | * Ignore all switches in KD_GRAPHICS+VT_AUTO mode | 1298 | * Ignore all switches in KD_GRAPHICS+VT_AUTO mode |
1299 | */ | 1299 | */ |
1300 | if (vc->vc_mode == KD_GRAPHICS) | 1300 | if (vc->vc_mode == KD_GRAPHICS) |
1301 | return; | 1301 | return; |
1302 | 1302 | ||
1303 | complete_change_console(new_vc); | 1303 | complete_change_console(new_vc); |
1304 | } | 1304 | } |
1305 | 1305 |
include/linux/vt_kern.h
1 | #ifndef _VT_KERN_H | 1 | #ifndef _VT_KERN_H |
2 | #define _VT_KERN_H | 2 | #define _VT_KERN_H |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * this really is an extension of the vc_cons structure in console.c, but | 5 | * this really is an extension of the vc_cons structure in console.c, but |
6 | * with information needed by the vt package | 6 | * with information needed by the vt package |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/vt.h> | 9 | #include <linux/vt.h> |
10 | #include <linux/kd.h> | 10 | #include <linux/kd.h> |
11 | #include <linux/tty.h> | 11 | #include <linux/tty.h> |
12 | #include <linux/mutex.h> | 12 | #include <linux/mutex.h> |
13 | #include <linux/console_struct.h> | 13 | #include <linux/console_struct.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * Presently, a lot of graphics programs do not restore the contents of | 17 | * Presently, a lot of graphics programs do not restore the contents of |
18 | * the higher font pages. Defining this flag will avoid use of them, but | 18 | * the higher font pages. Defining this flag will avoid use of them, but |
19 | * will lose support for PIO_FONTRESET. Note that many font operations are | 19 | * will lose support for PIO_FONTRESET. Note that many font operations are |
20 | * not likely to work with these programs anyway; they need to be | 20 | * not likely to work with these programs anyway; they need to be |
21 | * fixed. The linux/Documentation directory includes a code snippet | 21 | * fixed. The linux/Documentation directory includes a code snippet |
22 | * to save and restore the text font. | 22 | * to save and restore the text font. |
23 | */ | 23 | */ |
24 | #ifdef CONFIG_VGA_CONSOLE | 24 | #ifdef CONFIG_VGA_CONSOLE |
25 | #define BROKEN_GRAPHICS_PROGRAMS 1 | 25 | #define BROKEN_GRAPHICS_PROGRAMS 1 |
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | extern void kd_mksound(unsigned int hz, unsigned int ticks); | 28 | extern void kd_mksound(unsigned int hz, unsigned int ticks); |
29 | extern int kbd_rate(struct kbd_repeat *rep); | 29 | extern int kbd_rate(struct kbd_repeat *rep); |
30 | extern int fg_console, last_console, want_console; | 30 | extern int fg_console, last_console, want_console; |
31 | 31 | ||
32 | /* console.c */ | 32 | /* console.c */ |
33 | 33 | ||
34 | int vc_allocate(unsigned int console); | 34 | int vc_allocate(unsigned int console); |
35 | int vc_cons_allocated(unsigned int console); | 35 | int vc_cons_allocated(unsigned int console); |
36 | int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); | 36 | int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); |
37 | int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); | 37 | int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); |
38 | void vc_deallocate(unsigned int console); | 38 | void vc_deallocate(unsigned int console); |
39 | void reset_palette(struct vc_data *vc); | 39 | void reset_palette(struct vc_data *vc); |
40 | void do_blank_screen(int entering_gfx); | 40 | void do_blank_screen(int entering_gfx); |
41 | void do_unblank_screen(int leaving_gfx); | 41 | void do_unblank_screen(int leaving_gfx); |
42 | void unblank_screen(void); | 42 | void unblank_screen(void); |
43 | void poke_blanked_console(void); | 43 | void poke_blanked_console(void); |
44 | int con_font_op(struct vc_data *vc, struct console_font_op *op); | 44 | int con_font_op(struct vc_data *vc, struct console_font_op *op); |
45 | int con_set_cmap(unsigned char __user *cmap); | 45 | int con_set_cmap(unsigned char __user *cmap); |
46 | int con_get_cmap(unsigned char __user *cmap); | 46 | int con_get_cmap(unsigned char __user *cmap); |
47 | void scrollback(struct vc_data *vc, int lines); | 47 | void scrollback(struct vc_data *vc, int lines); |
48 | void scrollfront(struct vc_data *vc, int lines); | 48 | void scrollfront(struct vc_data *vc, int lines); |
49 | void update_region(struct vc_data *vc, unsigned long start, int count); | 49 | void update_region(struct vc_data *vc, unsigned long start, int count); |
50 | void redraw_screen(struct vc_data *vc, int is_switch); | 50 | void redraw_screen(struct vc_data *vc, int is_switch); |
51 | #define update_screen(x) redraw_screen(x, 0) | 51 | #define update_screen(x) redraw_screen(x, 0) |
52 | #define switch_screen(x) redraw_screen(x, 1) | 52 | #define switch_screen(x) redraw_screen(x, 1) |
53 | 53 | ||
54 | struct tty_struct; | 54 | struct tty_struct; |
55 | int tioclinux(struct tty_struct *tty, unsigned long arg); | 55 | int tioclinux(struct tty_struct *tty, unsigned long arg); |
56 | 56 | ||
57 | /* consolemap.c */ | 57 | /* consolemap.c */ |
58 | 58 | ||
59 | struct unimapinit; | 59 | struct unimapinit; |
60 | struct unipair; | 60 | struct unipair; |
61 | 61 | ||
62 | int con_set_trans_old(unsigned char __user * table); | 62 | int con_set_trans_old(unsigned char __user * table); |
63 | int con_get_trans_old(unsigned char __user * table); | 63 | int con_get_trans_old(unsigned char __user * table); |
64 | int con_set_trans_new(unsigned short __user * table); | 64 | int con_set_trans_new(unsigned short __user * table); |
65 | int con_get_trans_new(unsigned short __user * table); | 65 | int con_get_trans_new(unsigned short __user * table); |
66 | int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui); | 66 | int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui); |
67 | int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list); | 67 | int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list); |
68 | int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list); | 68 | int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list); |
69 | int con_set_default_unimap(struct vc_data *vc); | 69 | int con_set_default_unimap(struct vc_data *vc); |
70 | void con_free_unimap(struct vc_data *vc); | 70 | void con_free_unimap(struct vc_data *vc); |
71 | void con_protect_unimap(struct vc_data *vc, int rdonly); | 71 | void con_protect_unimap(struct vc_data *vc, int rdonly); |
72 | int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc); | 72 | int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc); |
73 | 73 | ||
74 | /* vt.c */ | 74 | /* vt.c */ |
75 | int vt_waitactive(int vt); | 75 | int vt_waitactive(int vt); |
76 | void change_console(struct vc_data *new_vc); | 76 | void change_console(struct vc_data *new_vc); |
77 | void reset_vc(struct vc_data *vc); | 77 | void reset_vc(struct vc_data *vc); |
78 | extern int unbind_con_driver(const struct consw *csw, int first, int last, | 78 | extern int unbind_con_driver(const struct consw *csw, int first, int last, |
79 | int deflt); | 79 | int deflt); |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * vc_screen.c shares this temporary buffer with the console write code so that | 82 | * vc_screen.c shares this temporary buffer with the console write code so that |
83 | * we can easily avoid touching user space while holding the console spinlock. | 83 | * we can easily avoid touching user space while holding the console spinlock. |
84 | */ | 84 | */ |
85 | 85 | ||
86 | #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) | 86 | #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) |
87 | extern char con_buf[CON_BUF_SIZE]; | 87 | extern char con_buf[CON_BUF_SIZE]; |
88 | extern struct mutex con_buf_mtx; | 88 | extern struct mutex con_buf_mtx; |
89 | extern char vt_dont_switch; | 89 | extern char vt_dont_switch; |
90 | extern int default_utf8; | ||
90 | 91 | ||
91 | struct vt_spawn_console { | 92 | struct vt_spawn_console { |
92 | spinlock_t lock; | 93 | spinlock_t lock; |
93 | struct pid *pid; | 94 | struct pid *pid; |
94 | int sig; | 95 | int sig; |
95 | }; | 96 | }; |
96 | extern struct vt_spawn_console vt_spawn_con; | 97 | extern struct vt_spawn_console vt_spawn_con; |
97 | 98 | ||
98 | #endif /* _VT_KERN_H */ | 99 | #endif /* _VT_KERN_H */ |
99 | 100 |