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