diff options
author | Willy Tarreau <w@1wt.eu> | 2008-11-13 20:18:59 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 16:52:29 -0500 |
commit | 7005b58458e4beecaf5efacb872c456bc7d3541a (patch) | |
tree | f9e42e1afd86d077508759180d0e4ea5832998ff | |
parent | 18223a99e60787ce41159ed321c8f0a21c328ac1 (diff) |
Staging: add lcd-panel driver
This adds the lcd-panel parallel port driver to the staging tree.
See the file, drivers/staging/panel/TODO for what needs to be fixed up
in order for this to be properly merged into the rest of the kernel
tree.
Cc: Willy Tarreau <w@1wt.eu>
Cc: Frank Menne <frank.menne@hsm.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/panel/Kconfig | 290 | ||||
-rw-r--r-- | drivers/staging/panel/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/panel/TODO | 9 | ||||
-rw-r--r-- | drivers/staging/panel/lcd-panel-cgram.txt | 24 | ||||
-rw-r--r-- | drivers/staging/panel/panel.c | 2343 |
7 files changed, 2670 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index a3e361db69fe..11d003d37ad9 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
@@ -77,5 +77,7 @@ source "drivers/staging/comedi/Kconfig" | |||
77 | 77 | ||
78 | source "drivers/staging/asus_oled/Kconfig" | 78 | source "drivers/staging/asus_oled/Kconfig" |
79 | 79 | ||
80 | source "drivers/staging/panel/Kconfig" | ||
81 | |||
80 | endif # !STAGING_EXCLUDE_BUILD | 82 | endif # !STAGING_EXCLUDE_BUILD |
81 | endif # STAGING | 83 | endif # STAGING |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 06613bb05085..a738bb34c8ae 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
@@ -21,3 +21,4 @@ obj-$(CONFIG_RT2860) += rt2860/ | |||
21 | obj-$(CONFIG_BENET) += benet/ | 21 | obj-$(CONFIG_BENET) += benet/ |
22 | obj-$(CONFIG_COMEDI) += comedi/ | 22 | obj-$(CONFIG_COMEDI) += comedi/ |
23 | obj-$(CONFIG_ASUS_OLED) += asus_oled/ | 23 | obj-$(CONFIG_ASUS_OLED) += asus_oled/ |
24 | obj-$(CONFIG_PANEL) += panel/ | ||
diff --git a/drivers/staging/panel/Kconfig b/drivers/staging/panel/Kconfig new file mode 100644 index 000000000000..7cf655757748 --- /dev/null +++ b/drivers/staging/panel/Kconfig | |||
@@ -0,0 +1,290 @@ | |||
1 | config PANEL | ||
2 | tristate "Parallel port LCD/Keypad Panel support" | ||
3 | depends on PARPORT | ||
4 | ---help--- | ||
5 | Say Y here if you have an HD44780 or KS-0074 LCD connected to your | ||
6 | parallel port. This driver also features 4 and 6-key keypads, and a | ||
7 | 'smartcard' reader. The LCD is accessible through the /dev/lcd char | ||
8 | device (10, 156), the keypad through /dev/keypad (10, 185), and the | ||
9 | smartcard through /dev/smartcard (10, 186). Both require misc device | ||
10 | to be enabled. This code can either be compiled as a module, or linked | ||
11 | into the kernel and started at boot. If you don't understand what all | ||
12 | this is about, say N. | ||
13 | |||
14 | config PANEL_PARPORT | ||
15 | int "Default parallel port number (0=LPT1)" | ||
16 | depends on PANEL | ||
17 | range 0 255 | ||
18 | default "0" | ||
19 | ---help--- | ||
20 | This is the index of the parallel port the panel is connected to. One | ||
21 | driver instance only supports one parallel port, so if your keypad | ||
22 | and LCD are connected to two separate ports, you have to start two | ||
23 | modules with different arguments. Numbering starts with '0' for LPT1, | ||
24 | and so on. | ||
25 | |||
26 | config PANEL_PROFILE | ||
27 | int "Default panel profile (0-5, 0=custom)" | ||
28 | depends on PANEL | ||
29 | range 0 5 | ||
30 | default "5" | ||
31 | ---help--- | ||
32 | To ease configuration, the driver supports different configuration | ||
33 | profiles for past and recent wirings. These profiles can also be | ||
34 | used to define an approximative configuration, completed by a few | ||
35 | other options. Here are the profiles : | ||
36 | |||
37 | 0 = custom (see further) | ||
38 | 1 = 2x16 parallel LCD, old keypad | ||
39 | 2 = 2x16 serial LCD (KS-0074), new keypad | ||
40 | 3 = 2x16 parallel LCD (Hantronix), no keypad | ||
41 | 4 = 2x16 parallel LCD (Nexcom NSA1045) with Nexcom's keypad | ||
42 | 5 = 2x40 parallel LCD (old one), with old keypad | ||
43 | |||
44 | Custom configurations allow you to define how your display is | ||
45 | wired to the parallel port, and how it works. This is only intended | ||
46 | for experts. | ||
47 | |||
48 | config PANEL_SMARTCARD | ||
49 | depends on PANEL && PANEL_PROFILE="0" | ||
50 | bool "Enable smartcard reader (read help!)" | ||
51 | default "n" | ||
52 | ---help--- | ||
53 | This enables the 'smartcard' reader as installed on the server at | ||
54 | 'www.ant-computing.com'. It was not really a smartcard reader, just | ||
55 | a telephone-card reader. It is left here for demonstration and | ||
56 | experimentation. If you enable this driver, it will be accessible | ||
57 | through character device 10,186. | ||
58 | |||
59 | config PANEL_KEYPAD | ||
60 | depends on PANEL && PANEL_PROFILE="0" | ||
61 | int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)" | ||
62 | range 0 4 | ||
63 | default 0 | ||
64 | ---help--- | ||
65 | This enables and configures a keypad connected to the parallel port. | ||
66 | The keys will be read from character device 10,185. Valid values are : | ||
67 | |||
68 | 0 : do not enable this driver | ||
69 | 1 : old 6 keys keypad | ||
70 | 2 : new 6 keys keypad, as used on the server at www.ant-computing.com | ||
71 | 3 : Nexcom NSA1045's 4 keys keypad | ||
72 | |||
73 | New profiles can be described in the driver source. The driver also | ||
74 | supports simultaneous keys pressed when the keypad supports them. | ||
75 | |||
76 | config PANEL_LCD | ||
77 | depends on PANEL && PANEL_PROFILE="0" | ||
78 | int "LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)" | ||
79 | range 0 5 | ||
80 | default 0 | ||
81 | ---help--- | ||
82 | This enables and configures an LCD connected to the parallel port. | ||
83 | The driver includes an interpreter for escape codes starting with | ||
84 | '\e[L' which are specific to the LCD, and a few ANSI codes. The | ||
85 | driver will be registered as character device 10,156, usually | ||
86 | under the name '/dev/lcd'. There are a total of 6 supported types : | ||
87 | |||
88 | 0 : do not enable the driver | ||
89 | 1 : custom configuration and wiring (see further) | ||
90 | 2 : 2x16 & 2x40 parallel LCD (old wiring) | ||
91 | 3 : 2x16 serial LCD (KS-0074 based) | ||
92 | 4 : 2x16 parallel LCD (Hantronix wiring) | ||
93 | 5 : 2x16 parallel LCD (Nexcom wiring) | ||
94 | |||
95 | When type '1' is specified, other options will appear to configure | ||
96 | more precise aspects (wiring, dimensions, protocol, ...). Please note | ||
97 | that those values changed from the 2.4 driver for better consistency. | ||
98 | |||
99 | config PANEL_LCD_HEIGHT | ||
100 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | ||
101 | int "Number of lines on the LCD (1-2)" | ||
102 | range 1 2 | ||
103 | default 2 | ||
104 | ---help--- | ||
105 | This is the number of visible character lines on the LCD in custom profile. | ||
106 | It can either be 1 or 2. | ||
107 | |||
108 | config PANEL_LCD_WIDTH | ||
109 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | ||
110 | int "Number of characters per line on the LCD (1-40)" | ||
111 | range 1 40 | ||
112 | default 40 | ||
113 | ---help--- | ||
114 | This is the number of characters per line on the LCD in custom profile. | ||
115 | Common values are 16,20,24,40. | ||
116 | |||
117 | config PANEL_LCD_BWIDTH | ||
118 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | ||
119 | int "Internal LCD line width (1-40, 40 by default)" | ||
120 | range 1 40 | ||
121 | default 40 | ||
122 | ---help--- | ||
123 | Most LCDs use a standard controller which supports hardware lines of 40 | ||
124 | characters, although sometimes only 16, 20 or 24 of them are really wired | ||
125 | to the terminal. This results in some non-visible but adressable characters, | ||
126 | and is the case for most parallel LCDs. Other LCDs, and some serial ones, | ||
127 | however, use the same line width internally as what is visible. The KS0074 | ||
128 | for example, uses 16 characters per line for 16 visible characters per line. | ||
129 | |||
130 | This option lets you configure the value used by your LCD in 'custom' profile. | ||
131 | If you don't know, put '40' here. | ||
132 | |||
133 | config PANEL_LCD_HWIDTH | ||
134 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | ||
135 | int "Hardware LCD line width (1-64, 64 by default)" | ||
136 | range 1 64 | ||
137 | default 64 | ||
138 | ---help--- | ||
139 | Most LCDs use a single address bit to differentiate line 0 and line 1. Since | ||
140 | some of them need to be able to address 40 chars with the lower bits, they | ||
141 | often use the immediately superior power of 2, which is 64, to address the | ||
142 | next line. | ||
143 | |||
144 | If you don't know what your LCD uses, in doubt let 16 here for a 2x16, and | ||
145 | 64 here for a 2x40. | ||
146 | |||
147 | config PANEL_LCD_CHARSET | ||
148 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | ||
149 | int "LCD character set (0=normal, 1=KS0074)" | ||
150 | range 0 1 | ||
151 | default 0 | ||
152 | ---help--- | ||
153 | Some controllers such as the KS0074 use a somewhat strange character set | ||
154 | where many symbols are at unusual places. The driver knows how to map | ||
155 | 'standard' ASCII characters to the character sets used by these controllers. | ||
156 | Valid values are : | ||
157 | |||
158 | 0 : normal (untranslated) character set | ||
159 | 1 : KS0074 character set | ||
160 | |||
161 | If you don't know, use the normal one (0). | ||
162 | |||
163 | config PANEL_LCD_PROTO | ||
164 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | ||
165 | int "LCD communication mode (0=parallel 8 bits, 1=serial)" | ||
166 | range 0 1 | ||
167 | default 0 | ||
168 | ---help--- | ||
169 | This driver now supports any serial or parallel LCD wired to a parallel | ||
170 | port. But before assigning signals, the driver needs to know if it will | ||
171 | be driving a serial LCD or a parallel one. Serial LCDs only use 2 wires | ||
172 | (SDA/SCL), while parallel ones use 2 or 3 wires for the control signals | ||
173 | (E, RS, sometimes RW), and 4 or 8 for the data. Use 0 here for a 8 bits | ||
174 | parallel LCD, and 1 for a serial LCD. | ||
175 | |||
176 | config PANEL_LCD_PIN_E | ||
177 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
178 | int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) " | ||
179 | range -17 17 | ||
180 | default 14 | ||
181 | ---help--- | ||
182 | This describes the number of the parallel port pin to which the LCD 'E' | ||
183 | signal has been connected. It can be : | ||
184 | |||
185 | 0 : no connection (eg: connected to ground) | ||
186 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
187 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
188 | |||
189 | Default for the 'E' pin in custom profile is '14' (AUTOFEED). | ||
190 | |||
191 | config PANEL_LCD_PIN_RS | ||
192 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
193 | int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) " | ||
194 | range -17 17 | ||
195 | default 17 | ||
196 | ---help--- | ||
197 | This describes the number of the parallel port pin to which the LCD 'RS' | ||
198 | signal has been connected. It can be : | ||
199 | |||
200 | 0 : no connection (eg: connected to ground) | ||
201 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
202 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
203 | |||
204 | Default for the 'RS' pin in custom profile is '17' (SELECT IN). | ||
205 | |||
206 | config PANEL_LCD_PIN_RW | ||
207 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
208 | int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) " | ||
209 | range -17 17 | ||
210 | default 16 | ||
211 | ---help--- | ||
212 | This describes the number of the parallel port pin to which the LCD 'RW' | ||
213 | signal has been connected. It can be : | ||
214 | |||
215 | 0 : no connection (eg: connected to ground) | ||
216 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
217 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
218 | |||
219 | Default for the 'RW' pin in custom profile is '16' (INIT). | ||
220 | |||
221 | config PANEL_LCD_PIN_SCL | ||
222 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" | ||
223 | int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) " | ||
224 | range -17 17 | ||
225 | default 1 | ||
226 | ---help--- | ||
227 | This describes the number of the parallel port pin to which the serial | ||
228 | LCD 'SCL' signal has been connected. It can be : | ||
229 | |||
230 | 0 : no connection (eg: connected to ground) | ||
231 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
232 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
233 | |||
234 | Default for the 'SCL' pin in custom profile is '1' (STROBE). | ||
235 | |||
236 | config PANEL_LCD_PIN_SDA | ||
237 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" | ||
238 | int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) " | ||
239 | range -17 17 | ||
240 | default 2 | ||
241 | ---help--- | ||
242 | This describes the number of the parallel port pin to which the serial | ||
243 | LCD 'SDA' signal has been connected. It can be : | ||
244 | |||
245 | 0 : no connection (eg: connected to ground) | ||
246 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
247 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
248 | |||
249 | Default for the 'SDA' pin in custom profile is '2' (D0). | ||
250 | |||
251 | config PANEL_LCD_PIN_BL | ||
252 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | ||
253 | int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) " | ||
254 | range -17 17 | ||
255 | default 0 | ||
256 | ---help--- | ||
257 | This describes the number of the parallel port pin to which the LCD 'BL' signal | ||
258 | has been connected. It can be : | ||
259 | |||
260 | 0 : no connection (eg: connected to ground) | ||
261 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
262 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
263 | |||
264 | Default for the 'BL' pin in custom profile is '0' (uncontrolled). | ||
265 | |||
266 | config PANEL_CHANGE_MESSAGE | ||
267 | depends on PANEL | ||
268 | bool "Change LCD initialization message ?" | ||
269 | default "n" | ||
270 | ---help--- | ||
271 | This allows you to replace the boot message indicating the kernel version | ||
272 | and the driver version with a custom message. This is useful on appliances | ||
273 | where a simple 'Starting system' message can be enough to stop a customer | ||
274 | from worrying. | ||
275 | |||
276 | If you say 'Y' here, you'll be able to choose a message yourself. Otherwise, | ||
277 | say 'N' and keep the default message with the version. | ||
278 | |||
279 | config PANEL_BOOT_MESSAGE | ||
280 | depends on PANEL && PANEL_CHANGE_MESSAGE="y" | ||
281 | string "New initialization message" | ||
282 | default "" | ||
283 | ---help--- | ||
284 | This allows you to replace the boot message indicating the kernel version | ||
285 | and the driver version with a custom message. This is useful on appliances | ||
286 | where a simple 'Starting system' message can be enough to stop a customer | ||
287 | from worrying. | ||
288 | |||
289 | An empty message will only clear the display at driver init time. Any other | ||
290 | printf()-formatted message is valid with newline and escape codes. | ||
diff --git a/drivers/staging/panel/Makefile b/drivers/staging/panel/Makefile new file mode 100644 index 000000000000..747c238b82f9 --- /dev/null +++ b/drivers/staging/panel/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_PANEL) += panel.o | |||
diff --git a/drivers/staging/panel/TODO b/drivers/staging/panel/TODO new file mode 100644 index 000000000000..a4be749bcdfc --- /dev/null +++ b/drivers/staging/panel/TODO | |||
@@ -0,0 +1,9 @@ | |||
1 | TODO: | ||
2 | - checkpatch.pl cleanups | ||
3 | - Lindent | ||
4 | - review major/minor usages | ||
5 | - review userspace api | ||
6 | - see if all of this could be easier done in userspace instead. | ||
7 | |||
8 | Please send patches to Greg Kroah-Hartman <greg@kroah.com> and | ||
9 | Willy Tarreau <willy@meta-x.org> | ||
diff --git a/drivers/staging/panel/lcd-panel-cgram.txt b/drivers/staging/panel/lcd-panel-cgram.txt new file mode 100644 index 000000000000..f9ceef4322a3 --- /dev/null +++ b/drivers/staging/panel/lcd-panel-cgram.txt | |||
@@ -0,0 +1,24 @@ | |||
1 | Some LCDs allow you to define up to 8 characters, mapped to ASCII | ||
2 | characters 0 to 7. The escape code to define a new character is | ||
3 | '\e[LG' followed by one digit from 0 to 7, representing the character | ||
4 | number, and up to 8 couples of hex digits terminated by a semi-colon | ||
5 | (';'). Each couple of digits represents a line, with 1-bits for each | ||
6 | illuminated pixel with LSB on the right. Lines are numberred from the | ||
7 | top of the character to the bottom. On a 5x7 matrix, only the 5 lower | ||
8 | bits of the 7 first bytes are used for each character. If the string | ||
9 | is incomplete, only complete lines will be redefined. Here are some | ||
10 | examples : | ||
11 | |||
12 | printf "\e[LG0010101050D1F0C04;" => 0 = [enter] | ||
13 | printf "\e[LG1040E1F0000000000;" => 1 = [up] | ||
14 | printf "\e[LG2000000001F0E0400;" => 2 = [down] | ||
15 | printf "\e[LG3040E1F001F0E0400;" => 3 = [up-down] | ||
16 | printf "\e[LG40002060E1E0E0602;" => 4 = [left] | ||
17 | printf "\e[LG500080C0E0F0E0C08;" => 5 = [right] | ||
18 | printf "\e[LG60016051516141400;" => 6 = "IP" | ||
19 | |||
20 | printf "\e[LG00103071F1F070301;" => big speaker | ||
21 | printf "\e[LG00002061E1E060200;" => small speaker | ||
22 | |||
23 | Willy | ||
24 | |||
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c new file mode 100644 index 000000000000..e021f5c4e079 --- /dev/null +++ b/drivers/staging/panel/panel.c | |||
@@ -0,0 +1,2343 @@ | |||
1 | /* | ||
2 | * Front panel driver for Linux - 20000810 - Willy Tarreau - willy@meta-x.org. | ||
3 | * It includes and LCD display (/dev/lcd), a 4-key keypad (/dev/keypad), and a | ||
4 | * smart card reader (/dev/smartcard). | ||
5 | * | ||
6 | * Updates for this driver may be found here : | ||
7 | * | ||
8 | * http://w.ods.org/linux/kernel/lcdpanel/ | ||
9 | * | ||
10 | * the driver skeleton has been stolen from nvram.c which was clearly written. | ||
11 | * | ||
12 | * Changes: | ||
13 | * 2000/08/10 | ||
14 | * - keypad now scrolls LCD when not opened | ||
15 | * - released 0.5.1 | ||
16 | * 2000/08/10 | ||
17 | * - bug fixes | ||
18 | * - released 0.5.2 | ||
19 | * 2000/08/10 | ||
20 | * - Reposition LCD when opening /dev/keypad (WIP) | ||
21 | * - Released 0.5.3 | ||
22 | * 2001/02/04 | ||
23 | * - Start of port to kernel 2.4.1 | ||
24 | * 2001/03/11 | ||
25 | * - implementation of a 24-key keyboard scanner with less electronics | ||
26 | * around, thus allowing to release the IRQ line. | ||
27 | * 2001/03/25 | ||
28 | * - the driver now compiles and works with both 2.4.2 and 2.2.18 kernels | ||
29 | * 2001/04/22 | ||
30 | * - implementation of KS0074-based serial LCD (load with lcd_enabled=2 and lcd_hwidth=16) | ||
31 | * 2001/04/29 | ||
32 | * - added back-light support, released 0.7.1 | ||
33 | * 2001/05/01 | ||
34 | * - added charset conversion table for ks0074, released 0.7.2 | ||
35 | * 2001/05/08 | ||
36 | * - start of rewriting towards v0.8 | ||
37 | * 2001/10/21 | ||
38 | * - replaced linux/malloc.h with linux/slab.h to be 2.4 compliant | ||
39 | * - definition of the multi-layer input system with its naming scheme | ||
40 | * - profile support for simplified configuration | ||
41 | * 2001/10/28 | ||
42 | * - smartcard now works for telecards. /dev/smartcard returns the card serial number | ||
43 | * 2001/11/10 | ||
44 | * - fix too short sleep for lcd_clear | ||
45 | * 2004/05/09 | ||
46 | * - add support for hantronix LCD modules (RS on SELECTIN instead of AUTOLF) | ||
47 | * (load with lcd_enabled=3 or profile=3) | ||
48 | * 2004/06/04 | ||
49 | * - changed all parallel LCD functions to be more generic. Now any | ||
50 | * connection of control signal is allowed with lcd_*_pin. | ||
51 | * 2004/07/23 | ||
52 | * - cleaned up some code | ||
53 | * - added support for keypads with inverted inputs | ||
54 | * - added support for Nexcom's LCD/Keypad on profile 4 | ||
55 | * - added character generator for chars 0-7 : "\e[LG{0-7}{8*2 hexdigits};" | ||
56 | * 2004/07/29 : 0.9.0 | ||
57 | * - deprecated lcd_enabled and keypad_enabled in profit of *_type | ||
58 | * - changed configuration so that the user can choose everything at | ||
59 | * kernel compilation time | ||
60 | * 2004/07/31 : 0.9.2 | ||
61 | * - fixed a stupid copy-paste bug affecting only the serial LCD | ||
62 | * - moved display geometries to lcd_init() to avoid problems with custom profiles. | ||
63 | * 2004/08/06 : 0.9.3 | ||
64 | * - added a system notifier callback to print the system state on the LCD | ||
65 | * during reboots or halts. | ||
66 | * | ||
67 | * 2005/05/20 : 0.9.4 | ||
68 | * - first working port on kernel 2.6 | ||
69 | * | ||
70 | * 2006/12/18 : 0.9.5 | ||
71 | * - fixed a long standing bug in 2.6 causing panics during reboot/kexec | ||
72 | * if the LCD was enabled but not initialized due to lack of parport. | ||
73 | * | ||
74 | * FIXME: | ||
75 | * - the initialization/deinitialization process is very dirty and should | ||
76 | * be rewritten. It may even be buggy. | ||
77 | * | ||
78 | * TODO: | ||
79 | * - document 24 keys keyboard (3 rows of 8 cols, 32 diodes + 2 inputs) | ||
80 | * - make the LCD a part of a virtual screen of Vx*Vy | ||
81 | * - make the inputs list smp-safe | ||
82 | * - change the keyboard to a double mapping : signals -> key_id -> values | ||
83 | * so that applications can change values without knowing signals | ||
84 | * | ||
85 | */ | ||
86 | |||
87 | #include <linux/module.h> | ||
88 | |||
89 | #include <linux/types.h> | ||
90 | #include <linux/errno.h> | ||
91 | #include <linux/signal.h> | ||
92 | #include <linux/sched.h> | ||
93 | #include <linux/spinlock.h> | ||
94 | #include <linux/smp_lock.h> | ||
95 | #include <linux/interrupt.h> | ||
96 | #include <linux/miscdevice.h> | ||
97 | #include <linux/slab.h> // previously <linux/malloc.h> | ||
98 | #include <linux/ioport.h> | ||
99 | #include <linux/fcntl.h> | ||
100 | #include <linux/init.h> | ||
101 | #include <linux/delay.h> | ||
102 | #include <linux/ctype.h> | ||
103 | #include <linux/parport.h> | ||
104 | #include <linux/version.h> | ||
105 | #include <linux/list.h> | ||
106 | #include <linux/notifier.h> | ||
107 | #include <linux/reboot.h> | ||
108 | #include <linux/utsrelease.h> | ||
109 | |||
110 | #include <asm/io.h> | ||
111 | #include <asm/uaccess.h> | ||
112 | #include <asm/system.h> | ||
113 | |||
114 | /* smartcard length */ | ||
115 | #define SMARTCARD_BYTES 64 | ||
116 | #define LCD_MINOR 156 | ||
117 | #define KEYPAD_MINOR 185 | ||
118 | #define SMARTCARD_MINOR 186 | ||
119 | |||
120 | #define PANEL_VERSION "0.9.5" | ||
121 | |||
122 | #define LCD_MAXBYTES 256 /* max burst write */ | ||
123 | |||
124 | #define SMARTCARD_LOGICAL_DETECTOR "S6" /* D6 wired to SELECT = card inserted */ | ||
125 | |||
126 | #define KEYPAD_BUFFER 64 | ||
127 | #define INPUT_POLL_TIME (HZ/50) /* poll the keyboard this every second */ | ||
128 | #define KEYPAD_REP_START (10) /* a key starts to repeat after this times INPUT_POLL_TIME */ | ||
129 | #define KEYPAD_REP_DELAY (2) /* a key repeats this times INPUT_POLL_TIME */ | ||
130 | |||
131 | #define FLASH_LIGHT_TEMPO (200) /* keep the light on this times INPUT_POLL_TIME for each flash */ | ||
132 | |||
133 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ | ||
134 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) | ||
135 | |||
136 | #define PNL_PBUSY 0x80 /* inverted input, active low */ | ||
137 | #define PNL_PACK 0x40 /* direct input, active low */ | ||
138 | #define PNL_POUTPA 0x20 /* direct input, active high */ | ||
139 | #define PNL_PSELECD 0x10 /* direct input, active high */ | ||
140 | #define PNL_PERRORP 0x08 /* direct input, active low */ | ||
141 | |||
142 | #define PNL_PBIDIR 0x20 /* bi-directional ports */ | ||
143 | #define PNL_PINTEN 0x10 /* high to read data in or-ed with data out */ | ||
144 | #define PNL_PSELECP 0x08 /* inverted output, active low */ | ||
145 | #define PNL_PINITP 0x04 /* direct output, active low */ | ||
146 | #define PNL_PAUTOLF 0x02 /* inverted output, active low */ | ||
147 | #define PNL_PSTROBE 0x01 /* inverted output */ | ||
148 | |||
149 | #define PNL_PD0 0x01 | ||
150 | #define PNL_PD1 0x02 | ||
151 | #define PNL_PD2 0x04 | ||
152 | #define PNL_PD3 0x08 | ||
153 | #define PNL_PD4 0x10 | ||
154 | #define PNL_PD5 0x20 | ||
155 | #define PNL_PD6 0x40 | ||
156 | #define PNL_PD7 0x80 | ||
157 | |||
158 | #define PIN_NONE 0 | ||
159 | #define PIN_STROBE 1 | ||
160 | #define PIN_D0 2 | ||
161 | #define PIN_D1 3 | ||
162 | #define PIN_D2 4 | ||
163 | #define PIN_D3 5 | ||
164 | #define PIN_D4 6 | ||
165 | #define PIN_D5 7 | ||
166 | #define PIN_D6 8 | ||
167 | #define PIN_D7 9 | ||
168 | #define PIN_AUTOLF 14 | ||
169 | #define PIN_INITP 16 | ||
170 | #define PIN_SELECP 17 | ||
171 | #define PIN_NOT_SET 127 | ||
172 | |||
173 | /* some smartcard-specific signals */ | ||
174 | #define PNL_SC_IO PNL_PD1 /* Warning! inverted output, 0=highZ */ | ||
175 | #define PNL_SC_RST PNL_PD2 | ||
176 | #define PNL_SC_CLK PNL_PD3 | ||
177 | #define PNL_SC_RW PNL_PD4 | ||
178 | #define PNL_SC_ENA PNL_PINITP | ||
179 | #define PNL_SC_IOR PNL_PACK | ||
180 | #define PNL_SC_BITS (PNL_SC_IO | PNL_SC_RST | PNL_SC_CLK | PNL_SC_RW) | ||
181 | |||
182 | #define LCD_FLAG_S 0x0001 | ||
183 | #define LCD_FLAG_ID 0x0002 | ||
184 | #define LCD_FLAG_B 0x0004 /* blink on */ | ||
185 | #define LCD_FLAG_C 0x0008 /* cursor on */ | ||
186 | #define LCD_FLAG_D 0x0010 /* display on */ | ||
187 | #define LCD_FLAG_F 0x0020 /* large font mode */ | ||
188 | #define LCD_FLAG_N 0x0040 /* 2-rows mode */ | ||
189 | #define LCD_FLAG_L 0x0080 /* backlight enabled */ | ||
190 | |||
191 | #define LCD_ESCAPE_LEN 24 /* 24 chars max for an LCD escape command */ | ||
192 | #define LCD_ESCAPE_CHAR 27 /* use char 27 for escape command */ | ||
193 | |||
194 | /* macros to simplify use of the parallel port */ | ||
195 | #define r_ctr(x) (parport_read_control((x)->port)) | ||
196 | #define r_dtr(x) (parport_read_data((x)->port)) | ||
197 | #define r_str(x) (parport_read_status((x)->port)) | ||
198 | #define w_ctr(x,y) do { parport_write_control((x)->port, (y)); } while (0) | ||
199 | #define w_dtr(x,y) do { parport_write_data((x)->port, (y)); } while (0) | ||
200 | |||
201 | /* this defines which bits are to be used and which ones to be ignored */ | ||
202 | static __u8 scan_mask_o = 0; /* logical or of the output bits involved in the scan matrix */ | ||
203 | static __u8 scan_mask_i = 0; /* logical or of the input bits involved in the scan matrix */ | ||
204 | |||
205 | typedef __u64 pmask_t; | ||
206 | |||
207 | enum input_type { | ||
208 | INPUT_TYPE_STD, | ||
209 | INPUT_TYPE_KBD, | ||
210 | }; | ||
211 | |||
212 | enum input_state { | ||
213 | INPUT_ST_LOW, | ||
214 | INPUT_ST_RISING, | ||
215 | INPUT_ST_HIGH, | ||
216 | INPUT_ST_FALLING, | ||
217 | }; | ||
218 | |||
219 | struct logical_input { | ||
220 | struct list_head list; | ||
221 | pmask_t mask; | ||
222 | pmask_t value; | ||
223 | enum input_type type; | ||
224 | enum input_state state; | ||
225 | __u8 rise_time, fall_time; | ||
226 | __u8 rise_timer, fall_timer, high_timer; | ||
227 | |||
228 | union { | ||
229 | struct { /* this structure is valid when type == INPUT_TYPE_STD */ | ||
230 | void(*press_fct)(int); | ||
231 | void(*release_fct)(int); | ||
232 | int press_data; | ||
233 | int release_data; | ||
234 | } std; | ||
235 | struct { /* this structure is valid when type == INPUT_TYPE_KBD */ | ||
236 | /* strings can be full-length (ie. non null-terminated) */ | ||
237 | char press_str[sizeof(void *) + sizeof (int)]; | ||
238 | char repeat_str[sizeof(void *) + sizeof (int)]; | ||
239 | char release_str[sizeof(void *) + sizeof (int)]; | ||
240 | } kbd; | ||
241 | } u; | ||
242 | }; | ||
243 | |||
244 | LIST_HEAD(logical_inputs); /* list of all defined logical inputs */ | ||
245 | |||
246 | /* physical contacts history | ||
247 | * Physical contacts are a 45 bits string of 9 groups of 5 bits each. | ||
248 | * The 8 lower groups correspond to output bits 0 to 7, and the 9th group | ||
249 | * corresponds to the ground. | ||
250 | * Within each group, bits are stored in the same order as read on the port : | ||
251 | * BAPSE (busy=4, ack=3, paper empty=2, select=1, error=0). | ||
252 | * So, each __u64 (or pmask_t) is represented like this : | ||
253 | * 0000000000000000000BAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSE | ||
254 | * <-----unused------><gnd><d07><d06><d05><d04><d03><d02><d01><d00> | ||
255 | */ | ||
256 | static pmask_t phys_read; /* what has just been read from the I/O ports */ | ||
257 | static pmask_t phys_read_prev; /* previous phys_read */ | ||
258 | static pmask_t phys_curr; /* stabilized phys_read (phys_read|phys_read_prev) */ | ||
259 | static pmask_t phys_prev; /* previous phys_curr */ | ||
260 | static char inputs_stable = 0; /* 0 means that at least one logical signal needs be computed */ | ||
261 | |||
262 | /* these variables are specific to the smartcard */ | ||
263 | static __u8 smartcard_data[SMARTCARD_BYTES]; | ||
264 | static int smartcard_ptr = 0; /* pointer to half bytes in smartcard_data */ | ||
265 | |||
266 | /* these variables are specific to the keypad */ | ||
267 | static char keypad_buffer[KEYPAD_BUFFER]; | ||
268 | static int keypad_buflen = 0; | ||
269 | static int keypad_start = 0; | ||
270 | static char keypressed = 0; | ||
271 | static wait_queue_head_t keypad_read_wait; | ||
272 | static wait_queue_head_t smartcard_read_wait; | ||
273 | |||
274 | /* lcd-specific variables */ | ||
275 | static unsigned long int lcd_flags = 0; /* contains the LCD config state */ | ||
276 | static unsigned long int lcd_addr_x = 0; /* contains the LCD X offset */ | ||
277 | static unsigned long int lcd_addr_y = 0; /* contains the LCD Y offset */ | ||
278 | static char lcd_escape[LCD_ESCAPE_LEN+1]; /* current escape sequence, 0 terminated */ | ||
279 | static int lcd_escape_len = -1; /* not in escape state. >=0 = escape cmd len */ | ||
280 | |||
281 | static int lcd_height = -1; | ||
282 | static int lcd_width = -1; | ||
283 | static int lcd_hwidth = -1; /* hardware buffer width (usually 64) */ | ||
284 | static int lcd_bwidth = -1; /* internal buffer width (usually 40) */ | ||
285 | |||
286 | /* | ||
287 | * These are the parallel port pins the LCD control signals are connected to. | ||
288 | * Set this to 0 if the signal is not used. Set it to its opposite value | ||
289 | * (negative) if the signal is negated. -MAXINT is used to indicate that the | ||
290 | * pin has not been explicitly specified. | ||
291 | * | ||
292 | * WARNING! no check will be performed about collisions with keypad/smartcard ! | ||
293 | */ | ||
294 | static int lcd_e_pin = PIN_NOT_SET; | ||
295 | static int lcd_rs_pin = PIN_NOT_SET; | ||
296 | static int lcd_rw_pin = PIN_NOT_SET; | ||
297 | static int lcd_bl_pin = PIN_NOT_SET; | ||
298 | static int lcd_cl_pin = PIN_NOT_SET; | ||
299 | static int lcd_da_pin = PIN_NOT_SET; | ||
300 | |||
301 | /* | ||
302 | * Bit masks to convert LCD signals to parallel port outputs. | ||
303 | * _d_ are values for data port, _c_ are for control port. | ||
304 | * [0] = signal OFF, [1] = signal ON, [2] = mask | ||
305 | */ | ||
306 | #define BIT_CLR 0 | ||
307 | #define BIT_SET 1 | ||
308 | #define BIT_MSK 2 | ||
309 | #define BIT_STATES 3 | ||
310 | /* | ||
311 | * one entry for each bit on the LCD | ||
312 | */ | ||
313 | #define LCD_BIT_E 0 | ||
314 | #define LCD_BIT_RS 1 | ||
315 | #define LCD_BIT_RW 2 | ||
316 | #define LCD_BIT_BL 3 | ||
317 | #define LCD_BIT_CL 4 | ||
318 | #define LCD_BIT_DA 5 | ||
319 | #define LCD_BITS 6 | ||
320 | |||
321 | /* | ||
322 | * each bit can be either connected to a DATA or CTRL port | ||
323 | */ | ||
324 | #define LCD_PORT_C 0 | ||
325 | #define LCD_PORT_D 1 | ||
326 | #define LCD_PORTS 2 | ||
327 | |||
328 | static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES]; | ||
329 | |||
330 | /* | ||
331 | * LCD protocols | ||
332 | */ | ||
333 | #define LCD_PROTO_PARALLEL 0 | ||
334 | #define LCD_PROTO_SERIAL 1 | ||
335 | |||
336 | /* | ||
337 | * LCD character sets | ||
338 | */ | ||
339 | #define LCD_CHARSET_NORMAL 0 | ||
340 | #define LCD_CHARSET_KS0074 1 | ||
341 | |||
342 | /* | ||
343 | * LCD types | ||
344 | */ | ||
345 | #define LCD_TYPE_NONE 0 | ||
346 | #define LCD_TYPE_OLD 1 | ||
347 | #define LCD_TYPE_KS0074 2 | ||
348 | #define LCD_TYPE_HANTRONIX 3 | ||
349 | #define LCD_TYPE_NEXCOM 4 | ||
350 | #define LCD_TYPE_CUSTOM 5 | ||
351 | |||
352 | /* | ||
353 | * keypad types | ||
354 | */ | ||
355 | #define KEYPAD_TYPE_NONE 0 | ||
356 | #define KEYPAD_TYPE_OLD 1 | ||
357 | #define KEYPAD_TYPE_NEW 2 | ||
358 | #define KEYPAD_TYPE_NEXCOM 3 | ||
359 | |||
360 | /* | ||
361 | * panel profiles | ||
362 | */ | ||
363 | #define PANEL_PROFILE_CUSTOM 0 | ||
364 | #define PANEL_PROFILE_OLD 1 | ||
365 | #define PANEL_PROFILE_NEW 2 | ||
366 | #define PANEL_PROFILE_HANTRONIX 3 | ||
367 | #define PANEL_PROFILE_NEXCOM 4 | ||
368 | #define PANEL_PROFILE_LARGE 5 | ||
369 | |||
370 | /* | ||
371 | * Construct custom config from the kernel's configuration | ||
372 | */ | ||
373 | #define DEFAULT_PROFILE PANEL_PROFILE_LARGE | ||
374 | #define DEFAULT_PARPORT 0 | ||
375 | #define DEFAULT_LCD LCD_TYPE_OLD | ||
376 | #define DEFAULT_KEYPAD KEYPAD_TYPE_OLD | ||
377 | #define DEFAULT_SMARTCARD 0 | ||
378 | #define DEFAULT_LCD_WIDTH 40 | ||
379 | #define DEFAULT_LCD_BWIDTH 40 | ||
380 | #define DEFAULT_LCD_HWIDTH 64 | ||
381 | #define DEFAULT_LCD_HEIGHT 2 | ||
382 | #define DEFAULT_LCD_PROTO LCD_PROTO_PARALLEL | ||
383 | |||
384 | #define DEFAULT_LCD_PIN_E PIN_AUTOLF | ||
385 | #define DEFAULT_LCD_PIN_RS PIN_SELECP | ||
386 | #define DEFAULT_LCD_PIN_RW PIN_INITP | ||
387 | #define DEFAULT_LCD_PIN_SCL PIN_STROBE | ||
388 | #define DEFAULT_LCD_PIN_SDA PIN_D0 | ||
389 | #define DEFAULT_LCD_PIN_BL PIN_NOT_SET | ||
390 | #define DEFAULT_LCD_CHARSET LCD_CHARSET_NORMAL | ||
391 | |||
392 | #ifdef CONFIG_PANEL_PROFILE | ||
393 | #undef DEFAULT_PROFILE | ||
394 | #define DEFAULT_PROFILE CONFIG_PANEL_PROFILE | ||
395 | #endif | ||
396 | |||
397 | #ifdef CONFIG_PANEL_PARPORT | ||
398 | #undef DEFAULT_PARPORT | ||
399 | #define DEFAULT_PARPORT CONFIG_PANEL_PARPORT | ||
400 | #endif | ||
401 | |||
402 | #if DEFAULT_PROFILE==0 /* custom */ | ||
403 | #ifdef CONFIG_PANEL_KEYPAD | ||
404 | #undef DEFAULT_KEYPAD | ||
405 | #define DEFAULT_KEYPAD CONFIG_PANEL_KEYPAD | ||
406 | #endif | ||
407 | |||
408 | #ifdef CONFIG_PANEL_SMARTCARD | ||
409 | #undef DEFAULT_SMARTCARD | ||
410 | #define DEFAULT_SMARTCARD 1 | ||
411 | #endif | ||
412 | |||
413 | #ifdef CONFIG_PANEL_LCD | ||
414 | #undef DEFAULT_LCD | ||
415 | #define DEFAULT_LCD CONFIG_PANEL_LCD | ||
416 | #endif | ||
417 | |||
418 | #ifdef CONFIG_PANEL_LCD_WIDTH | ||
419 | #undef DEFAULT_LCD_WIDTH | ||
420 | #define DEFAULT_LCD_WIDTH CONFIG_PANEL_LCD_WIDTH | ||
421 | #endif | ||
422 | |||
423 | #ifdef CONFIG_PANEL_LCD_BWIDTH | ||
424 | #undef DEFAULT_LCD_BWIDTH | ||
425 | #define DEFAULT_LCD_BWIDTH CONFIG_PANEL_LCD_BWIDTH | ||
426 | #endif | ||
427 | |||
428 | #ifdef CONFIG_PANEL_LCD_HWIDTH | ||
429 | #undef DEFAULT_LCD_HWIDTH | ||
430 | #define DEFAULT_LCD_HWIDTH CONFIG_PANEL_LCD_HWIDTH | ||
431 | #endif | ||
432 | |||
433 | #ifdef CONFIG_PANEL_LCD_HEIGHT | ||
434 | #undef DEFAULT_LCD_HEIGHT | ||
435 | #define DEFAULT_LCD_HEIGHT CONFIG_PANEL_LCD_HEIGHT | ||
436 | #endif | ||
437 | |||
438 | #ifdef CONFIG_PANEL_LCD_PROTO | ||
439 | #undef DEFAULT_LCD_PROTO | ||
440 | #define DEFAULT_LCD_PROTO CONFIG_PANEL_LCD_PROTO | ||
441 | #endif | ||
442 | |||
443 | #ifdef CONFIG_PANEL_LCD_PIN_E | ||
444 | #undef DEFAULT_LCD_PIN_E | ||
445 | #define DEFAULT_LCD_PIN_E CONFIG_PANEL_LCD_PIN_E | ||
446 | #endif | ||
447 | |||
448 | #ifdef CONFIG_PANEL_LCD_PIN_RS | ||
449 | #undef DEFAULT_LCD_PIN_RS | ||
450 | #define DEFAULT_LCD_PIN_RS CONFIG_PANEL_LCD_PIN_RS | ||
451 | #endif | ||
452 | |||
453 | #ifdef CONFIG_PANEL_LCD_PIN_RW | ||
454 | #undef DEFAULT_LCD_PIN_RW | ||
455 | #define DEFAULT_LCD_PIN_RW CONFIG_PANEL_LCD_PIN_RW | ||
456 | #endif | ||
457 | |||
458 | #ifdef CONFIG_PANEL_LCD_PIN_SCL | ||
459 | #undef DEFAULT_LCD_PIN_SCL | ||
460 | #define DEFAULT_LCD_PIN_SCL CONFIG_PANEL_LCD_PIN_SCL | ||
461 | #endif | ||
462 | |||
463 | #ifdef CONFIG_PANEL_LCD_PIN_SDA | ||
464 | #undef DEFAULT_LCD_PIN_SDA | ||
465 | #define DEFAULT_LCD_PIN_SDA CONFIG_PANEL_LCD_PIN_SDA | ||
466 | #endif | ||
467 | |||
468 | #ifdef CONFIG_PANEL_LCD_PIN_BL | ||
469 | #undef DEFAULT_LCD_PIN_BL | ||
470 | #define DEFAULT_LCD_PIN_BL CONFIG_PANEL_LCD_PIN_BL | ||
471 | #endif | ||
472 | |||
473 | #ifdef CONFIG_PANEL_LCD_CHARSET | ||
474 | #undef DEFAULT_LCD_CHARSET | ||
475 | #define DEFAULT_LCD_CHARSET | ||
476 | #endif | ||
477 | |||
478 | #endif /* DEFAULT_PROFILE == 0 */ | ||
479 | |||
480 | /* global variables */ | ||
481 | static int smartcard_open_cnt = 0; /* #times opened */ | ||
482 | static int keypad_open_cnt = 0; /* #times opened */ | ||
483 | static int lcd_open_cnt = 0; /* #times opened */ | ||
484 | |||
485 | static int profile = DEFAULT_PROFILE; | ||
486 | static struct pardevice *pprt = NULL; | ||
487 | static int parport = -1; | ||
488 | static int lcd_enabled = -1; | ||
489 | static int lcd_type = -1; | ||
490 | static int lcd_proto = -1; | ||
491 | static int lcd_charset = -1; | ||
492 | static int keypad_enabled = -1; | ||
493 | static int keypad_type = -1; | ||
494 | static int smartcard_enabled = -1; | ||
495 | |||
496 | static int lcd_initialized, keypad_initialized, smartcard_initialized; | ||
497 | |||
498 | static int light_tempo = 0; | ||
499 | |||
500 | static char lcd_must_clear = 0; | ||
501 | static char lcd_left_shift = 0; | ||
502 | static char init_in_progress = 0; | ||
503 | |||
504 | static void(*lcd_write_cmd)(int) = NULL; | ||
505 | static void(*lcd_write_data)(int) = NULL; | ||
506 | static void(*lcd_clear_fast)(void) = NULL; | ||
507 | |||
508 | static spinlock_t pprt_lock = SPIN_LOCK_UNLOCKED; | ||
509 | static struct timer_list scan_timer; | ||
510 | |||
511 | #ifdef MODULE | ||
512 | |||
513 | MODULE_DESCRIPTION("Generic parallel port LCD/Keypad/Smartcard driver"); | ||
514 | module_param(parport, int, 0000);MODULE_PARM_DESC(parport, "Parallel port index (0=lpt1, 1=lpt2, ...)"); | ||
515 | module_param(lcd_height, int, 0000);MODULE_PARM_DESC(lcd_height, "Number of lines on the LCD"); | ||
516 | module_param(lcd_width, int, 0000);MODULE_PARM_DESC(lcd_width, "Number of columns on the LCD"); | ||
517 | module_param(lcd_bwidth, int, 0000);MODULE_PARM_DESC(lcd_bwidth, "Internal LCD line width (40)"); | ||
518 | module_param(lcd_hwidth, int, 0000);MODULE_PARM_DESC(lcd_hwidth, "LCD line hardware address (64)"); | ||
519 | module_param(lcd_enabled, int, 0000);MODULE_PARM_DESC(lcd_enabled, "Deprecated option, use lcd_type instead"); | ||
520 | module_param(keypad_enabled, int, 0000);MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead"); | ||
521 | module_param(lcd_type, int, 0000);MODULE_PARM_DESC(lcd_type, "LCD type: 0=none, 1=old //, 2=serial ks0074, 3=hantronix //, 4=nexcom //, 5=compiled-in"); | ||
522 | module_param(lcd_proto, int, 0000);MODULE_PARM_DESC(lcd_proto, "LCD communication: 0=parallel (//), 1=serial"); | ||
523 | module_param(lcd_charset, int, 0000);MODULE_PARM_DESC(lcd_charset, "LCD character set: 0=standard, 1=KS0074"); | ||
524 | module_param(keypad_type, int, 0000);MODULE_PARM_DESC(keypad_type, "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, 3=nexcom 4 keys"); | ||
525 | module_param(smartcard_enabled, int, 0000);MODULE_PARM_DESC(smartcard_enabled, "Smartcard reader: 0=disabled (default), 1=enabled"); | ||
526 | module_param(profile, int, 0000); MODULE_PARM_DESC(profile, "1=16x2 old kp; 2=serial 16x2, new kp; 3=16x2 hantronix; 4=16x2 nexcom; default=40x2, old kp"); | ||
527 | |||
528 | module_param(lcd_e_pin, int, 0000); MODULE_PARM_DESC(lcd_e_pin, "# of the // port pin connected to LCD 'E' signal, with polarity (-17..17)"); | ||
529 | module_param(lcd_rs_pin, int, 0000);MODULE_PARM_DESC(lcd_rs_pin, "# of the // port pin connected to LCD 'RS' signal, with polarity (-17..17)"); | ||
530 | module_param(lcd_rw_pin, int, 0000);MODULE_PARM_DESC(lcd_rw_pin, "# of the // port pin connected to LCD 'RW' signal, with polarity (-17..17)"); | ||
531 | module_param(lcd_bl_pin, int, 0000);MODULE_PARM_DESC(lcd_bl_pin, "# of the // port pin connected to LCD backlight, with polarity (-17..17)"); | ||
532 | module_param(lcd_da_pin, int, 0000);MODULE_PARM_DESC(lcd_da_pin, "# of the // port pin connected to serial LCD 'SDA' signal, with polarity (-17..17)"); | ||
533 | module_param(lcd_cl_pin, int, 0000);MODULE_PARM_DESC(lcd_cl_pin, "# of the // port pin connected to serial LCD 'SCL' signal, with polarity (-17..17)"); | ||
534 | |||
535 | #endif | ||
536 | |||
537 | static unsigned char *lcd_char_conv = NULL; | ||
538 | |||
539 | /* for some LCD drivers (ks0074) we need a charset conversion table. */ | ||
540 | static unsigned char lcd_char_conv_ks0074[256] = { | ||
541 | /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ | ||
542 | /* 0x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | ||
543 | /* 0x10 */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | ||
544 | /* 0x20 */ 0x20, 0x21, 0x22, 0x23, 0xa2, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, | ||
545 | /* 0x30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, | ||
546 | /* 0x40 */ 0xa0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, | ||
547 | /* 0x50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0xfa, 0xfb, 0xfc, 0x1d, 0xc4, | ||
548 | /* 0x60 */ 0x96, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, | ||
549 | /* 0x70 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xfd, 0xfe, 0xff, 0xce, 0x20, | ||
550 | /* 0x80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, | ||
551 | /* 0x90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, | ||
552 | /* 0xA0 */ 0x20, 0x40, 0xb1, 0xa1, 0x24, 0xa3, 0xfe, 0x5f, 0x22, 0xc8, 0x61, 0x14, 0x97, 0x2d, 0xad, 0x96, | ||
553 | /* 0xB0 */ 0x80, 0x8c, 0x82, 0x83, 0x27, 0x8f, 0x86, 0xdd, 0x2c, 0x81, 0x6f, 0x15, 0x8b, 0x8a, 0x84, 0x60, | ||
554 | /* 0xC0 */ 0xe2, 0xe2, 0xe2, 0x5b, 0x5b, 0xae, 0xbc, 0xa9, 0xc5, 0xbf, 0xc6, 0xf1, 0xe3, 0xe3, 0xe3, 0xe3, | ||
555 | /* 0xD0 */ 0x44, 0x5d, 0xa8, 0xe4, 0xec, 0xec, 0x5c, 0x78, 0xab, 0xa6, 0xe5, 0x5e, 0x5e, 0xe6, 0xaa, 0xbe, | ||
556 | /* 0xE0 */ 0x7f, 0xe7, 0xaf, 0x7b, 0x7b, 0xaf, 0xbd, 0xc8, 0xa4, 0xa5, 0xc7, 0xf6, 0xa7, 0xe8, 0x69, 0x69, | ||
557 | /* 0xF0 */ 0xed, 0x7d, 0xa8, 0xe4, 0xec, 0x5c, 0x5c, 0x25, 0xac, 0xa6, 0xea, 0xef, 0x7e, 0xeb, 0xb2, 0x79, | ||
558 | }; | ||
559 | |||
560 | char old_keypad_profile[][4][9] = { | ||
561 | {"S0", "Left\n", "Left\n", ""}, | ||
562 | {"S1", "Down\n", "Down\n", ""}, | ||
563 | {"S2", "Up\n", "Up\n", ""}, | ||
564 | {"S3", "Right\n", "Right\n", ""}, | ||
565 | {"S4", "Esc\n", "Esc\n", ""}, | ||
566 | {"S5", "Ret\n", "Ret\n", ""}, | ||
567 | {"","","",""} | ||
568 | }; | ||
569 | |||
570 | /* signals, press, repeat, release */ | ||
571 | char new_keypad_profile[][4][9] = { | ||
572 | {"S0", "Left\n", "Left\n", ""}, | ||
573 | {"S1", "Down\n", "Down\n", ""}, | ||
574 | {"S2", "Up\n", "Up\n", ""}, | ||
575 | {"S3", "Right\n", "Right\n", ""}, | ||
576 | {"S4s5", "", "Esc\n", "Esc\n"}, | ||
577 | {"s4S5", "", "Ret\n", "Ret\n"}, | ||
578 | {"S4S5", "Help\n", "", ""}, | ||
579 | /* add new signals above this line */ | ||
580 | {"","","",""} | ||
581 | }; | ||
582 | |||
583 | /* signals, press, repeat, release */ | ||
584 | char nexcom_keypad_profile[][4][9] = { | ||
585 | {"a-p-e-", "Down\n", "Down\n", ""}, // Down | ||
586 | {"a-p-E-", "Ret\n", "Ret\n", ""}, // Enter | ||
587 | {"a-P-E-", "Esc\n", "Esc\n", ""}, // Esc | ||
588 | {"a-P-e-", "Up\n", "Up\n", ""}, // Up | ||
589 | /* add new signals above this line */ | ||
590 | {"","","",""} | ||
591 | }; | ||
592 | |||
593 | static char (*keypad_profile)[4][9] = old_keypad_profile; | ||
594 | |||
595 | /* FIXME: this should be converted to a bit array containing signals states */ | ||
596 | static struct { | ||
597 | unsigned char e; /* parallel LCD E (data latch on falling edge) */ | ||
598 | unsigned char rs; /* parallel LCD RS (0 = cmd, 1 = data) */ | ||
599 | unsigned char rw; /* parallel LCD R/W (0 = W, 1 = R) */ | ||
600 | unsigned char bl; /* parallel LCD backlight (0 = off, 1 = on) */ | ||
601 | unsigned char cl; /* serial LCD clock (latch on rising edge) */ | ||
602 | unsigned char da; /* serial LCD data */ | ||
603 | } bits; | ||
604 | |||
605 | static void init_scan_timer(void); | ||
606 | |||
607 | /* sets data port bits according to current signals values */ | ||
608 | static int set_data_bits(void) { | ||
609 | int val, bit; | ||
610 | |||
611 | val = r_dtr(pprt); | ||
612 | for (bit = 0; bit < LCD_BITS; bit++) | ||
613 | val &= lcd_bits[LCD_PORT_D][bit][BIT_MSK]; | ||
614 | |||
615 | val |= lcd_bits[LCD_PORT_D][LCD_BIT_E][bits.e] | ||
616 | | lcd_bits[LCD_PORT_D][LCD_BIT_RS][bits.rs] | ||
617 | | lcd_bits[LCD_PORT_D][LCD_BIT_RW][bits.rw] | ||
618 | | lcd_bits[LCD_PORT_D][LCD_BIT_BL][bits.bl] | ||
619 | | lcd_bits[LCD_PORT_D][LCD_BIT_CL][bits.cl] | ||
620 | | lcd_bits[LCD_PORT_D][LCD_BIT_DA][bits.da]; | ||
621 | |||
622 | w_dtr(pprt, val); | ||
623 | return val; | ||
624 | } | ||
625 | |||
626 | /* sets ctrl port bits according to current signals values */ | ||
627 | static int set_ctrl_bits(void) { | ||
628 | int val, bit; | ||
629 | |||
630 | val = r_ctr(pprt); | ||
631 | for (bit = 0; bit < LCD_BITS; bit++) | ||
632 | val &= lcd_bits[LCD_PORT_C][bit][BIT_MSK]; | ||
633 | |||
634 | val |= lcd_bits[LCD_PORT_C][LCD_BIT_E][bits.e] | ||
635 | | lcd_bits[LCD_PORT_C][LCD_BIT_RS][bits.rs] | ||
636 | | lcd_bits[LCD_PORT_C][LCD_BIT_RW][bits.rw] | ||
637 | | lcd_bits[LCD_PORT_C][LCD_BIT_BL][bits.bl] | ||
638 | | lcd_bits[LCD_PORT_C][LCD_BIT_CL][bits.cl] | ||
639 | | lcd_bits[LCD_PORT_C][LCD_BIT_DA][bits.da]; | ||
640 | |||
641 | w_ctr(pprt, val); | ||
642 | return val; | ||
643 | } | ||
644 | |||
645 | /* sets ctrl & data port bits according to current signals values */ | ||
646 | static void set_bits(void) { | ||
647 | set_data_bits(); | ||
648 | set_ctrl_bits(); | ||
649 | } | ||
650 | |||
651 | /* | ||
652 | * Converts a parallel port pin (from -25 to 25) to data and control ports | ||
653 | * masks, and data and control port bits. The signal will be considered | ||
654 | * unconnected if it's on pin 0 or an invalid pin (<-25 or >25). | ||
655 | * | ||
656 | * Result will be used this way : | ||
657 | * out(dport, in(dport) & d_val[2] | d_val[signal_state]) | ||
658 | * out(cport, in(cport) & c_val[2] | c_val[signal_state]) | ||
659 | */ | ||
660 | void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val) { | ||
661 | int d_bit, c_bit, inv; | ||
662 | |||
663 | d_val[0] = c_val[0] = d_val[1] = c_val[1] = 0; | ||
664 | d_val[2] = c_val[2] = 0xFF; | ||
665 | |||
666 | if (pin == 0) | ||
667 | return; | ||
668 | |||
669 | inv = (pin < 0); | ||
670 | if (inv) | ||
671 | pin = -pin; | ||
672 | |||
673 | d_bit = c_bit = 0; | ||
674 | |||
675 | switch (pin) { | ||
676 | case PIN_STROBE: /* strobe, inverted */ | ||
677 | c_bit = PNL_PSTROBE; | ||
678 | inv = !inv; | ||
679 | break; | ||
680 | case PIN_D0 ... PIN_D7: /* D0 - D7 = 2 - 9 */ | ||
681 | d_bit = 1 << (pin - 2); | ||
682 | break; | ||
683 | case PIN_AUTOLF: /* autofeed, inverted */ | ||
684 | c_bit = PNL_PAUTOLF; | ||
685 | inv = !inv; | ||
686 | break; | ||
687 | case PIN_INITP: /* init, direct */ | ||
688 | c_bit = PNL_PINITP; | ||
689 | break; | ||
690 | case PIN_SELECP: /* select_in, inverted */ | ||
691 | c_bit = PNL_PSELECP; | ||
692 | inv = !inv; | ||
693 | break; | ||
694 | default: /* unknown pin, ignore */ | ||
695 | break; | ||
696 | } | ||
697 | |||
698 | if (c_bit) { | ||
699 | c_val[2] &= ~c_bit; | ||
700 | c_val[!inv] = c_bit; | ||
701 | } else if (d_bit) { | ||
702 | d_val[2] &= ~d_bit; | ||
703 | d_val[!inv] = d_bit; | ||
704 | } | ||
705 | } | ||
706 | |||
707 | /* sleeps that many milliseconds with a reschedule */ | ||
708 | static void long_sleep(int ms) { | ||
709 | |||
710 | if (in_interrupt()) | ||
711 | mdelay(ms); | ||
712 | else { | ||
713 | current->state = TASK_INTERRUPTIBLE; | ||
714 | schedule_timeout((ms*HZ+999)/1000); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | |||
719 | /* send a serial byte to the LCD panel. The caller is responsible for locking if needed. */ | ||
720 | static void lcd_send_serial(int byte) { | ||
721 | int bit; | ||
722 | |||
723 | /* the data bit is set on D0, and the clock on STROBE. | ||
724 | * LCD reads D0 on STROBE's rising edge. | ||
725 | */ | ||
726 | for (bit = 0; bit < 8; bit++) { | ||
727 | bits.cl = BIT_CLR; /* CLK low */ | ||
728 | set_bits(); | ||
729 | bits.da = byte & 1; | ||
730 | set_bits(); | ||
731 | udelay(2); /* maintain the data during 2 us before CLK up */ | ||
732 | bits.cl = BIT_SET; /* CLK high */ | ||
733 | set_bits(); | ||
734 | udelay(1); /* maintain the strobe during 1 us */ | ||
735 | byte >>= 1; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | /* turn the backlight on or off */ | ||
740 | static void lcd_backlight(int on) { | ||
741 | if (lcd_bl_pin == PIN_NONE) | ||
742 | return; | ||
743 | |||
744 | /* The backlight is activated by seting the AUTOFEED line to +5V */ | ||
745 | spin_lock(&pprt_lock); | ||
746 | bits.bl = on; | ||
747 | set_bits(); | ||
748 | spin_unlock(&pprt_lock); | ||
749 | } | ||
750 | |||
751 | /* send a command to the LCD panel in serial mode */ | ||
752 | static void lcd_write_cmd_s(int cmd) { | ||
753 | spin_lock(&pprt_lock); | ||
754 | lcd_send_serial(0x1F); /* R/W=W, RS=0 */ | ||
755 | lcd_send_serial(cmd & 0x0F); | ||
756 | lcd_send_serial((cmd >> 4) & 0x0F); | ||
757 | udelay(40); /* the shortest command takes at least 40 us */ | ||
758 | spin_unlock(&pprt_lock); | ||
759 | } | ||
760 | |||
761 | /* send data to the LCD panel in serial mode */ | ||
762 | static void lcd_write_data_s(int data) { | ||
763 | spin_lock(&pprt_lock); | ||
764 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ | ||
765 | lcd_send_serial(data & 0x0F); | ||
766 | lcd_send_serial((data >> 4) & 0x0F); | ||
767 | udelay(40); /* the shortest data takes at least 40 us */ | ||
768 | spin_unlock(&pprt_lock); | ||
769 | } | ||
770 | |||
771 | /* send a command to the LCD panel in 8 bits parallel mode */ | ||
772 | static void lcd_write_cmd_p8(int cmd) { | ||
773 | spin_lock(&pprt_lock); | ||
774 | /* present the data to the data port */ | ||
775 | w_dtr(pprt, cmd); | ||
776 | udelay(20); /* maintain the data during 20 us before the strobe */ | ||
777 | |||
778 | bits.e = BIT_SET ; bits.rs = BIT_CLR ; bits.rw = BIT_CLR; | ||
779 | set_ctrl_bits(); | ||
780 | |||
781 | udelay(40); /* maintain the strobe during 40 us */ | ||
782 | |||
783 | bits.e = BIT_CLR; | ||
784 | set_ctrl_bits(); | ||
785 | |||
786 | udelay(120); /* the shortest command takes at least 120 us */ | ||
787 | spin_unlock(&pprt_lock); | ||
788 | } | ||
789 | |||
790 | /* send data to the LCD panel in 8 bits parallel mode */ | ||
791 | static void lcd_write_data_p8(int data) { | ||
792 | spin_lock(&pprt_lock); | ||
793 | /* present the data to the data port */ | ||
794 | w_dtr(pprt, data); | ||
795 | udelay(20); /* maintain the data during 20 us before the strobe */ | ||
796 | |||
797 | bits.e = BIT_SET ; bits.rs = BIT_SET ; bits.rw = BIT_CLR; | ||
798 | set_ctrl_bits(); | ||
799 | |||
800 | udelay(40); /* maintain the strobe during 40 us */ | ||
801 | |||
802 | bits.e = BIT_CLR; | ||
803 | set_ctrl_bits(); | ||
804 | |||
805 | udelay(45); /* the shortest data takes at least 45 us */ | ||
806 | spin_unlock(&pprt_lock); | ||
807 | } | ||
808 | |||
809 | static void lcd_gotoxy(void) { | ||
810 | lcd_write_cmd(0x80 /* set DDRAM address */ | ||
811 | | (lcd_addr_y ? lcd_hwidth : 0) | ||
812 | /* we force the cursor to stay at the end of the line if it wants to go farther */ | ||
813 | | ((lcd_addr_x < lcd_bwidth) ? lcd_addr_x & (lcd_hwidth-1) : lcd_bwidth - 1)); | ||
814 | } | ||
815 | |||
816 | static void lcd_print(char c) { | ||
817 | if (lcd_addr_x < lcd_bwidth) { | ||
818 | if (lcd_char_conv != NULL) | ||
819 | c = lcd_char_conv[(unsigned char)c]; | ||
820 | lcd_write_data(c); | ||
821 | lcd_addr_x++; | ||
822 | } | ||
823 | /* prevents the cursor from wrapping onto the next line */ | ||
824 | if (lcd_addr_x == lcd_bwidth) { | ||
825 | lcd_gotoxy(); | ||
826 | } | ||
827 | } | ||
828 | |||
829 | /* fills the display with spaces and resets X/Y */ | ||
830 | static void lcd_clear_fast_s(void) { | ||
831 | int pos; | ||
832 | lcd_addr_x = lcd_addr_y = 0; | ||
833 | lcd_gotoxy(); | ||
834 | |||
835 | spin_lock(&pprt_lock); | ||
836 | for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) { | ||
837 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ | ||
838 | lcd_send_serial(' ' & 0x0F); | ||
839 | lcd_send_serial((' ' >> 4) & 0x0F); | ||
840 | udelay(40); /* the shortest data takes at least 40 us */ | ||
841 | } | ||
842 | spin_unlock(&pprt_lock); | ||
843 | |||
844 | lcd_addr_x = lcd_addr_y = 0; | ||
845 | lcd_gotoxy(); | ||
846 | } | ||
847 | |||
848 | /* fills the display with spaces and resets X/Y */ | ||
849 | static void lcd_clear_fast_p8(void) { | ||
850 | int pos; | ||
851 | lcd_addr_x = lcd_addr_y = 0; | ||
852 | lcd_gotoxy(); | ||
853 | |||
854 | spin_lock(&pprt_lock); | ||
855 | for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) { | ||
856 | /* present the data to the data port */ | ||
857 | w_dtr(pprt, ' '); | ||
858 | udelay(20); /* maintain the data during 20 us before the strobe */ | ||
859 | |||
860 | bits.e = BIT_SET ; bits.rs = BIT_SET ; bits.rw = BIT_CLR; | ||
861 | set_ctrl_bits(); | ||
862 | |||
863 | udelay(40); /* maintain the strobe during 40 us */ | ||
864 | |||
865 | bits.e = BIT_CLR; | ||
866 | set_ctrl_bits(); | ||
867 | |||
868 | udelay(45); /* the shortest data takes at least 45 us */ | ||
869 | } | ||
870 | spin_unlock(&pprt_lock); | ||
871 | |||
872 | lcd_addr_x = lcd_addr_y = 0; | ||
873 | lcd_gotoxy(); | ||
874 | } | ||
875 | |||
876 | /* clears the display and resets X/Y */ | ||
877 | static void lcd_clear_display(void) { | ||
878 | lcd_write_cmd(0x01); /* clear display */ | ||
879 | lcd_addr_x = lcd_addr_y = 0; | ||
880 | /* we must wait a few milliseconds (15) */ | ||
881 | long_sleep(15); | ||
882 | } | ||
883 | |||
884 | static void lcd_init_display(void) { | ||
885 | |||
886 | lcd_flags = ((lcd_height > 1) ? LCD_FLAG_N : 0) | ||
887 | | LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B; | ||
888 | |||
889 | long_sleep(20); /* wait 20 ms after power-up for the paranoid */ | ||
890 | |||
891 | lcd_write_cmd(0x30); /* 8bits, 1 line, small fonts */ | ||
892 | long_sleep(10); | ||
893 | lcd_write_cmd(0x30); /* 8bits, 1 line, small fonts */ | ||
894 | long_sleep(10); | ||
895 | lcd_write_cmd(0x30); /* 8bits, 1 line, small fonts */ | ||
896 | long_sleep(10); | ||
897 | |||
898 | lcd_write_cmd(0x30 /* set font height and lines number */ | ||
899 | | ((lcd_flags & LCD_FLAG_F)?4:0) | ||
900 | | ((lcd_flags & LCD_FLAG_N)?8:0) | ||
901 | ); | ||
902 | long_sleep(10); | ||
903 | |||
904 | lcd_write_cmd(0x08); /* display off, cursor off, blink off */ | ||
905 | long_sleep(10); | ||
906 | |||
907 | lcd_write_cmd(0x08 /* set display mode */ | ||
908 | | ((lcd_flags & LCD_FLAG_D)?4:0) | ||
909 | | ((lcd_flags & LCD_FLAG_C)?2:0) | ||
910 | | ((lcd_flags & LCD_FLAG_B)?1:0) | ||
911 | ); | ||
912 | |||
913 | lcd_backlight((lcd_flags & LCD_FLAG_L) ? 1 : 0); | ||
914 | |||
915 | long_sleep(10); | ||
916 | |||
917 | lcd_write_cmd(0x06); /* entry mode set : increment, cursor shifting */ | ||
918 | |||
919 | lcd_clear_display(); | ||
920 | } | ||
921 | |||
922 | /* | ||
923 | * These are the file operation function for user access to /dev/lcd | ||
924 | * This function can also be called from inside the kernel, by | ||
925 | * setting file and ppos to NULL. | ||
926 | * | ||
927 | */ | ||
928 | |||
929 | static ssize_t lcd_write(struct file * file, | ||
930 | const char * buf, size_t count, loff_t *ppos ) { | ||
931 | |||
932 | const char *tmp = buf; | ||
933 | char c; | ||
934 | |||
935 | for( ; count-- > 0; (ppos ? (*ppos)++ : 0), ++tmp ) { | ||
936 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) { | ||
937 | schedule(); /* let's be a little nice with other processes that need some CPU */ | ||
938 | } | ||
939 | if (ppos == NULL && file == NULL) | ||
940 | c = *tmp; /* let's not use get_user() from the kernel ! */ | ||
941 | else if (get_user( c, tmp )) | ||
942 | return -EFAULT; | ||
943 | |||
944 | /* first, we'll test if we're in escape mode */ | ||
945 | if ((c != '\n') && lcd_escape_len >= 0) { /* yes, let's add this char to the buffer */ | ||
946 | lcd_escape[lcd_escape_len++] = c; | ||
947 | lcd_escape[lcd_escape_len] = 0; | ||
948 | } | ||
949 | else { | ||
950 | lcd_escape_len = -1; /* aborts any previous escape sequence */ | ||
951 | |||
952 | switch (c) { | ||
953 | case LCD_ESCAPE_CHAR: /* start of an escape sequence */ | ||
954 | lcd_escape_len = 0; | ||
955 | lcd_escape[lcd_escape_len] = 0; | ||
956 | break; | ||
957 | case '\b': /* go back one char and clear it */ | ||
958 | if (lcd_addr_x > 0) { | ||
959 | if (lcd_addr_x < lcd_bwidth) /* check if we're not at the end of the line */ | ||
960 | lcd_write_cmd(0x10); /* back one char */ | ||
961 | lcd_addr_x--; | ||
962 | } | ||
963 | lcd_write_data(' '); /* replace with a space */ | ||
964 | lcd_write_cmd(0x10); /* back one char again */ | ||
965 | break; | ||
966 | case '\014': /* quickly clear the display */ | ||
967 | lcd_clear_fast(); | ||
968 | break; | ||
969 | case '\n': /* flush the remainder of the current line and go to the | ||
970 | beginning of the next line */ | ||
971 | for (; lcd_addr_x<lcd_bwidth; lcd_addr_x++) | ||
972 | lcd_write_data(' '); | ||
973 | lcd_addr_x = 0; | ||
974 | lcd_addr_y = (lcd_addr_y + 1) % lcd_height; | ||
975 | lcd_gotoxy(); | ||
976 | break; | ||
977 | case '\r': /* go to the beginning of the same line */ | ||
978 | lcd_addr_x = 0; | ||
979 | lcd_gotoxy(); | ||
980 | break; | ||
981 | case '\t': /* print a space instead of the tab */ | ||
982 | lcd_print(' '); | ||
983 | break; | ||
984 | default : /* simply print this char */ | ||
985 | lcd_print(c); | ||
986 | break; | ||
987 | } | ||
988 | } | ||
989 | |||
990 | /* now we'll see if we're in an escape mode and if the current | ||
991 | escape sequence can be understood. | ||
992 | */ | ||
993 | if (lcd_escape_len >= 2) { /* minimal length for an escape command */ | ||
994 | int processed = 0; /* 1 means the command has been processed */ | ||
995 | |||
996 | if (!strcmp(lcd_escape,"[2J")) { /* Clear the display */ | ||
997 | lcd_clear_fast(); /* clear display */ | ||
998 | processed = 1; | ||
999 | } | ||
1000 | else if (!strcmp(lcd_escape,"[H")) { /* Cursor to home */ | ||
1001 | lcd_addr_x = lcd_addr_y = 0; | ||
1002 | lcd_gotoxy(); | ||
1003 | processed = 1; | ||
1004 | } | ||
1005 | /* codes starting with ^[[L */ | ||
1006 | else if ((lcd_escape_len >= 3) && | ||
1007 | (lcd_escape[0]=='[') && (lcd_escape[1]=='L')) { /* LCD special codes */ | ||
1008 | |||
1009 | char *esc = lcd_escape + 2; | ||
1010 | int oldflags = lcd_flags; | ||
1011 | |||
1012 | /* check for display mode flags */ | ||
1013 | switch (*esc) { | ||
1014 | case 'D' : /* Display ON */ | ||
1015 | lcd_flags |= LCD_FLAG_D; | ||
1016 | processed = 1; | ||
1017 | break; | ||
1018 | case 'd' : /* Display OFF */ | ||
1019 | lcd_flags &= ~LCD_FLAG_D; | ||
1020 | processed = 1; | ||
1021 | break; | ||
1022 | case 'C' : /* Cursor ON */ | ||
1023 | lcd_flags |= LCD_FLAG_C; | ||
1024 | processed = 1; | ||
1025 | break; | ||
1026 | case 'c' : /* Cursor OFF */ | ||
1027 | lcd_flags &= ~LCD_FLAG_C; | ||
1028 | processed = 1; | ||
1029 | break; | ||
1030 | case 'B' : /* Blink ON */ | ||
1031 | lcd_flags |= LCD_FLAG_B; | ||
1032 | processed = 1; | ||
1033 | break; | ||
1034 | case 'b' : /* Blink OFF */ | ||
1035 | lcd_flags &= ~LCD_FLAG_B; | ||
1036 | processed = 1; | ||
1037 | break; | ||
1038 | case '+' : /* Back light ON */ | ||
1039 | lcd_flags |= LCD_FLAG_L; | ||
1040 | processed = 1; | ||
1041 | break; | ||
1042 | case '-' : /* Back light OFF */ | ||
1043 | lcd_flags &= ~LCD_FLAG_L; | ||
1044 | processed = 1; | ||
1045 | break; | ||
1046 | case '*' : /* flash back light using the keypad timer */ | ||
1047 | if (scan_timer.function != NULL) { | ||
1048 | if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0)) | ||
1049 | lcd_backlight(1); | ||
1050 | light_tempo = FLASH_LIGHT_TEMPO; | ||
1051 | } | ||
1052 | processed = 1; | ||
1053 | break; | ||
1054 | case 'f' : /* Small Font */ | ||
1055 | lcd_flags &= ~LCD_FLAG_F; | ||
1056 | processed = 1; | ||
1057 | break; | ||
1058 | case 'F' : /* Large Font */ | ||
1059 | lcd_flags |= LCD_FLAG_F; | ||
1060 | processed = 1; | ||
1061 | break; | ||
1062 | case 'n' : /* One Line */ | ||
1063 | lcd_flags &= ~LCD_FLAG_N; | ||
1064 | processed = 1; | ||
1065 | break; | ||
1066 | case 'N' : /* Two Lines */ | ||
1067 | lcd_flags |= LCD_FLAG_N; | ||
1068 | break; | ||
1069 | |||
1070 | case 'l' : /* Shift Cursor Left */ | ||
1071 | if (lcd_addr_x > 0) { | ||
1072 | if (lcd_addr_x < lcd_bwidth) | ||
1073 | lcd_write_cmd(0x10); /* back one char if not at end of line */ | ||
1074 | lcd_addr_x--; | ||
1075 | } | ||
1076 | processed = 1; | ||
1077 | break; | ||
1078 | |||
1079 | case 'r' : /* shift cursor right */ | ||
1080 | if (lcd_addr_x < lcd_width) { | ||
1081 | if (lcd_addr_x < (lcd_bwidth - 1)) | ||
1082 | lcd_write_cmd(0x14); /* allow the cursor to pass the end of the line */ | ||
1083 | lcd_addr_x++; | ||
1084 | } | ||
1085 | processed = 1; | ||
1086 | break; | ||
1087 | |||
1088 | case 'L' : /* shift display left */ | ||
1089 | lcd_left_shift++; | ||
1090 | lcd_write_cmd(0x18); | ||
1091 | processed = 1; | ||
1092 | break; | ||
1093 | |||
1094 | case 'R' : /* shift display right */ | ||
1095 | lcd_left_shift--; | ||
1096 | lcd_write_cmd(0x1C); | ||
1097 | processed = 1; | ||
1098 | break; | ||
1099 | |||
1100 | case 'k' : { /* kill end of line */ | ||
1101 | int x; | ||
1102 | for (x=lcd_addr_x; x<lcd_bwidth; x++) | ||
1103 | lcd_write_data(' '); | ||
1104 | lcd_gotoxy(); /* restore cursor position */ | ||
1105 | processed = 1; | ||
1106 | break; | ||
1107 | } | ||
1108 | case 'I' : /* reinitialize display */ | ||
1109 | lcd_init_display(); | ||
1110 | lcd_left_shift = 0; | ||
1111 | processed = 1; | ||
1112 | break; | ||
1113 | |||
1114 | case 'G' : /* Generator : LGcxxxxx...xx; */ { | ||
1115 | /* must have <c> between '0' and '7', representing the numerical | ||
1116 | * ASCII code of the redefined character, and <xx...xx> a sequence | ||
1117 | * of 16 hex digits representing 8 bytes for each character. Most | ||
1118 | * LCDs will only use 5 lower bits of the 7 first bytes. | ||
1119 | */ | ||
1120 | |||
1121 | unsigned char cgbytes[8]; | ||
1122 | unsigned char cgaddr; | ||
1123 | int cgoffset; | ||
1124 | int shift; | ||
1125 | char value; | ||
1126 | int addr; | ||
1127 | |||
1128 | if (strchr(esc, ';') == NULL) | ||
1129 | break; | ||
1130 | |||
1131 | esc++; | ||
1132 | |||
1133 | cgaddr = *(esc++) - '0'; | ||
1134 | if (cgaddr > 7) { | ||
1135 | processed = 1; | ||
1136 | break; | ||
1137 | } | ||
1138 | |||
1139 | cgoffset = 0; | ||
1140 | shift = 0; | ||
1141 | value = 0; | ||
1142 | while (*esc && cgoffset < 8) { | ||
1143 | shift ^= 4; | ||
1144 | if (*esc >= '0' && *esc <='9') | ||
1145 | value |= (*esc - '0') << shift; | ||
1146 | else if (*esc >= 'A' && *esc <='Z') | ||
1147 | value |= (*esc - 'A' + 10) << shift; | ||
1148 | else if (*esc >= 'a' && *esc <='z') | ||
1149 | value |= (*esc - 'a' + 10) << shift; | ||
1150 | else { | ||
1151 | esc++; | ||
1152 | continue; | ||
1153 | } | ||
1154 | |||
1155 | if (shift == 0) { | ||
1156 | cgbytes[cgoffset++] = value; | ||
1157 | value = 0; | ||
1158 | } | ||
1159 | |||
1160 | esc++; | ||
1161 | } | ||
1162 | |||
1163 | lcd_write_cmd(0x40 | (cgaddr * 8)); | ||
1164 | for (addr = 0; addr < cgoffset; addr++) { | ||
1165 | lcd_write_data(cgbytes[addr]); | ||
1166 | } | ||
1167 | |||
1168 | lcd_gotoxy(); /* ensures that we stop writing to CGRAM */ | ||
1169 | processed = 1; | ||
1170 | break; | ||
1171 | } | ||
1172 | case 'x' : /* gotoxy : LxXXX[yYYY]; */ | ||
1173 | case 'y' : /* gotoxy : LyYYY[xXXX]; */ | ||
1174 | if (strchr(esc, ';') == NULL) | ||
1175 | break; | ||
1176 | |||
1177 | while (*esc) { | ||
1178 | if (*esc == 'x') { | ||
1179 | esc++; | ||
1180 | lcd_addr_x = 0; | ||
1181 | while (isdigit(*esc)) { | ||
1182 | lcd_addr_x = lcd_addr_x*10 + (*esc - '0'); | ||
1183 | esc++; | ||
1184 | } | ||
1185 | } | ||
1186 | else if (*esc == 'y') { | ||
1187 | esc++; | ||
1188 | lcd_addr_y = 0; | ||
1189 | while (isdigit(*esc)) { | ||
1190 | lcd_addr_y = lcd_addr_y*10 + (*esc - '0'); | ||
1191 | esc++; | ||
1192 | } | ||
1193 | } | ||
1194 | else break; | ||
1195 | } | ||
1196 | |||
1197 | lcd_gotoxy(); | ||
1198 | processed = 1; | ||
1199 | break; | ||
1200 | } /* end of switch */ | ||
1201 | |||
1202 | /* Check wether one flag was changed */ | ||
1203 | if (oldflags != lcd_flags) { | ||
1204 | /* check wether one of B,C,D flags was changed */ | ||
1205 | if ((oldflags ^ lcd_flags) & (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D)) | ||
1206 | lcd_write_cmd(0x08 /* set display mode */ | ||
1207 | | ((lcd_flags & LCD_FLAG_D)?4:0) | ||
1208 | | ((lcd_flags & LCD_FLAG_C)?2:0) | ||
1209 | | ((lcd_flags & LCD_FLAG_B)?1:0) | ||
1210 | ); | ||
1211 | /* check wether one of F,N flags was changed */ | ||
1212 | else if ((oldflags ^ lcd_flags) & (LCD_FLAG_F | LCD_FLAG_N)) | ||
1213 | lcd_write_cmd(0x30 | ||
1214 | | ((lcd_flags & LCD_FLAG_F)?4:0) | ||
1215 | | ((lcd_flags & LCD_FLAG_N)?8:0) | ||
1216 | ); | ||
1217 | /* check wether L flag was changed */ | ||
1218 | else if ((oldflags ^ lcd_flags) & (LCD_FLAG_L)) { | ||
1219 | if (lcd_flags & (LCD_FLAG_L)) | ||
1220 | lcd_backlight(1); | ||
1221 | else if (light_tempo == 0) /* switch off the light only when the tempo lighting is gone */ | ||
1222 | lcd_backlight(0); | ||
1223 | } | ||
1224 | } | ||
1225 | } /* LCD special escape codes */ | ||
1226 | |||
1227 | /* flush the escape sequence if it's been processed or if it is | ||
1228 | getting too long. */ | ||
1229 | if (processed || (lcd_escape_len >= LCD_ESCAPE_LEN)) | ||
1230 | lcd_escape_len = -1; | ||
1231 | } /* escape codes */ | ||
1232 | } | ||
1233 | |||
1234 | return( tmp - buf ); | ||
1235 | } | ||
1236 | |||
1237 | static int lcd_open( struct inode *inode, struct file *file ) { | ||
1238 | if (lcd_open_cnt) | ||
1239 | return( -EBUSY ); /* open only once at a time */ | ||
1240 | |||
1241 | if (file->f_mode & FMODE_READ) /* device is write-only */ | ||
1242 | return ( -EPERM ); | ||
1243 | |||
1244 | if (lcd_must_clear) { | ||
1245 | lcd_clear_display(); | ||
1246 | lcd_must_clear = 0; | ||
1247 | } | ||
1248 | lcd_open_cnt++; | ||
1249 | return( 0 ); | ||
1250 | } | ||
1251 | |||
1252 | static int lcd_release( struct inode *inode, struct file *file ) { | ||
1253 | lcd_open_cnt--; | ||
1254 | return( 0 ); | ||
1255 | } | ||
1256 | |||
1257 | |||
1258 | static struct file_operations lcd_fops = { | ||
1259 | write: lcd_write, | ||
1260 | open: lcd_open, | ||
1261 | release: lcd_release, | ||
1262 | }; | ||
1263 | |||
1264 | static struct miscdevice lcd_dev = { | ||
1265 | LCD_MINOR, | ||
1266 | "lcd", | ||
1267 | &lcd_fops | ||
1268 | }; | ||
1269 | |||
1270 | |||
1271 | |||
1272 | /* public function usable from the kernel for any purpose */ | ||
1273 | void panel_lcd_print(char *s) { | ||
1274 | if (lcd_enabled && lcd_initialized) | ||
1275 | lcd_write(NULL, s, strlen(s), NULL); | ||
1276 | } | ||
1277 | |||
1278 | |||
1279 | /* initialize the LCD driver */ | ||
1280 | void lcd_init(void) { | ||
1281 | switch (lcd_type) { | ||
1282 | case LCD_TYPE_OLD : /* parallel mode, 8 bits */ | ||
1283 | if (lcd_proto < 0) lcd_proto = LCD_PROTO_PARALLEL; | ||
1284 | if (lcd_charset < 0) lcd_charset = LCD_CHARSET_NORMAL; | ||
1285 | if (lcd_e_pin == PIN_NOT_SET) lcd_e_pin = PIN_STROBE; | ||
1286 | if (lcd_rs_pin == PIN_NOT_SET) lcd_rs_pin = PIN_AUTOLF; | ||
1287 | |||
1288 | if (lcd_width < 0) lcd_width = 40; | ||
1289 | if (lcd_bwidth < 0) lcd_bwidth = 40; | ||
1290 | if (lcd_hwidth < 0) lcd_hwidth = 64; | ||
1291 | if (lcd_height < 0) lcd_height = 2; | ||
1292 | break; | ||
1293 | case LCD_TYPE_KS0074 : /* serial mode, ks0074 */ | ||
1294 | if (lcd_proto < 0) lcd_proto = LCD_PROTO_SERIAL; | ||
1295 | if (lcd_charset < 0) lcd_charset = LCD_CHARSET_KS0074; | ||
1296 | if (lcd_bl_pin == PIN_NOT_SET) lcd_bl_pin = PIN_AUTOLF; | ||
1297 | if (lcd_cl_pin == PIN_NOT_SET) lcd_cl_pin = PIN_STROBE; | ||
1298 | if (lcd_da_pin == PIN_NOT_SET) lcd_da_pin = PIN_D0; | ||
1299 | |||
1300 | if (lcd_width < 0) lcd_width = 16; | ||
1301 | if (lcd_bwidth < 0) lcd_bwidth = 40; | ||
1302 | if (lcd_hwidth < 0) lcd_hwidth = 16; | ||
1303 | if (lcd_height < 0) lcd_height = 2; | ||
1304 | break; | ||
1305 | case LCD_TYPE_NEXCOM : /* parallel mode, 8 bits, generic */ | ||
1306 | if (lcd_proto < 0) lcd_proto = LCD_PROTO_PARALLEL; | ||
1307 | if (lcd_charset < 0) lcd_charset = LCD_CHARSET_NORMAL; | ||
1308 | if (lcd_e_pin == PIN_NOT_SET) lcd_e_pin = PIN_AUTOLF; | ||
1309 | if (lcd_rs_pin == PIN_NOT_SET) lcd_rs_pin = PIN_SELECP; | ||
1310 | if (lcd_rw_pin == PIN_NOT_SET) lcd_rw_pin = PIN_INITP; | ||
1311 | |||
1312 | if (lcd_width < 0) lcd_width = 16; | ||
1313 | if (lcd_bwidth < 0) lcd_bwidth = 40; | ||
1314 | if (lcd_hwidth < 0) lcd_hwidth = 64; | ||
1315 | if (lcd_height < 0) lcd_height = 2; | ||
1316 | break; | ||
1317 | case LCD_TYPE_CUSTOM : /* customer-defined */ | ||
1318 | if (lcd_proto < 0) lcd_proto = DEFAULT_LCD_PROTO; | ||
1319 | if (lcd_charset < 0) lcd_charset = DEFAULT_LCD_CHARSET; | ||
1320 | /* default geometry will be set later */ | ||
1321 | break; | ||
1322 | case LCD_TYPE_HANTRONIX : /* parallel mode, 8 bits, hantronix-like */ | ||
1323 | default : | ||
1324 | if (lcd_proto < 0) lcd_proto = LCD_PROTO_PARALLEL; | ||
1325 | if (lcd_charset < 0) lcd_charset = LCD_CHARSET_NORMAL; | ||
1326 | if (lcd_e_pin == PIN_NOT_SET) lcd_e_pin = PIN_STROBE; | ||
1327 | if (lcd_rs_pin == PIN_NOT_SET) lcd_rs_pin = PIN_SELECP; | ||
1328 | |||
1329 | if (lcd_width < 0) lcd_width = 16; | ||
1330 | if (lcd_bwidth < 0) lcd_bwidth = 40; | ||
1331 | if (lcd_hwidth < 0) lcd_hwidth = 64; | ||
1332 | if (lcd_height < 0) lcd_height = 2; | ||
1333 | break; | ||
1334 | } | ||
1335 | |||
1336 | /* this is used to catch wrong and default values */ | ||
1337 | if (lcd_width <= 0) lcd_width = DEFAULT_LCD_WIDTH; | ||
1338 | if (lcd_bwidth <= 0) lcd_bwidth = DEFAULT_LCD_BWIDTH; | ||
1339 | if (lcd_hwidth <= 0) lcd_hwidth = DEFAULT_LCD_HWIDTH; | ||
1340 | if (lcd_height <= 0) lcd_height = DEFAULT_LCD_HEIGHT; | ||
1341 | |||
1342 | if (lcd_proto == LCD_PROTO_SERIAL) { /* SERIAL */ | ||
1343 | lcd_write_cmd = lcd_write_cmd_s; | ||
1344 | lcd_write_data = lcd_write_data_s; | ||
1345 | lcd_clear_fast = lcd_clear_fast_s; | ||
1346 | |||
1347 | if (lcd_cl_pin == PIN_NOT_SET) | ||
1348 | lcd_cl_pin = DEFAULT_LCD_PIN_SCL; | ||
1349 | if (lcd_da_pin == PIN_NOT_SET) | ||
1350 | lcd_da_pin = DEFAULT_LCD_PIN_SDA; | ||
1351 | |||
1352 | } else { /* PARALLEL */ | ||
1353 | lcd_write_cmd = lcd_write_cmd_p8; | ||
1354 | lcd_write_data = lcd_write_data_p8; | ||
1355 | lcd_clear_fast = lcd_clear_fast_p8; | ||
1356 | |||
1357 | if (lcd_e_pin == PIN_NOT_SET) | ||
1358 | lcd_e_pin = DEFAULT_LCD_PIN_E; | ||
1359 | if (lcd_rs_pin == PIN_NOT_SET) | ||
1360 | lcd_rs_pin = DEFAULT_LCD_PIN_RS; | ||
1361 | if (lcd_rw_pin == PIN_NOT_SET) | ||
1362 | lcd_rw_pin = DEFAULT_LCD_PIN_RW; | ||
1363 | } | ||
1364 | |||
1365 | if (lcd_bl_pin == PIN_NOT_SET) | ||
1366 | lcd_bl_pin = DEFAULT_LCD_PIN_BL; | ||
1367 | |||
1368 | if (lcd_e_pin == PIN_NOT_SET) lcd_e_pin = PIN_NONE; | ||
1369 | if (lcd_rs_pin == PIN_NOT_SET) lcd_rs_pin = PIN_NONE; | ||
1370 | if (lcd_rw_pin == PIN_NOT_SET) lcd_rw_pin = PIN_NONE; | ||
1371 | if (lcd_bl_pin == PIN_NOT_SET) lcd_bl_pin = PIN_NONE; | ||
1372 | if (lcd_cl_pin == PIN_NOT_SET) lcd_cl_pin = PIN_NONE; | ||
1373 | if (lcd_da_pin == PIN_NOT_SET) lcd_da_pin = PIN_NONE; | ||
1374 | |||
1375 | if (lcd_charset < 0) | ||
1376 | lcd_charset = DEFAULT_LCD_CHARSET; | ||
1377 | |||
1378 | if (lcd_charset == LCD_CHARSET_KS0074) | ||
1379 | lcd_char_conv = lcd_char_conv_ks0074; | ||
1380 | else | ||
1381 | lcd_char_conv = NULL; | ||
1382 | |||
1383 | if (lcd_bl_pin != PIN_NONE) | ||
1384 | init_scan_timer(); | ||
1385 | |||
1386 | pin_to_bits(lcd_e_pin, lcd_bits[LCD_PORT_D][LCD_BIT_E], lcd_bits[LCD_PORT_C][LCD_BIT_E]); | ||
1387 | pin_to_bits(lcd_rs_pin, lcd_bits[LCD_PORT_D][LCD_BIT_RS], lcd_bits[LCD_PORT_C][LCD_BIT_RS]); | ||
1388 | pin_to_bits(lcd_rw_pin, lcd_bits[LCD_PORT_D][LCD_BIT_RW], lcd_bits[LCD_PORT_C][LCD_BIT_RW]); | ||
1389 | pin_to_bits(lcd_bl_pin, lcd_bits[LCD_PORT_D][LCD_BIT_BL], lcd_bits[LCD_PORT_C][LCD_BIT_BL]); | ||
1390 | pin_to_bits(lcd_cl_pin, lcd_bits[LCD_PORT_D][LCD_BIT_CL], lcd_bits[LCD_PORT_C][LCD_BIT_CL]); | ||
1391 | pin_to_bits(lcd_da_pin, lcd_bits[LCD_PORT_D][LCD_BIT_DA], lcd_bits[LCD_PORT_C][LCD_BIT_DA]); | ||
1392 | |||
1393 | /* before this line, we must NOT send anything to the display. | ||
1394 | * Since lcd_init_display() needs to write data, we have to | ||
1395 | * enable mark the LCD initialized just before. | ||
1396 | */ | ||
1397 | lcd_initialized = 1; | ||
1398 | lcd_init_display(); | ||
1399 | |||
1400 | /* display a short message */ | ||
1401 | #ifdef CONFIG_PANEL_CHANGE_MESSAGE | ||
1402 | #ifdef CONFIG_PANEL_BOOT_MESSAGE | ||
1403 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); | ||
1404 | #endif | ||
1405 | #else | ||
1406 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\nPanel-" PANEL_VERSION); | ||
1407 | #endif | ||
1408 | lcd_addr_x = lcd_addr_y = 0; | ||
1409 | lcd_must_clear = 1; /* clear the display on the next device opening */ | ||
1410 | lcd_gotoxy(); | ||
1411 | } | ||
1412 | |||
1413 | |||
1414 | /* | ||
1415 | * These are the file operation function for user access to /dev/keypad | ||
1416 | */ | ||
1417 | |||
1418 | static ssize_t keypad_read(struct file * file, | ||
1419 | char * buf, size_t count, loff_t *ppos ) { | ||
1420 | |||
1421 | unsigned i = *ppos; | ||
1422 | char *tmp = buf; | ||
1423 | |||
1424 | if (keypad_buflen == 0) { | ||
1425 | if (file->f_flags & O_NONBLOCK) | ||
1426 | return -EAGAIN; | ||
1427 | |||
1428 | //printk(KERN_ERR "keypad_read():1 len=%d", keypad_buflen); | ||
1429 | interruptible_sleep_on(&keypad_read_wait); | ||
1430 | //printk(KERN_ERR "keypad_read():2 len=%d", keypad_buflen); | ||
1431 | if (signal_pending(current)) | ||
1432 | return -EINTR; | ||
1433 | } | ||
1434 | |||
1435 | //printk(KERN_ERR "keypad_read():3 len=%d", keypad_buflen); | ||
1436 | for( ; count-- > 0 && (keypad_buflen > 0); ++i, ++tmp, --keypad_buflen ) { | ||
1437 | put_user( keypad_buffer[keypad_start], tmp ); | ||
1438 | keypad_start = (keypad_start + 1) % KEYPAD_BUFFER; | ||
1439 | } | ||
1440 | *ppos = i; | ||
1441 | //printk(KERN_ERR "keypad_read():4 len=%d", keypad_buflen); | ||
1442 | |||
1443 | return( tmp - buf ); | ||
1444 | } | ||
1445 | |||
1446 | |||
1447 | static int keypad_open( struct inode *inode, struct file *file ) { | ||
1448 | |||
1449 | if (keypad_open_cnt) | ||
1450 | return( -EBUSY ); /* open only once at a time */ | ||
1451 | |||
1452 | if (file->f_mode & FMODE_WRITE) /* device is read-only */ | ||
1453 | return ( -EPERM ); | ||
1454 | |||
1455 | keypad_buflen = 0; /* flush the buffer on opening */ | ||
1456 | keypad_open_cnt++; | ||
1457 | return( 0 ); | ||
1458 | } | ||
1459 | |||
1460 | static int keypad_release( struct inode *inode, struct file *file ) { | ||
1461 | keypad_open_cnt--; | ||
1462 | return( 0 ); | ||
1463 | } | ||
1464 | |||
1465 | static struct file_operations keypad_fops = { | ||
1466 | read: keypad_read, /* read */ | ||
1467 | open: keypad_open, /* open */ | ||
1468 | release: keypad_release, /* close */ | ||
1469 | }; | ||
1470 | |||
1471 | static struct miscdevice keypad_dev = { | ||
1472 | KEYPAD_MINOR, | ||
1473 | "keypad", | ||
1474 | &keypad_fops | ||
1475 | }; | ||
1476 | |||
1477 | static void keypad_send_key(char *string, int max_len) { | ||
1478 | //printk(KERN_ERR "keypad_send_key(%c,%d):1\n", *string,max_len); | ||
1479 | if (init_in_progress) | ||
1480 | return; | ||
1481 | //printk(KERN_ERR "keypad_send_key(%c,%d):2\n", *string,max_len); | ||
1482 | |||
1483 | /* send the key to the device only if a process is attached to it. */ | ||
1484 | if (keypad_open_cnt > 0) { | ||
1485 | //printk(KERN_ERR "keypad_send_key(%c,%d):3\n", *string,max_len); | ||
1486 | while (max_len-- && keypad_buflen < KEYPAD_BUFFER && *string) { | ||
1487 | keypad_buffer[(keypad_start + keypad_buflen++) % KEYPAD_BUFFER] = *string++; | ||
1488 | } | ||
1489 | //printk(KERN_ERR "keypad_send_key(%d):4\n", *string,max_len); | ||
1490 | wake_up_interruptible(&keypad_read_wait); | ||
1491 | } | ||
1492 | //printk(KERN_ERR "keypad_send_key(%d):5\n", *string,max_len); | ||
1493 | } | ||
1494 | |||
1495 | |||
1496 | /* this function scans all the bits involving at least one logical signal, and puts the | ||
1497 | * results in the bitfield "phys_read" (one bit per established contact), and sets | ||
1498 | * "phys_read_prev" to "phys_read". | ||
1499 | * | ||
1500 | * Note: to debounce input signals, we will only consider as switched a signal which is | ||
1501 | * stable across 2 measures. Signals which are different between two reads will be kept | ||
1502 | * as they previously were in their logical form (phys_prev). A signal which has just | ||
1503 | * switched will have a 1 in (phys_read ^ phys_read_prev). | ||
1504 | */ | ||
1505 | static void phys_scan_contacts(void) { | ||
1506 | int bit, bitval; | ||
1507 | char oldval; | ||
1508 | char bitmask; | ||
1509 | char gndmask; | ||
1510 | |||
1511 | phys_prev = phys_curr; | ||
1512 | phys_read_prev = phys_read; | ||
1513 | phys_read = 0; /* flush all signals */ | ||
1514 | |||
1515 | oldval = r_dtr(pprt) | scan_mask_o; /* keep track of old value, with all outputs disabled */ | ||
1516 | w_dtr(pprt, oldval & ~scan_mask_o); /* activate all keyboard outputs (active low) */ | ||
1517 | bitmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i; /* will have a 1 for each bit set to gnd */ | ||
1518 | w_dtr(pprt, oldval); /* disable all matrix signals */ | ||
1519 | |||
1520 | /* now that all outputs are cleared, the only active input bits are | ||
1521 | * directly connected to the ground | ||
1522 | */ | ||
1523 | gndmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i; /* 1 for each grounded input */ | ||
1524 | |||
1525 | phys_read |= (pmask_t)gndmask << 40; /* grounded inputs are signals 40-44 */ | ||
1526 | |||
1527 | if (bitmask != gndmask) { | ||
1528 | /* since clearing the outputs changed some inputs, we know that some | ||
1529 | * input signals are currently tied to some outputs. So we'll scan them. | ||
1530 | */ | ||
1531 | for (bit = 0; bit < 8; bit ++) { | ||
1532 | bitval = 1 << bit; | ||
1533 | |||
1534 | if (!(scan_mask_o & bitval)) /* skip unused bits */ | ||
1535 | continue; | ||
1536 | |||
1537 | w_dtr(pprt, oldval & ~bitval); /* enable this output */ | ||
1538 | bitmask = PNL_PINPUT(r_str(pprt)) & ~gndmask; | ||
1539 | phys_read |= (pmask_t) bitmask << (5*bit); | ||
1540 | } | ||
1541 | w_dtr(pprt, oldval); /* disable all outputs */ | ||
1542 | } | ||
1543 | /* this is easy: use old bits when they are flapping, use new ones when stable */ | ||
1544 | phys_curr = (phys_prev & (phys_read ^ phys_read_prev)) | (phys_read & ~(phys_read ^ phys_read_prev)); | ||
1545 | } | ||
1546 | |||
1547 | static void panel_process_inputs(void) { | ||
1548 | struct list_head *item; | ||
1549 | struct logical_input *input; | ||
1550 | |||
1551 | #if 0 | ||
1552 | printk(KERN_DEBUG "entering panel_process_inputs with pp=%016Lx & pc=%016Lx\n", | ||
1553 | phys_prev, phys_curr); | ||
1554 | #endif | ||
1555 | |||
1556 | keypressed = 0; | ||
1557 | inputs_stable = 1; | ||
1558 | list_for_each(item, &logical_inputs) { | ||
1559 | input = list_entry(item, struct logical_input, list); | ||
1560 | |||
1561 | switch (input->state) { | ||
1562 | case INPUT_ST_LOW: | ||
1563 | if ((phys_curr & input->mask) != input->value) | ||
1564 | break; | ||
1565 | /* if all needed ones were already set previously, this means that | ||
1566 | * this logical signal has been activated by the releasing of | ||
1567 | * another combined signal, so we don't want to match. | ||
1568 | * eg: AB -(release B)-> A -(release A)-> 0 : don't match A. | ||
1569 | */ | ||
1570 | if ((phys_prev & input->mask) == input->value) | ||
1571 | break; | ||
1572 | input->rise_timer = 0; | ||
1573 | input->state = INPUT_ST_RISING; | ||
1574 | /* no break here, fall through */ | ||
1575 | case INPUT_ST_RISING: | ||
1576 | if ((phys_curr & input->mask) != input->value) { | ||
1577 | input->state = INPUT_ST_LOW; | ||
1578 | break; | ||
1579 | } | ||
1580 | if (input->rise_timer < input->rise_time) { | ||
1581 | inputs_stable = 0; | ||
1582 | input->rise_timer++; | ||
1583 | break; | ||
1584 | } | ||
1585 | input->high_timer = 0; | ||
1586 | input->state = INPUT_ST_HIGH; | ||
1587 | /* no break here, fall through */ | ||
1588 | case INPUT_ST_HIGH: | ||
1589 | #if 0 | ||
1590 | /* FIXME: | ||
1591 | * this is an invalid test. It tries to catch transitions from single-key | ||
1592 | * to multiple-key, but doesn't take into account the contacts polarity. | ||
1593 | * The only solution to the problem is to parse keys from the most complex | ||
1594 | * to the simplest combinations, and mark them as 'caught' once a combination | ||
1595 | * matches, then unmatch it for all other ones. | ||
1596 | */ | ||
1597 | |||
1598 | /* try to catch dangerous transitions cases : | ||
1599 | * someone adds a bit, so this signal was a false | ||
1600 | * positive resulting from a transition. We should invalidate | ||
1601 | * the signal immediately and not call the release function. | ||
1602 | * eg: 0 -(press A)-> A -(press B)-> AB : don't match A's release. | ||
1603 | */ | ||
1604 | if (((phys_prev & input->mask) == input->value) | ||
1605 | && ((phys_curr & input->mask) > input->value)) { | ||
1606 | input->state = INPUT_ST_LOW; /* invalidate */ | ||
1607 | break; | ||
1608 | } | ||
1609 | //else | ||
1610 | #endif | ||
1611 | |||
1612 | if ((phys_curr & input->mask) == input->value) { | ||
1613 | if ((input->type == INPUT_TYPE_STD) && (input->high_timer == 0)) { | ||
1614 | input->high_timer++; | ||
1615 | if (input->u.std.press_fct != NULL) | ||
1616 | input->u.std.press_fct(input->u.std.press_data); | ||
1617 | } | ||
1618 | else if (input->type == INPUT_TYPE_KBD) { | ||
1619 | keypressed = 1; /* will turn on the light */ | ||
1620 | |||
1621 | if (input->high_timer == 0) { | ||
1622 | if (input->u.kbd.press_str[0]) | ||
1623 | keypad_send_key(input->u.kbd.press_str, sizeof(input->u.kbd.press_str)); | ||
1624 | } | ||
1625 | |||
1626 | if (input->u.kbd.repeat_str[0]) { | ||
1627 | if (input->high_timer >= KEYPAD_REP_START) { | ||
1628 | input->high_timer -= KEYPAD_REP_DELAY; | ||
1629 | keypad_send_key(input->u.kbd.repeat_str, sizeof(input->u.kbd.repeat_str)); | ||
1630 | } | ||
1631 | inputs_stable = 0; /* we will need to come back here soon */ | ||
1632 | } | ||
1633 | |||
1634 | if (input->high_timer < 255) { | ||
1635 | input->high_timer++; | ||
1636 | } | ||
1637 | } | ||
1638 | break; | ||
1639 | } | ||
1640 | else { | ||
1641 | /* else signal falling down. Let's fall through. */ | ||
1642 | input->state = INPUT_ST_FALLING; | ||
1643 | input->fall_timer = 0; | ||
1644 | } | ||
1645 | /* no break here, fall through */ | ||
1646 | case INPUT_ST_FALLING: | ||
1647 | #if 0 | ||
1648 | /* FIXME !!! same comment as above */ | ||
1649 | if (((phys_prev & input->mask) == input->value) | ||
1650 | && ((phys_curr & input->mask) > input->value)) { | ||
1651 | input->state = INPUT_ST_LOW; /* invalidate */ | ||
1652 | break; | ||
1653 | } | ||
1654 | //else | ||
1655 | #endif | ||
1656 | |||
1657 | if ((phys_curr & input->mask) == input->value) { | ||
1658 | if (input->type == INPUT_TYPE_KBD) { | ||
1659 | keypressed = 1; /* will turn on the light */ | ||
1660 | |||
1661 | if (input->u.kbd.repeat_str[0]) { | ||
1662 | if (input->high_timer >= KEYPAD_REP_START) | ||
1663 | input->high_timer -= KEYPAD_REP_DELAY; | ||
1664 | keypad_send_key(input->u.kbd.repeat_str, sizeof(input->u.kbd.repeat_str)); | ||
1665 | inputs_stable = 0; /* we will need to come back here soon */ | ||
1666 | } | ||
1667 | |||
1668 | if (input->high_timer < 255) { | ||
1669 | input->high_timer++; | ||
1670 | } | ||
1671 | } | ||
1672 | input->state = INPUT_ST_HIGH; | ||
1673 | break; | ||
1674 | } | ||
1675 | else if (input->fall_timer >= input->fall_time) { | ||
1676 | /* call release event */ | ||
1677 | if (input->type == INPUT_TYPE_STD) { | ||
1678 | if (input->u.std.release_fct != NULL) | ||
1679 | input->u.std.release_fct(input->u.std.release_data); | ||
1680 | } | ||
1681 | else if (input->type == INPUT_TYPE_KBD) { | ||
1682 | if (input->u.kbd.release_str[0]) | ||
1683 | keypad_send_key(input->u.kbd.release_str, sizeof(input->u.kbd.release_str)); | ||
1684 | } | ||
1685 | |||
1686 | input->state = INPUT_ST_LOW; | ||
1687 | break; | ||
1688 | } | ||
1689 | else { | ||
1690 | input->fall_timer++; | ||
1691 | inputs_stable = 0; | ||
1692 | break; | ||
1693 | } | ||
1694 | } | ||
1695 | } | ||
1696 | } | ||
1697 | |||
1698 | static void panel_scan_timer(void) { | ||
1699 | if ((keypad_enabled && keypad_initialized) | ||
1700 | || (smartcard_enabled && smartcard_enabled)) { | ||
1701 | |||
1702 | if (spin_trylock(&pprt_lock)) { | ||
1703 | phys_scan_contacts(); | ||
1704 | spin_unlock(&pprt_lock); /* no need for the parport anymore */ | ||
1705 | } | ||
1706 | |||
1707 | if (!inputs_stable || phys_curr != phys_prev) { | ||
1708 | panel_process_inputs(); | ||
1709 | } | ||
1710 | } | ||
1711 | |||
1712 | if (lcd_enabled && lcd_initialized) { | ||
1713 | if (keypressed) { | ||
1714 | if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0)) | ||
1715 | lcd_backlight(1); | ||
1716 | light_tempo = FLASH_LIGHT_TEMPO; | ||
1717 | } | ||
1718 | else if (light_tempo > 0) { | ||
1719 | light_tempo--; | ||
1720 | if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0)) | ||
1721 | lcd_backlight(0); | ||
1722 | } | ||
1723 | } | ||
1724 | |||
1725 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); | ||
1726 | } | ||
1727 | |||
1728 | /* send a high / low clock impulse of <duration> microseconds high and low */ | ||
1729 | static void smartcard_send_clock(int duration) { | ||
1730 | int old; | ||
1731 | |||
1732 | w_dtr(pprt, (old = r_dtr(pprt)) | PNL_SC_CLK); | ||
1733 | udelay(duration); | ||
1734 | w_dtr(pprt, (old & ~PNL_SC_CLK)); | ||
1735 | udelay(duration); | ||
1736 | } | ||
1737 | |||
1738 | static void smartcard_insert(int dummy) { | ||
1739 | int ofs; | ||
1740 | |||
1741 | spin_lock(&pprt_lock); | ||
1742 | w_dtr(pprt, (r_dtr(pprt) & ~PNL_SC_BITS)); | ||
1743 | w_ctr(pprt, (r_ctr(pprt) | PNL_SC_ENA)); | ||
1744 | |||
1745 | udelay(30); /* ensure the rst is low at least 30 us */ | ||
1746 | |||
1747 | smartcard_send_clock(100); /* reset address counter */ | ||
1748 | |||
1749 | w_dtr(pprt, r_dtr(pprt) | PNL_SC_RST); | ||
1750 | udelay(30); /* ensure the rst is high at least 30 us */ | ||
1751 | |||
1752 | for (ofs = 0; ofs < SMARTCARD_BYTES; ofs++) { | ||
1753 | int bit, byte; | ||
1754 | byte = 0; | ||
1755 | for (bit = 128; bit > 0; bit >>= 1) { | ||
1756 | if (!(r_str(pprt) & PNL_SC_IOR)) | ||
1757 | byte |= bit; | ||
1758 | smartcard_send_clock(15); /* 15 us are enough for data */ | ||
1759 | } | ||
1760 | smartcard_data[ofs] = byte; | ||
1761 | } | ||
1762 | |||
1763 | w_dtr(pprt, (r_dtr(pprt) & ~PNL_SC_BITS)); | ||
1764 | w_ctr(pprt, (r_ctr(pprt) & ~PNL_SC_ENA)); | ||
1765 | |||
1766 | spin_unlock(&pprt_lock); | ||
1767 | |||
1768 | printk(KERN_INFO "Panel: smart card inserted : %02x%02x%02x%02x%1x\n", | ||
1769 | smartcard_data[2], smartcard_data[3], smartcard_data[4], | ||
1770 | smartcard_data[5], smartcard_data[6] >> 4); | ||
1771 | keypad_send_key("CardIn\n", 7); | ||
1772 | } | ||
1773 | |||
1774 | static void smartcard_remove(int dummy) { | ||
1775 | printk(KERN_INFO "Panel: smart card removed : %02x%02x%02x%02x%1x\n", | ||
1776 | smartcard_data[2], smartcard_data[3], smartcard_data[4], | ||
1777 | smartcard_data[5], smartcard_data[6] >> 4); | ||
1778 | memset(smartcard_data, 0, sizeof(smartcard_data)); | ||
1779 | keypad_send_key("CardOut\n", 8); | ||
1780 | } | ||
1781 | |||
1782 | /* | ||
1783 | * These are the file operation function for user access to /dev/smartcard | ||
1784 | */ | ||
1785 | |||
1786 | static ssize_t smartcard_read(struct file * file, | ||
1787 | char * buf, size_t count, loff_t *ppos ) { | ||
1788 | |||
1789 | unsigned i = *ppos; | ||
1790 | char *tmp = buf; | ||
1791 | |||
1792 | for( ; count-- > 0 && (smartcard_ptr < 9); ++i, ++tmp, ++smartcard_ptr ) { | ||
1793 | if (smartcard_ptr & 1) | ||
1794 | put_user( '0' + (smartcard_data[2 + (smartcard_ptr >> 1)] & 0xF), tmp ); | ||
1795 | else | ||
1796 | put_user( '0' + (smartcard_data[2 + (smartcard_ptr >> 1)] >> 4), tmp ); | ||
1797 | } | ||
1798 | *ppos = i; | ||
1799 | |||
1800 | return( tmp - buf ); | ||
1801 | } | ||
1802 | |||
1803 | |||
1804 | static int smartcard_open( struct inode *inode, struct file *file ) { | ||
1805 | |||
1806 | if (smartcard_open_cnt) | ||
1807 | return( -EBUSY ); /* open only once at a time */ | ||
1808 | |||
1809 | if (file->f_mode & FMODE_WRITE) /* device is read-only */ | ||
1810 | return ( -EPERM ); | ||
1811 | |||
1812 | smartcard_ptr = 0; /* flush the buffer on opening */ | ||
1813 | smartcard_open_cnt++; | ||
1814 | return( 0 ); | ||
1815 | } | ||
1816 | |||
1817 | static int smartcard_release( struct inode *inode, struct file *file ) { | ||
1818 | smartcard_open_cnt--; | ||
1819 | return( 0 ); | ||
1820 | } | ||
1821 | |||
1822 | static struct file_operations smartcard_fops = { | ||
1823 | read: smartcard_read, /* read */ | ||
1824 | open: smartcard_open, /* open */ | ||
1825 | release: smartcard_release, /* close */ | ||
1826 | }; | ||
1827 | |||
1828 | static struct miscdevice smartcard_dev = { | ||
1829 | SMARTCARD_MINOR, | ||
1830 | "smartcard", | ||
1831 | &smartcard_fops | ||
1832 | }; | ||
1833 | |||
1834 | static void init_scan_timer(void) { | ||
1835 | if (scan_timer.function != NULL) | ||
1836 | return; /* already started */ | ||
1837 | |||
1838 | init_timer(&scan_timer); | ||
1839 | scan_timer.expires = jiffies + INPUT_POLL_TIME; | ||
1840 | scan_timer.data = 0; | ||
1841 | scan_timer.function = (void *)&panel_scan_timer; | ||
1842 | add_timer(&scan_timer); | ||
1843 | } | ||
1844 | |||
1845 | /* converts a name of the form "({BbAaPpSsEe}{01234567-})*" to a series of bits. | ||
1846 | * if <omask> or <imask> are non-null, they will be or'ed with the bits corresponding | ||
1847 | * to out and in bits respectively. | ||
1848 | * returns 1 if ok, 0 if error (in which case, nothing is written). | ||
1849 | */ | ||
1850 | static int input_name2mask(char *name, pmask_t *mask, pmask_t *value, char *imask, char *omask) { | ||
1851 | static char sigtab[10]="EeSsPpAaBb"; | ||
1852 | char im, om; | ||
1853 | pmask_t m, v; | ||
1854 | |||
1855 | om = im = m = v = 0ULL; | ||
1856 | while (*name) { | ||
1857 | int in, out, bit, neg; | ||
1858 | for (in = 0; (in < sizeof(sigtab)) && (sigtab[in] != *name); in++); | ||
1859 | if (in >= sizeof(sigtab)) | ||
1860 | return 0; /* input name not found */ | ||
1861 | neg = (in & 1); /* odd (lower) names are negated */ | ||
1862 | in >>= 1; | ||
1863 | im |= (1 << in); | ||
1864 | |||
1865 | name++; | ||
1866 | if (isdigit(*name)) { | ||
1867 | out = *name - '0'; | ||
1868 | om |= (1 << out); | ||
1869 | } | ||
1870 | else if (*name == '-') | ||
1871 | out = 8; | ||
1872 | else | ||
1873 | return 0; /* unknown bit name */ | ||
1874 | |||
1875 | bit = (out * 5) + in; | ||
1876 | |||
1877 | m |= 1ULL << bit; | ||
1878 | if (!neg) | ||
1879 | v |= 1ULL << bit; | ||
1880 | name++; | ||
1881 | } | ||
1882 | *mask = m; | ||
1883 | *value = v; | ||
1884 | if (imask) | ||
1885 | *imask |= im; | ||
1886 | if (omask) | ||
1887 | *omask |= om; | ||
1888 | return 1; | ||
1889 | } | ||
1890 | |||
1891 | /* tries to bind a key to the signal name <name>. The key will send the | ||
1892 | * strings <press>, <repeat>, <release> for these respective events. | ||
1893 | * Returns the pointer to the new key if ok, NULL if the key could not be bound. | ||
1894 | */ | ||
1895 | static struct logical_input *panel_bind_key(char *name, char *press, char *repeat, char *release) { | ||
1896 | struct logical_input *key; | ||
1897 | |||
1898 | key = (struct logical_input*)kmalloc(sizeof(struct logical_input), GFP_KERNEL); | ||
1899 | if (!key) { | ||
1900 | printk(KERN_ERR "panel: not enough memory\n"); | ||
1901 | return NULL; | ||
1902 | } | ||
1903 | memset(key, 0, sizeof(struct logical_input)); | ||
1904 | if (!input_name2mask(name, &key->mask, &key->value, &scan_mask_i, &scan_mask_o)) | ||
1905 | return NULL; | ||
1906 | key->type = INPUT_TYPE_KBD; | ||
1907 | key->state = INPUT_ST_LOW; | ||
1908 | key->rise_time = 1; | ||
1909 | key->fall_time = 1; | ||
1910 | |||
1911 | #if 0 | ||
1912 | printk(KERN_DEBUG "bind: <%s> : m=%016Lx v=%016Lx\n", name, key->mask, key->value); | ||
1913 | #endif | ||
1914 | strncpy(key->u.kbd.press_str, press, sizeof(key->u.kbd.press_str)); | ||
1915 | strncpy(key->u.kbd.repeat_str, repeat, sizeof(key->u.kbd.repeat_str)); | ||
1916 | strncpy(key->u.kbd.release_str, release, sizeof(key->u.kbd.release_str)); | ||
1917 | list_add(&key->list, &logical_inputs); | ||
1918 | return key; | ||
1919 | } | ||
1920 | |||
1921 | /* tries to bind a callback function to the signal name <name>. The function | ||
1922 | * <press_fct> will be called with the <press_data> arg when the signal is | ||
1923 | * activated, and so on for <release_fct>/<release_data> | ||
1924 | * Returns the pointer to the new signal if ok, NULL if the signal could not be bound. | ||
1925 | */ | ||
1926 | static struct logical_input *panel_bind_callback(char *name, | ||
1927 | void (*press_fct)(int), int press_data, | ||
1928 | void (*release_fct)(int), int release_data) { | ||
1929 | struct logical_input *callback; | ||
1930 | |||
1931 | callback = (struct logical_input*)kmalloc(sizeof(struct logical_input), GFP_KERNEL); | ||
1932 | if (!callback) { | ||
1933 | printk(KERN_ERR "panel: not enough memory\n"); | ||
1934 | return NULL; | ||
1935 | } | ||
1936 | memset(callback, 0, sizeof(struct logical_input)); | ||
1937 | if (!input_name2mask(name, &callback->mask, &callback->value, &scan_mask_i, &scan_mask_o)) | ||
1938 | return NULL; | ||
1939 | callback->type = INPUT_TYPE_STD; | ||
1940 | callback->state = INPUT_ST_LOW; | ||
1941 | callback->rise_time = 1; | ||
1942 | callback->fall_time = 1; | ||
1943 | callback->u.std.press_fct = press_fct; | ||
1944 | callback->u.std.press_data = press_data; | ||
1945 | callback->u.std.release_fct = release_fct; | ||
1946 | callback->u.std.release_data = release_data; | ||
1947 | list_add(&callback->list, &logical_inputs); | ||
1948 | return callback; | ||
1949 | } | ||
1950 | |||
1951 | static void keypad_init(void) { | ||
1952 | int keynum; | ||
1953 | init_waitqueue_head(&keypad_read_wait); | ||
1954 | keypad_buflen = 0; /* flushes any eventual noisy keystroke */ | ||
1955 | |||
1956 | /* Let's create all known keys */ | ||
1957 | |||
1958 | for (keynum = 0; keypad_profile[keynum][0][0]; keynum++) { | ||
1959 | panel_bind_key(keypad_profile[keynum][0], | ||
1960 | keypad_profile[keynum][1], | ||
1961 | keypad_profile[keynum][2], | ||
1962 | keypad_profile[keynum][3]); | ||
1963 | } | ||
1964 | |||
1965 | init_scan_timer(); | ||
1966 | keypad_initialized = 1; | ||
1967 | } | ||
1968 | |||
1969 | |||
1970 | static void smartcard_init(void) { | ||
1971 | init_waitqueue_head(&smartcard_read_wait); | ||
1972 | |||
1973 | panel_bind_callback(SMARTCARD_LOGICAL_DETECTOR, &smartcard_insert, 0, &smartcard_remove, 0); | ||
1974 | init_scan_timer(); | ||
1975 | smartcard_enabled = 1; | ||
1976 | } | ||
1977 | |||
1978 | |||
1979 | /**************************************************/ | ||
1980 | /* device initialization */ | ||
1981 | /**************************************************/ | ||
1982 | |||
1983 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) | ||
1984 | #define INIT_FUNC static int __init panel_init_module | ||
1985 | #define CLEANUP_FUNC static void __exit panel_cleanup_module | ||
1986 | #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) | ||
1987 | #define INIT_FUNC static int __init panel_init_module | ||
1988 | #define CLEANUP_FUNC static void panel_cleanup_module | ||
1989 | #else | ||
1990 | #define INIT_FUNC int init_module | ||
1991 | #define CLEANUP_FUNC int cleanup_module | ||
1992 | #endif | ||
1993 | |||
1994 | #ifndef MODULE | ||
1995 | /* called when compiled into the kernel */ | ||
1996 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) | ||
1997 | static int __init panel_setup(char *str) | ||
1998 | #else | ||
1999 | __initfunc(void panel_setup(char *str, int *ints)) | ||
2000 | #endif | ||
2001 | { | ||
2002 | int dummy; | ||
2003 | int *where; | ||
2004 | int helpdisplayed = 0; | ||
2005 | |||
2006 | if (!str) | ||
2007 | return 0; | ||
2008 | |||
2009 | while (*str) { | ||
2010 | where = NULL; | ||
2011 | |||
2012 | /* let's parse each of the command line parameters of the following form : | ||
2013 | panel=[parport:x],[lcd_height:x],[lcd_width:x],[lcd_bwidth:x],[lcd_hwidth:x] | ||
2014 | */ | ||
2015 | if (!strncmp(str, "parport:", 8)) { | ||
2016 | str += 8; | ||
2017 | where = &parport; | ||
2018 | } | ||
2019 | else if (!strncmp(str, "disabled", 8)) { | ||
2020 | return 0; | ||
2021 | } | ||
2022 | else if (!strncmp(str, "lcd_height:", 11)) { | ||
2023 | str += 11; | ||
2024 | where = &lcd_height; | ||
2025 | } | ||
2026 | else if (!strncmp(str, "lcd_width:", 10)) { | ||
2027 | str += 10; | ||
2028 | where = &lcd_width; | ||
2029 | } | ||
2030 | else if (!strncmp(str, "lcd_bwidth:", 11)) { | ||
2031 | str += 11; | ||
2032 | where = &lcd_bwidth; | ||
2033 | } | ||
2034 | else if (!strncmp(str, "lcd_hwidth:", 11)) { | ||
2035 | str += 11; | ||
2036 | where = &lcd_hwidth; | ||
2037 | } | ||
2038 | else if (!strncmp(str, "lcd_enabled:", 12)) { | ||
2039 | str += 12; | ||
2040 | where = &lcd_enabled; | ||
2041 | } | ||
2042 | else if (!strncmp(str, "keypad_enabled:", 15)) { | ||
2043 | str += 15; | ||
2044 | where = &keypad_enabled; | ||
2045 | } | ||
2046 | else if (!strncmp(str, "smartcard_enabled:", 18)) { | ||
2047 | str += 18; | ||
2048 | where = &smartcard_enabled; | ||
2049 | } | ||
2050 | else if (!strncmp(str, "profile:", 8)) { | ||
2051 | str += 8; | ||
2052 | where = &profile; | ||
2053 | } | ||
2054 | else if (!helpdisplayed) { | ||
2055 | helpdisplayed = 1; | ||
2056 | printk(KERN_ERR "Panel version " PANEL_VERSION ": invalid argument. Known arguments are :\n" | ||
2057 | " parport:, lcd_{height,width,bwidth,enabled}:, keypad_enabled:\n"); | ||
2058 | } | ||
2059 | |||
2060 | /* see if we need to read a number */ | ||
2061 | if (where != NULL) { | ||
2062 | dummy = 0; | ||
2063 | while (isdigit(*str)) { | ||
2064 | dummy = (dummy*10) + (*str - '0'); | ||
2065 | str++; | ||
2066 | } | ||
2067 | *where = dummy; | ||
2068 | } | ||
2069 | |||
2070 | /* look for next arg */ | ||
2071 | while (*str && (*str != ',')) | ||
2072 | str++; | ||
2073 | while (*str == ',') | ||
2074 | str++; | ||
2075 | } | ||
2076 | return 1; | ||
2077 | } | ||
2078 | |||
2079 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) | ||
2080 | __setup("panel=", panel_setup ); | ||
2081 | #else | ||
2082 | __setup("panel", panel_setup ); | ||
2083 | #endif | ||
2084 | |||
2085 | #endif /* !MODULE */ | ||
2086 | |||
2087 | static int panel_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { | ||
2088 | if (lcd_enabled && lcd_initialized) { | ||
2089 | switch(code) { | ||
2090 | case SYS_DOWN: | ||
2091 | panel_lcd_print("\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2092 | break; | ||
2093 | case SYS_HALT: | ||
2094 | panel_lcd_print("\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2095 | break; | ||
2096 | case SYS_POWER_OFF: | ||
2097 | panel_lcd_print("\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2098 | break; | ||
2099 | default: | ||
2100 | break; | ||
2101 | } | ||
2102 | } | ||
2103 | return NOTIFY_DONE; | ||
2104 | } | ||
2105 | |||
2106 | static struct notifier_block panel_notifier = { | ||
2107 | panel_notify_sys, | ||
2108 | NULL, | ||
2109 | 0 | ||
2110 | }; | ||
2111 | |||
2112 | |||
2113 | static void panel_attach (struct parport *port) | ||
2114 | { | ||
2115 | if (port->number != parport) | ||
2116 | return; | ||
2117 | |||
2118 | if (pprt) { | ||
2119 | printk(KERN_ERR "panel_attach(): port->number=%d parport=%d, already registered !\n", port->number, parport); | ||
2120 | return; | ||
2121 | } | ||
2122 | |||
2123 | pprt = parport_register_device(port, "panel", | ||
2124 | NULL, NULL, /* pf, kf */ | ||
2125 | NULL, | ||
2126 | /*PARPORT_DEV_EXCL*/ | ||
2127 | 0, | ||
2128 | (void *)&pprt); | ||
2129 | |||
2130 | if (parport_claim(pprt)) { | ||
2131 | printk(KERN_ERR "Panel: could not claim access to parport%d. Aborting.\n", parport); | ||
2132 | //parport_unregister_device(pprt); | ||
2133 | //parport_unregister_driver(&panel_driver); | ||
2134 | //return -EIO; | ||
2135 | return; | ||
2136 | } | ||
2137 | |||
2138 | /* turns IRQ off */ | ||
2139 | // port->ops->disable_irq(port); | ||
2140 | |||
2141 | /* must init LCD first, just in case an IRQ from the keypad is generated at keypad init */ | ||
2142 | if (lcd_enabled) { | ||
2143 | lcd_init(); | ||
2144 | misc_register( &lcd_dev ); | ||
2145 | } | ||
2146 | |||
2147 | if (keypad_enabled) { | ||
2148 | keypad_init(); | ||
2149 | misc_register( &keypad_dev ); | ||
2150 | } | ||
2151 | |||
2152 | if (smartcard_enabled) { | ||
2153 | smartcard_init(); | ||
2154 | misc_register( &smartcard_dev ); | ||
2155 | } | ||
2156 | } | ||
2157 | |||
2158 | static void panel_detach (struct parport *port) | ||
2159 | { | ||
2160 | if (port->number != parport) | ||
2161 | return; | ||
2162 | |||
2163 | if (!pprt) { | ||
2164 | printk(KERN_ERR "panel_detach(): port->number=%d parport=%d, nothing to unregister.\n", | ||
2165 | port->number, parport); | ||
2166 | return; | ||
2167 | } | ||
2168 | |||
2169 | if (smartcard_enabled && smartcard_initialized) { | ||
2170 | misc_deregister( &smartcard_dev ); | ||
2171 | } | ||
2172 | |||
2173 | if (keypad_enabled && keypad_initialized) { | ||
2174 | misc_deregister( &keypad_dev ); | ||
2175 | } | ||
2176 | |||
2177 | if (lcd_enabled && lcd_initialized) { | ||
2178 | misc_deregister( &lcd_dev ); | ||
2179 | } | ||
2180 | |||
2181 | parport_release(pprt); | ||
2182 | parport_unregister_device(pprt); | ||
2183 | pprt = NULL; | ||
2184 | } | ||
2185 | |||
2186 | static struct parport_driver panel_driver = { | ||
2187 | .name = "panel", | ||
2188 | .attach = panel_attach, | ||
2189 | .detach = panel_detach, | ||
2190 | }; | ||
2191 | |||
2192 | /* init function */ | ||
2193 | int panel_init (void) { | ||
2194 | /* for backwards compatibility */ | ||
2195 | if (keypad_type < 0) | ||
2196 | keypad_type = keypad_enabled; | ||
2197 | |||
2198 | if (lcd_type < 0) | ||
2199 | lcd_type = lcd_enabled; | ||
2200 | |||
2201 | if (parport < 0) | ||
2202 | parport = DEFAULT_PARPORT; | ||
2203 | |||
2204 | /* take care of an eventual profile */ | ||
2205 | switch (profile) { | ||
2206 | case PANEL_PROFILE_CUSTOM: /* custom profile */ | ||
2207 | if (keypad_type < 0) keypad_type = DEFAULT_KEYPAD; | ||
2208 | if (smartcard_enabled < 0) smartcard_enabled = DEFAULT_SMARTCARD; | ||
2209 | if (lcd_type < 0) lcd_type = DEFAULT_LCD; | ||
2210 | break; | ||
2211 | case PANEL_PROFILE_OLD: /* 8 bits, 2*16, old keypad */ | ||
2212 | if (keypad_type < 0) keypad_type = KEYPAD_TYPE_OLD; | ||
2213 | if (smartcard_enabled < 0) smartcard_enabled = 0; | ||
2214 | if (lcd_type < 0) lcd_type = LCD_TYPE_OLD; | ||
2215 | if (lcd_width < 0) lcd_width = 16; | ||
2216 | if (lcd_hwidth < 0) lcd_hwidth = 16; | ||
2217 | break; | ||
2218 | case PANEL_PROFILE_NEW: /* serial, 2*16, new keypad */ | ||
2219 | if (keypad_type < 0) keypad_type = KEYPAD_TYPE_NEW; | ||
2220 | if (smartcard_enabled < 0) smartcard_enabled = 1; | ||
2221 | if (lcd_type < 0) lcd_type = LCD_TYPE_KS0074; | ||
2222 | break; | ||
2223 | case PANEL_PROFILE_HANTRONIX: /* 8 bits, 2*16 hantronix-like, no keypad */ | ||
2224 | if (keypad_type < 0) keypad_type = KEYPAD_TYPE_NONE; | ||
2225 | if (smartcard_enabled < 0) smartcard_enabled = 0; | ||
2226 | if (lcd_type < 0) lcd_type = LCD_TYPE_HANTRONIX; | ||
2227 | break; | ||
2228 | case PANEL_PROFILE_NEXCOM: /* generic 8 bits, 2*16, nexcom keypad, eg. Nexcom. */ | ||
2229 | if (keypad_type < 0) keypad_type = KEYPAD_TYPE_NEXCOM; | ||
2230 | if (smartcard_enabled < 0) smartcard_enabled = 0; | ||
2231 | if (lcd_type < 0) lcd_type = LCD_TYPE_NEXCOM; | ||
2232 | break; | ||
2233 | case PANEL_PROFILE_LARGE: /* 8 bits, 2*40, old keypad */ | ||
2234 | if (keypad_type < 0) keypad_type = KEYPAD_TYPE_OLD; | ||
2235 | if (smartcard_enabled < 0) smartcard_enabled = 0; | ||
2236 | if (lcd_type < 0) lcd_type = LCD_TYPE_OLD; | ||
2237 | break; | ||
2238 | } | ||
2239 | |||
2240 | lcd_enabled = (lcd_type > 0); | ||
2241 | keypad_enabled = (keypad_type > 0); | ||
2242 | |||
2243 | switch (keypad_type) { | ||
2244 | case KEYPAD_TYPE_OLD: | ||
2245 | keypad_profile = old_keypad_profile; | ||
2246 | break; | ||
2247 | case KEYPAD_TYPE_NEW: | ||
2248 | keypad_profile = new_keypad_profile; | ||
2249 | break; | ||
2250 | case KEYPAD_TYPE_NEXCOM: | ||
2251 | keypad_profile = nexcom_keypad_profile; | ||
2252 | break; | ||
2253 | default: | ||
2254 | keypad_profile = NULL; | ||
2255 | break; | ||
2256 | } | ||
2257 | |||
2258 | /* tells various subsystems about the fact that we are initializing */ | ||
2259 | init_in_progress = 1; | ||
2260 | |||
2261 | if (parport_register_driver(&panel_driver)) { | ||
2262 | printk(KERN_ERR "Panel: could not register with parport. Aborting.\n"); | ||
2263 | return -EIO; | ||
2264 | } | ||
2265 | |||
2266 | // The parport can be asynchronously registered later. | ||
2267 | //if (pprt == NULL) { | ||
2268 | // printk(KERN_ERR "Panel: could not register parport%d. Aborting.\n", parport); | ||
2269 | // parport_unregister_driver(&panel_driver); | ||
2270 | // return -ENODEV; /* port not found */ | ||
2271 | //} | ||
2272 | |||
2273 | |||
2274 | if (!lcd_enabled && !keypad_enabled && !smartcard_enabled) { /* no device enabled, let's release the parport */ | ||
2275 | if (pprt) { | ||
2276 | parport_release(pprt); | ||
2277 | parport_unregister_device(pprt); | ||
2278 | } | ||
2279 | parport_unregister_driver(&panel_driver); | ||
2280 | printk(KERN_ERR "Panel driver version " PANEL_VERSION " disabled.\n"); | ||
2281 | return -ENODEV; | ||
2282 | } | ||
2283 | |||
2284 | register_reboot_notifier(&panel_notifier); | ||
2285 | |||
2286 | if (pprt) | ||
2287 | printk(KERN_INFO "Panel driver version " PANEL_VERSION " registered on parport%d (io=0x%lx).\n", | ||
2288 | parport, pprt->port->base); | ||
2289 | else | ||
2290 | printk(KERN_INFO "Panel driver version " PANEL_VERSION " not yet registered\n"); | ||
2291 | /* tells various subsystems about the fact that initialization is finished */ | ||
2292 | init_in_progress = 0; | ||
2293 | return 0; | ||
2294 | } | ||
2295 | |||
2296 | |||
2297 | #if defined(MODULE) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) | ||
2298 | INIT_FUNC (void) { | ||
2299 | return panel_init(); | ||
2300 | } | ||
2301 | |||
2302 | CLEANUP_FUNC (void) { | ||
2303 | unregister_reboot_notifier(&panel_notifier); | ||
2304 | |||
2305 | if (scan_timer.function != NULL) { | ||
2306 | del_timer(&scan_timer); | ||
2307 | } | ||
2308 | |||
2309 | if (keypad_enabled) { | ||
2310 | misc_deregister( &keypad_dev ); | ||
2311 | } | ||
2312 | |||
2313 | if (smartcard_enabled) { | ||
2314 | misc_deregister( &smartcard_dev ); | ||
2315 | } | ||
2316 | |||
2317 | if (lcd_enabled) { | ||
2318 | panel_lcd_print("\x0cLCD driver " PANEL_VERSION "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-"); | ||
2319 | misc_deregister( &lcd_dev ); | ||
2320 | } | ||
2321 | |||
2322 | /* TODO: free all input signals */ | ||
2323 | |||
2324 | parport_release(pprt); | ||
2325 | parport_unregister_device(pprt); | ||
2326 | parport_unregister_driver(&panel_driver); | ||
2327 | } | ||
2328 | #endif | ||
2329 | |||
2330 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) | ||
2331 | module_init(panel_init_module); | ||
2332 | module_exit(panel_cleanup_module); | ||
2333 | MODULE_AUTHOR("Willy Tarreau"); | ||
2334 | MODULE_LICENSE("GPL"); | ||
2335 | #endif | ||
2336 | |||
2337 | /* | ||
2338 | * Local variables: | ||
2339 | * c-indent-level: 4 | ||
2340 | * tab-width: 8 | ||
2341 | * End: | ||
2342 | */ | ||
2343 | |||