1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
70
71#define KEYPAD_BUFFER 64
72
73
74#define INPUT_POLL_TIME (HZ/50)
75
76#define KEYPAD_REP_START (10)
77
78#define KEYPAD_REP_DELAY (2)
79
80
81#define FLASH_LIGHT_TEMPO (200)
82
83
84#define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3)
85
86#define PNL_PBUSY 0x80
87#define PNL_PACK 0x40
88#define PNL_POUTPA 0x20
89#define PNL_PSELECD 0x10
90#define PNL_PERRORP 0x08
91
92#define PNL_PBIDIR 0x20
93
94#define PNL_PINTEN 0x10
95#define PNL_PSELECP 0x08
96#define PNL_PINITP 0x04
97#define PNL_PAUTOLF 0x02
98#define PNL_PSTROBE 0x01
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
127#define LCD_FLAG_C 0x0008
128#define LCD_FLAG_D 0x0010
129#define LCD_FLAG_F 0x0020
130#define LCD_FLAG_N 0x0040
131#define LCD_FLAG_L 0x0080
132
133#define LCD_ESCAPE_LEN 24
134#define LCD_ESCAPE_CHAR 27
135
136
137#define r_ctr(x) (parport_read_control((x)->port))
138#define r_dtr(x) (parport_read_data((x)->port))
139#define r_str(x) (parport_read_status((x)->port))
140#define w_ctr(x, y) (parport_write_control((x)->port, (y)))
141#define w_dtr(x, y) (parport_write_data((x)->port, (y)))
142
143
144
145static __u8 scan_mask_o;
146
147static __u8 scan_mask_i;
148
149typedef __u64 pmask_t;
150
151enum input_type {
152 INPUT_TYPE_STD,
153 INPUT_TYPE_KBD,
154};
155
156enum input_state {
157 INPUT_ST_LOW,
158 INPUT_ST_RISING,
159 INPUT_ST_HIGH,
160 INPUT_ST_FALLING,
161};
162
163struct logical_input {
164 struct list_head list;
165 pmask_t mask;
166 pmask_t value;
167 enum input_type type;
168 enum input_state state;
169 __u8 rise_time, fall_time;
170 __u8 rise_timer, fall_timer, high_timer;
171
172 union {
173 struct {
174 void (*press_fct) (int);
175 void (*release_fct) (int);
176 int press_data;
177 int release_data;
178 } std;
179 struct {
180
181 char press_str[sizeof(void *) + sizeof(int)];
182 char repeat_str[sizeof(void *) + sizeof(int)];
183 char release_str[sizeof(void *) + sizeof(int)];
184 } kbd;
185 } u;
186};
187
188static LIST_HEAD(logical_inputs);
189
190
191
192
193
194
195
196
197
198
199
200
201
202static pmask_t phys_read;
203
204static pmask_t phys_read_prev;
205
206static pmask_t phys_curr;
207
208static pmask_t phys_prev;
209
210static char inputs_stable;
211
212
213static char keypad_buffer[KEYPAD_BUFFER];
214static int keypad_buflen;
215static int keypad_start;
216static char keypressed;
217static wait_queue_head_t keypad_read_wait;
218
219
220
221
222static unsigned long int lcd_flags;
223
224static unsigned long int lcd_addr_x;
225
226static unsigned long int lcd_addr_y;
227
228static char lcd_escape[LCD_ESCAPE_LEN + 1];
229
230static int lcd_escape_len = -1;
231
232
233
234
235
236
237#define BIT_CLR 0
238#define BIT_SET 1
239#define BIT_MSK 2
240#define BIT_STATES 3
241
242
243
244#define LCD_BIT_E 0
245#define LCD_BIT_RS 1
246#define LCD_BIT_RW 2
247#define LCD_BIT_BL 3
248#define LCD_BIT_CL 4
249#define LCD_BIT_DA 5
250#define LCD_BITS 6
251
252
253
254
255#define LCD_PORT_C 0
256#define LCD_PORT_D 1
257#define LCD_PORTS 2
258
259static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES];
260
261
262
263
264#define LCD_PROTO_PARALLEL 0
265#define LCD_PROTO_SERIAL 1
266#define LCD_PROTO_TI_DA8XX_LCD 2
267
268
269
270
271#define LCD_CHARSET_NORMAL 0
272#define LCD_CHARSET_KS0074 1
273
274
275
276
277#define LCD_TYPE_NONE 0
278#define LCD_TYPE_OLD 1
279#define LCD_TYPE_KS0074 2
280#define LCD_TYPE_HANTRONIX 3
281#define LCD_TYPE_NEXCOM 4
282#define LCD_TYPE_CUSTOM 5
283
284
285
286
287#define KEYPAD_TYPE_NONE 0
288#define KEYPAD_TYPE_OLD 1
289#define KEYPAD_TYPE_NEW 2
290#define KEYPAD_TYPE_NEXCOM 3
291
292
293
294
295#define PANEL_PROFILE_CUSTOM 0
296#define PANEL_PROFILE_OLD 1
297#define PANEL_PROFILE_NEW 2
298#define PANEL_PROFILE_HANTRONIX 3
299#define PANEL_PROFILE_NEXCOM 4
300#define PANEL_PROFILE_LARGE 5
301
302
303
304
305#define DEFAULT_PROFILE PANEL_PROFILE_LARGE
306#define DEFAULT_PARPORT 0
307#define DEFAULT_LCD LCD_TYPE_OLD
308#define DEFAULT_KEYPAD KEYPAD_TYPE_OLD
309#define DEFAULT_LCD_WIDTH 40
310#define DEFAULT_LCD_BWIDTH 40
311#define DEFAULT_LCD_HWIDTH 64
312#define DEFAULT_LCD_HEIGHT 2
313#define DEFAULT_LCD_PROTO LCD_PROTO_PARALLEL
314
315#define DEFAULT_LCD_PIN_E PIN_AUTOLF
316#define DEFAULT_LCD_PIN_RS PIN_SELECP
317#define DEFAULT_LCD_PIN_RW PIN_INITP
318#define DEFAULT_LCD_PIN_SCL PIN_STROBE
319#define DEFAULT_LCD_PIN_SDA PIN_D0
320#define DEFAULT_LCD_PIN_BL PIN_NOT_SET
321#define DEFAULT_LCD_CHARSET LCD_CHARSET_NORMAL
322
323#ifdef CONFIG_PANEL_PROFILE
324#undef DEFAULT_PROFILE
325#define DEFAULT_PROFILE CONFIG_PANEL_PROFILE
326#endif
327
328#ifdef CONFIG_PANEL_PARPORT
329#undef DEFAULT_PARPORT
330#define DEFAULT_PARPORT CONFIG_PANEL_PARPORT
331#endif
332
333#if DEFAULT_PROFILE == 0
334#ifdef CONFIG_PANEL_KEYPAD
335#undef DEFAULT_KEYPAD
336#define DEFAULT_KEYPAD CONFIG_PANEL_KEYPAD
337#endif
338
339#ifdef CONFIG_PANEL_LCD
340#undef DEFAULT_LCD
341#define DEFAULT_LCD CONFIG_PANEL_LCD
342#endif
343
344#ifdef CONFIG_PANEL_LCD_WIDTH
345#undef DEFAULT_LCD_WIDTH
346#define DEFAULT_LCD_WIDTH CONFIG_PANEL_LCD_WIDTH
347#endif
348
349#ifdef CONFIG_PANEL_LCD_BWIDTH
350#undef DEFAULT_LCD_BWIDTH
351#define DEFAULT_LCD_BWIDTH CONFIG_PANEL_LCD_BWIDTH
352#endif
353
354#ifdef CONFIG_PANEL_LCD_HWIDTH
355#undef DEFAULT_LCD_HWIDTH
356#define DEFAULT_LCD_HWIDTH CONFIG_PANEL_LCD_HWIDTH
357#endif
358
359#ifdef CONFIG_PANEL_LCD_HEIGHT
360#undef DEFAULT_LCD_HEIGHT
361#define DEFAULT_LCD_HEIGHT CONFIG_PANEL_LCD_HEIGHT
362#endif
363
364#ifdef CONFIG_PANEL_LCD_PROTO
365#undef DEFAULT_LCD_PROTO
366#define DEFAULT_LCD_PROTO CONFIG_PANEL_LCD_PROTO
367#endif
368
369#ifdef CONFIG_PANEL_LCD_PIN_E
370#undef DEFAULT_LCD_PIN_E
371#define DEFAULT_LCD_PIN_E CONFIG_PANEL_LCD_PIN_E
372#endif
373
374#ifdef CONFIG_PANEL_LCD_PIN_RS
375#undef DEFAULT_LCD_PIN_RS
376#define DEFAULT_LCD_PIN_RS CONFIG_PANEL_LCD_PIN_RS
377#endif
378
379#ifdef CONFIG_PANEL_LCD_PIN_RW
380#undef DEFAULT_LCD_PIN_RW
381#define DEFAULT_LCD_PIN_RW CONFIG_PANEL_LCD_PIN_RW
382#endif
383
384#ifdef CONFIG_PANEL_LCD_PIN_SCL
385#undef DEFAULT_LCD_PIN_SCL
386#define DEFAULT_LCD_PIN_SCL CONFIG_PANEL_LCD_PIN_SCL
387#endif
388
389#ifdef CONFIG_PANEL_LCD_PIN_SDA
390#undef DEFAULT_LCD_PIN_SDA
391#define DEFAULT_LCD_PIN_SDA CONFIG_PANEL_LCD_PIN_SDA
392#endif
393
394#ifdef CONFIG_PANEL_LCD_PIN_BL
395#undef DEFAULT_LCD_PIN_BL
396#define DEFAULT_LCD_PIN_BL CONFIG_PANEL_LCD_PIN_BL
397#endif
398
399#ifdef CONFIG_PANEL_LCD_CHARSET
400#undef DEFAULT_LCD_CHARSET
401#define DEFAULT_LCD_CHARSET CONFIG_PANEL_LCD_CHARSET
402#endif
403
404#endif
405
406
407static int keypad_open_cnt;
408static int lcd_open_cnt;
409static struct pardevice *pprt;
410
411static int lcd_initialized;
412static int keypad_initialized;
413
414static int light_tempo;
415
416static char lcd_must_clear;
417static char lcd_left_shift;
418static char init_in_progress;
419
420static void (*lcd_write_cmd) (int);
421static void (*lcd_write_data) (int);
422static void (*lcd_clear_fast) (void);
423
424static DEFINE_SPINLOCK(pprt_lock);
425static struct timer_list scan_timer;
426
427MODULE_DESCRIPTION("Generic parallel port LCD/Keypad driver");
428
429static int parport = -1;
430module_param(parport, int, 0000);
431MODULE_PARM_DESC(parport, "Parallel port index (0=lpt1, 1=lpt2, ...)");
432
433static int lcd_height = -1;
434module_param(lcd_height, int, 0000);
435MODULE_PARM_DESC(lcd_height, "Number of lines on the LCD");
436
437static int lcd_width = -1;
438module_param(lcd_width, int, 0000);
439MODULE_PARM_DESC(lcd_width, "Number of columns on the LCD");
440
441static int lcd_bwidth = -1;
442module_param(lcd_bwidth, int, 0000);
443MODULE_PARM_DESC(lcd_bwidth, "Internal LCD line width (40)");
444
445static int lcd_hwidth = -1;
446module_param(lcd_hwidth, int, 0000);
447MODULE_PARM_DESC(lcd_hwidth, "LCD line hardware address (64)");
448
449static int lcd_enabled = -1;
450module_param(lcd_enabled, int, 0000);
451MODULE_PARM_DESC(lcd_enabled, "Deprecated option, use lcd_type instead");
452
453static int keypad_enabled = -1;
454module_param(keypad_enabled, int, 0000);
455MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead");
456
457static int lcd_type = -1;
458module_param(lcd_type, int, 0000);
459MODULE_PARM_DESC(lcd_type,
460 "LCD type: 0=none, 1=old //, 2=serial ks0074, "
461 "3=hantronix //, 4=nexcom //, 5=compiled-in");
462
463static int lcd_proto = -1;
464module_param(lcd_proto, int, 0000);
465MODULE_PARM_DESC(lcd_proto,
466 "LCD communication: 0=parallel (//), 1=serial,"
467 "2=TI LCD Interface");
468
469static int lcd_charset = -1;
470module_param(lcd_charset, int, 0000);
471MODULE_PARM_DESC(lcd_charset, "LCD character set: 0=standard, 1=KS0074");
472
473static int keypad_type = -1;
474module_param(keypad_type, int, 0000);
475MODULE_PARM_DESC(keypad_type,
476 "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, "
477 "3=nexcom 4 keys");
478
479static int profile = DEFAULT_PROFILE;
480module_param(profile, int, 0000);
481MODULE_PARM_DESC(profile,
482 "1=16x2 old kp; 2=serial 16x2, new kp; 3=16x2 hantronix; "
483 "4=16x2 nexcom; default=40x2, old kp");
484
485
486
487
488
489
490
491
492
493
494static int lcd_e_pin = PIN_NOT_SET;
495module_param(lcd_e_pin, int, 0000);
496MODULE_PARM_DESC(lcd_e_pin,
497 "# of the // port pin connected to LCD 'E' signal, "
498 "with polarity (-17..17)");
499
500static int lcd_rs_pin = PIN_NOT_SET;
501module_param(lcd_rs_pin, int, 0000);
502MODULE_PARM_DESC(lcd_rs_pin,
503 "# of the // port pin connected to LCD 'RS' signal, "
504 "with polarity (-17..17)");
505
506static int lcd_rw_pin = PIN_NOT_SET;
507module_param(lcd_rw_pin, int, 0000);
508MODULE_PARM_DESC(lcd_rw_pin,
509 "# of the // port pin connected to LCD 'RW' signal, "
510 "with polarity (-17..17)");
511
512static int lcd_bl_pin = PIN_NOT_SET;
513module_param(lcd_bl_pin, int, 0000);
514MODULE_PARM_DESC(lcd_bl_pin,
515 "# of the // port pin connected to LCD backlight, "
516 "with polarity (-17..17)");
517
518static int lcd_da_pin = PIN_NOT_SET;
519module_param(lcd_da_pin, int, 0000);
520MODULE_PARM_DESC(lcd_da_pin,
521 "# of the // port pin connected to serial LCD 'SDA' "
522 "signal, with polarity (-17..17)");
523
524static int lcd_cl_pin = PIN_NOT_SET;
525module_param(lcd_cl_pin, int, 0000);
526MODULE_PARM_DESC(lcd_cl_pin,
527 "# of the // port pin connected to serial LCD 'SCL' "
528 "signal, with polarity (-17..17)");
529
530static const unsigned char *lcd_char_conv;
531
532
533static const unsigned char lcd_char_conv_ks0074[256] = {
534
535 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
536 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
537 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
538 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
539 0x20, 0x21, 0x22, 0x23, 0xa2, 0x25, 0x26, 0x27,
540 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
541 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
542 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
543 0xa0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
544 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
545 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
546 0x58, 0x59, 0x5a, 0xfa, 0xfb, 0xfc, 0x1d, 0xc4,
547 0x96, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
548 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
549 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
550 0x78, 0x79, 0x7a, 0xfd, 0xfe, 0xff, 0xce, 0x20,
551 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
552 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
553 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
554 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
555 0x20, 0x40, 0xb1, 0xa1, 0x24, 0xa3, 0xfe, 0x5f,
556 0x22, 0xc8, 0x61, 0x14, 0x97, 0x2d, 0xad, 0x96,
557 0x80, 0x8c, 0x82, 0x83, 0x27, 0x8f, 0x86, 0xdd,
558 0x2c, 0x81, 0x6f, 0x15, 0x8b, 0x8a, 0x84, 0x60,
559 0xe2, 0xe2, 0xe2, 0x5b, 0x5b, 0xae, 0xbc, 0xa9,
560 0xc5, 0xbf, 0xc6, 0xf1, 0xe3, 0xe3, 0xe3, 0xe3,
561 0x44, 0x5d, 0xa8, 0xe4, 0xec, 0xec, 0x5c, 0x78,
562 0xab, 0xa6, 0xe5, 0x5e, 0x5e, 0xe6, 0xaa, 0xbe,
563 0x7f, 0xe7, 0xaf, 0x7b, 0x7b, 0xaf, 0xbd, 0xc8,
564 0xa4, 0xa5, 0xc7, 0xf6, 0xa7, 0xe8, 0x69, 0x69,
565 0xed, 0x7d, 0xa8, 0xe4, 0xec, 0x5c, 0x5c, 0x25,
566 0xac, 0xa6, 0xea, 0xef, 0x7e, 0xeb, 0xb2, 0x79,
567};
568
569static const char old_keypad_profile[][4][9] = {
570 {"S0", "Left\n", "Left\n", ""},
571 {"S1", "Down\n", "Down\n", ""},
572 {"S2", "Up\n", "Up\n", ""},
573 {"S3", "Right\n", "Right\n", ""},
574 {"S4", "Esc\n", "Esc\n", ""},
575 {"S5", "Ret\n", "Ret\n", ""},
576 {"", "", "", ""}
577};
578
579
580static const char new_keypad_profile[][4][9] = {
581 {"S0", "Left\n", "Left\n", ""},
582 {"S1", "Down\n", "Down\n", ""},
583 {"S2", "Up\n", "Up\n", ""},
584 {"S3", "Right\n", "Right\n", ""},
585 {"S4s5", "", "Esc\n", "Esc\n"},
586 {"s4S5", "", "Ret\n", "Ret\n"},
587 {"S4S5", "Help\n", "", ""},
588
589 {"", "", "", ""}
590};
591
592
593static const char nexcom_keypad_profile[][4][9] = {
594 {"a-p-e-", "Down\n", "Down\n", ""},
595 {"a-p-E-", "Ret\n", "Ret\n", ""},
596 {"a-P-E-", "Esc\n", "Esc\n", ""},
597 {"a-P-e-", "Up\n", "Up\n", ""},
598
599 {"", "", "", ""}
600};
601
602static const char (*keypad_profile)[4][9] = old_keypad_profile;
603
604
605static struct {
606 unsigned char e;
607 unsigned char rs;
608 unsigned char rw;
609 unsigned char bl;
610 unsigned char cl;
611 unsigned char da;
612} bits;
613
614static void init_scan_timer(void);
615
616
617static int set_data_bits(void)
618{
619 int val, bit;
620
621 val = r_dtr(pprt);
622 for (bit = 0; bit < LCD_BITS; bit++)
623 val &= lcd_bits[LCD_PORT_D][bit][BIT_MSK];
624
625 val |= lcd_bits[LCD_PORT_D][LCD_BIT_E][bits.e]
626 | lcd_bits[LCD_PORT_D][LCD_BIT_RS][bits.rs]
627 | lcd_bits[LCD_PORT_D][LCD_BIT_RW][bits.rw]
628 | lcd_bits[LCD_PORT_D][LCD_BIT_BL][bits.bl]
629 | lcd_bits[LCD_PORT_D][LCD_BIT_CL][bits.cl]
630 | lcd_bits[LCD_PORT_D][LCD_BIT_DA][bits.da];
631
632 w_dtr(pprt, val);
633 return val;
634}
635
636
637static int set_ctrl_bits(void)
638{
639 int val, bit;
640
641 val = r_ctr(pprt);
642 for (bit = 0; bit < LCD_BITS; bit++)
643 val &= lcd_bits[LCD_PORT_C][bit][BIT_MSK];
644
645 val |= lcd_bits[LCD_PORT_C][LCD_BIT_E][bits.e]
646 | lcd_bits[LCD_PORT_C][LCD_BIT_RS][bits.rs]
647 | lcd_bits[LCD_PORT_C][LCD_BIT_RW][bits.rw]
648 | lcd_bits[LCD_PORT_C][LCD_BIT_BL][bits.bl]
649 | lcd_bits[LCD_PORT_C][LCD_BIT_CL][bits.cl]
650 | lcd_bits[LCD_PORT_C][LCD_BIT_DA][bits.da];
651
652 w_ctr(pprt, val);
653 return val;
654}
655
656
657static void panel_set_bits(void)
658{
659 set_data_bits();
660 set_ctrl_bits();
661}
662
663
664
665
666
667
668
669
670
671
672static void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val)
673{
674 int d_bit, c_bit, inv;
675
676 d_val[0] = c_val[0] = d_val[1] = c_val[1] = 0;
677 d_val[2] = c_val[2] = 0xFF;
678
679 if (pin == 0)
680 return;
681
682 inv = (pin < 0);
683 if (inv)
684 pin = -pin;
685
686 d_bit = c_bit = 0;
687
688 switch (pin) {
689 case PIN_STROBE:
690 c_bit = PNL_PSTROBE;
691 inv = !inv;
692 break;
693 case PIN_D0...PIN_D7:
694 d_bit = 1 << (pin - 2);
695 break;
696 case PIN_AUTOLF:
697 c_bit = PNL_PAUTOLF;
698 inv = !inv;
699 break;
700 case PIN_INITP:
701 c_bit = PNL_PINITP;
702 break;
703 case PIN_SELECP:
704 c_bit = PNL_PSELECP;
705 inv = !inv;
706 break;
707 default:
708 break;
709 }
710
711 if (c_bit) {
712 c_val[2] &= ~c_bit;
713 c_val[!inv] = c_bit;
714 } else if (d_bit) {
715 d_val[2] &= ~d_bit;
716 d_val[!inv] = d_bit;
717 }
718}
719
720
721static void long_sleep(int ms)
722{
723
724 if (in_interrupt())
725 mdelay(ms);
726 else {
727 current->state = TASK_INTERRUPTIBLE;
728 schedule_timeout((ms * HZ + 999) / 1000);
729 }
730}
731
732
733
734static void lcd_send_serial(int byte)
735{
736 int bit;
737
738
739
740 for (bit = 0; bit < 8; bit++) {
741 bits.cl = BIT_CLR;
742 panel_set_bits();
743 bits.da = byte & 1;
744 panel_set_bits();
745 udelay(2);
746 bits.cl = BIT_SET;
747 panel_set_bits();
748 udelay(1);
749 byte >>= 1;
750 }
751}
752
753
754static void lcd_backlight(int on)
755{
756 if (lcd_bl_pin == PIN_NONE)
757 return;
758
759
760 spin_lock_irq(&pprt_lock);
761 bits.bl = on;
762 panel_set_bits();
763 spin_unlock_irq(&pprt_lock);
764}
765
766
767static void lcd_write_cmd_s(int cmd)
768{
769 spin_lock_irq(&pprt_lock);
770 lcd_send_serial(0x1F);
771 lcd_send_serial(cmd & 0x0F);
772 lcd_send_serial((cmd >> 4) & 0x0F);
773 udelay(40);
774 spin_unlock_irq(&pprt_lock);
775}
776
777
778static void lcd_write_data_s(int data)
779{
780 spin_lock_irq(&pprt_lock);
781 lcd_send_serial(0x5F);
782 lcd_send_serial(data & 0x0F);
783 lcd_send_serial((data >> 4) & 0x0F);
784 udelay(40);
785 spin_unlock_irq(&pprt_lock);
786}
787
788
789static void lcd_write_cmd_p8(int cmd)
790{
791 spin_lock_irq(&pprt_lock);
792
793 w_dtr(pprt, cmd);
794 udelay(20);
795
796 bits.e = BIT_SET;
797 bits.rs = BIT_CLR;
798 bits.rw = BIT_CLR;
799 set_ctrl_bits();
800
801 udelay(40);
802
803 bits.e = BIT_CLR;
804 set_ctrl_bits();
805
806 udelay(120);
807 spin_unlock_irq(&pprt_lock);
808}
809
810
811static void lcd_write_data_p8(int data)
812{
813 spin_lock_irq(&pprt_lock);
814
815 w_dtr(pprt, data);
816 udelay(20);
817
818 bits.e = BIT_SET;
819 bits.rs = BIT_SET;
820 bits.rw = BIT_CLR;
821 set_ctrl_bits();
822
823 udelay(40);
824
825 bits.e = BIT_CLR;
826 set_ctrl_bits();
827
828 udelay(45);
829 spin_unlock_irq(&pprt_lock);
830}
831
832
833static void lcd_write_cmd_tilcd(int cmd)
834{
835 spin_lock_irq(&pprt_lock);
836
837 w_ctr(pprt, cmd);
838 udelay(60);
839 spin_unlock_irq(&pprt_lock);
840}
841
842
843static void lcd_write_data_tilcd(int data)
844{
845 spin_lock_irq(&pprt_lock);
846
847 w_dtr(pprt, data);
848 udelay(60);
849 spin_unlock_irq(&pprt_lock);
850}
851
852static void lcd_gotoxy(void)
853{
854 lcd_write_cmd(0x80
855 | (lcd_addr_y ? lcd_hwidth : 0)
856
857
858 | ((lcd_addr_x < lcd_bwidth) ? lcd_addr_x &
859 (lcd_hwidth - 1) : lcd_bwidth - 1));
860}
861
862static void lcd_print(char c)
863{
864 if (lcd_addr_x < lcd_bwidth) {
865 if (lcd_char_conv != NULL)
866 c = lcd_char_conv[(unsigned char)c];
867 lcd_write_data(c);
868 lcd_addr_x++;
869 }
870
871 if (lcd_addr_x == lcd_bwidth)
872 lcd_gotoxy();
873}
874
875
876static void lcd_clear_fast_s(void)
877{
878 int pos;
879 lcd_addr_x = lcd_addr_y = 0;
880 lcd_gotoxy();
881
882 spin_lock_irq(&pprt_lock);
883 for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) {
884 lcd_send_serial(0x5F);
885 lcd_send_serial(' ' & 0x0F);
886 lcd_send_serial((' ' >> 4) & 0x0F);
887 udelay(40);
888 }
889 spin_unlock_irq(&pprt_lock);
890
891 lcd_addr_x = lcd_addr_y = 0;
892 lcd_gotoxy();
893}
894
895
896static void lcd_clear_fast_p8(void)
897{
898 int pos;
899 lcd_addr_x = lcd_addr_y = 0;
900 lcd_gotoxy();
901
902 spin_lock_irq(&pprt_lock);
903 for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) {
904
905 w_dtr(pprt, ' ');
906
907
908 udelay(20);
909
910 bits.e = BIT_SET;
911 bits.rs = BIT_SET;
912 bits.rw = BIT_CLR;
913 set_ctrl_bits();
914
915
916 udelay(40);
917
918 bits.e = BIT_CLR;
919 set_ctrl_bits();
920
921
922 udelay(45);
923 }
924 spin_unlock_irq(&pprt_lock);
925
926 lcd_addr_x = lcd_addr_y = 0;
927 lcd_gotoxy();
928}
929
930
931static void lcd_clear_fast_tilcd(void)
932{
933 int pos;
934 lcd_addr_x = lcd_addr_y = 0;
935 lcd_gotoxy();
936
937 spin_lock_irq(&pprt_lock);
938 for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) {
939
940 w_dtr(pprt, ' ');
941 udelay(60);
942 }
943
944 spin_unlock_irq(&pprt_lock);
945
946 lcd_addr_x = lcd_addr_y = 0;
947 lcd_gotoxy();
948}
949
950
951static void lcd_clear_display(void)
952{
953 lcd_write_cmd(0x01);
954 lcd_addr_x = lcd_addr_y = 0;
955
956 long_sleep(15);
957}
958
959static void lcd_init_display(void)
960{
961
962 lcd_flags = ((lcd_height > 1) ? LCD_FLAG_N : 0)
963 | LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B;
964
965 long_sleep(20);
966
967 lcd_write_cmd(0x30);
968 long_sleep(10);
969 lcd_write_cmd(0x30);
970 long_sleep(10);
971 lcd_write_cmd(0x30);
972 long_sleep(10);
973
974 lcd_write_cmd(0x30
975 | ((lcd_flags & LCD_FLAG_F) ? 4 : 0)
976 | ((lcd_flags & LCD_FLAG_N) ? 8 : 0)
977 );
978 long_sleep(10);
979
980 lcd_write_cmd(0x08);
981 long_sleep(10);
982
983 lcd_write_cmd(0x08
984 | ((lcd_flags & LCD_FLAG_D) ? 4 : 0)
985 | ((lcd_flags & LCD_FLAG_C) ? 2 : 0)
986 | ((lcd_flags & LCD_FLAG_B) ? 1 : 0)
987 );
988
989 lcd_backlight((lcd_flags & LCD_FLAG_L) ? 1 : 0);
990
991 long_sleep(10);
992
993
994 lcd_write_cmd(0x06);
995
996 lcd_clear_display();
997}
998
999
1000
1001
1002
1003
1004
1005
1006static inline int handle_lcd_special_code(void)
1007{
1008
1009
1010 int processed = 0;
1011
1012 char *esc = lcd_escape + 2;
1013 int oldflags = lcd_flags;
1014
1015
1016 switch (*esc) {
1017 case 'D':
1018 lcd_flags |= LCD_FLAG_D;
1019 processed = 1;
1020 break;
1021 case 'd':
1022 lcd_flags &= ~LCD_FLAG_D;
1023 processed = 1;
1024 break;
1025 case 'C':
1026 lcd_flags |= LCD_FLAG_C;
1027 processed = 1;
1028 break;
1029 case 'c':
1030 lcd_flags &= ~LCD_FLAG_C;
1031 processed = 1;
1032 break;
1033 case 'B':
1034 lcd_flags |= LCD_FLAG_B;
1035 processed = 1;
1036 break;
1037 case 'b':
1038 lcd_flags &= ~LCD_FLAG_B;
1039 processed = 1;
1040 break;
1041 case '+':
1042 lcd_flags |= LCD_FLAG_L;
1043 processed = 1;
1044 break;
1045 case '-':
1046 lcd_flags &= ~LCD_FLAG_L;
1047 processed = 1;
1048 break;
1049 case '*':
1050
1051 if (scan_timer.function != NULL) {
1052 if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0))
1053 lcd_backlight(1);
1054 light_tempo = FLASH_LIGHT_TEMPO;
1055 }
1056 processed = 1;
1057 break;
1058 case 'f':
1059 lcd_flags &= ~LCD_FLAG_F;
1060 processed = 1;
1061 break;
1062 case 'F':
1063 lcd_flags |= LCD_FLAG_F;
1064 processed = 1;
1065 break;
1066 case 'n':
1067 lcd_flags &= ~LCD_FLAG_N;
1068 processed = 1;
1069 break;
1070 case 'N':
1071 lcd_flags |= LCD_FLAG_N;
1072 break;
1073 case 'l':
1074 if (lcd_addr_x > 0) {
1075
1076 if (lcd_addr_x < lcd_bwidth)
1077 lcd_write_cmd(0x10);
1078 lcd_addr_x--;
1079 }
1080 processed = 1;
1081 break;
1082 case 'r':
1083 if (lcd_addr_x < lcd_width) {
1084
1085 if (lcd_addr_x <
1086 (lcd_bwidth - 1))
1087 lcd_write_cmd(0x14);
1088 lcd_addr_x++;
1089 }
1090 processed = 1;
1091 break;
1092 case 'L':
1093 lcd_left_shift++;
1094 lcd_write_cmd(0x18);
1095 processed = 1;
1096 break;
1097 case 'R':
1098 lcd_left_shift--;
1099 lcd_write_cmd(0x1C);
1100 processed = 1;
1101 break;
1102 case 'k': {
1103 int x;
1104 for (x = lcd_addr_x; x < lcd_bwidth; x++)
1105 lcd_write_data(' ');
1106
1107
1108 lcd_gotoxy();
1109 processed = 1;
1110 break;
1111 }
1112 case 'I':
1113 lcd_init_display();
1114 lcd_left_shift = 0;
1115 processed = 1;
1116 break;
1117 case 'G': {
1118
1119
1120
1121
1122
1123
1124
1125
1126 unsigned char cgbytes[8];
1127 unsigned char cgaddr;
1128 int cgoffset;
1129 int shift;
1130 char value;
1131 int addr;
1132
1133 if (strchr(esc, ';') == NULL)
1134 break;
1135
1136 esc++;
1137
1138 cgaddr = *(esc++) - '0';
1139 if (cgaddr > 7) {
1140 processed = 1;
1141 break;
1142 }
1143
1144 cgoffset = 0;
1145 shift = 0;
1146 value = 0;
1147 while (*esc && cgoffset < 8) {
1148 shift ^= 4;
1149 if (*esc >= '0' && *esc <= '9')
1150 value |= (*esc - '0') << shift;
1151 else if (*esc >= 'A' && *esc <= 'Z')
1152 value |= (*esc - 'A' + 10) << shift;
1153 else if (*esc >= 'a' && *esc <= 'z')
1154 value |= (*esc - 'a' + 10) << shift;
1155 else {
1156 esc++;
1157 continue;
1158 }
1159
1160 if (shift == 0) {
1161 cgbytes[cgoffset++] = value;
1162 value = 0;
1163 }
1164
1165 esc++;
1166 }
1167
1168 lcd_write_cmd(0x40 | (cgaddr * 8));
1169 for (addr = 0; addr < cgoffset; addr++)
1170 lcd_write_data(cgbytes[addr]);
1171
1172
1173 lcd_gotoxy();
1174 processed = 1;
1175 break;
1176 }
1177 case 'x':
1178 case 'y':
1179 if (strchr(esc, ';') == NULL)
1180 break;
1181
1182 while (*esc) {
1183 if (*esc == 'x') {
1184 esc++;
1185 if (kstrtoul(esc, 10, &lcd_addr_x) < 0)
1186 break;
1187 } else if (*esc == 'y') {
1188 esc++;
1189 if (kstrtoul(esc, 10, &lcd_addr_y) < 0)
1190 break;
1191 } else
1192 break;
1193 }
1194
1195 lcd_gotoxy();
1196 processed = 1;
1197 break;
1198 }
1199
1200
1201 if (oldflags != lcd_flags) {
1202
1203 if ((oldflags ^ lcd_flags) &
1204 (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
1205
1206 lcd_write_cmd(0x08
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 else if ((oldflags ^ lcd_flags) & (LCD_FLAG_F | LCD_FLAG_N))
1212 lcd_write_cmd(0x30
1213 | ((lcd_flags & LCD_FLAG_F) ? 4 : 0)
1214 | ((lcd_flags & LCD_FLAG_N) ? 8 : 0));
1215
1216 else if ((oldflags ^ lcd_flags) & (LCD_FLAG_L)) {
1217 if (lcd_flags & (LCD_FLAG_L))
1218 lcd_backlight(1);
1219 else if (light_tempo == 0)
1220
1221
1222 lcd_backlight(0);
1223 }
1224 }
1225
1226 return processed;
1227}
1228
1229static ssize_t lcd_write(struct file *file,
1230 const char *buf, size_t count, loff_t *ppos)
1231{
1232 const char *tmp = buf;
1233 char c;
1234
1235 for (; count-- > 0; (ppos ? (*ppos)++ : 0), ++tmp) {
1236 if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
1237
1238
1239 schedule();
1240
1241 if (ppos == NULL && file == NULL)
1242
1243 c = *tmp;
1244 else if (get_user(c, tmp))
1245 return -EFAULT;
1246
1247
1248 if ((c != '\n') && lcd_escape_len >= 0) {
1249
1250 lcd_escape[lcd_escape_len++] = c;
1251 lcd_escape[lcd_escape_len] = 0;
1252 } else {
1253
1254 lcd_escape_len = -1;
1255
1256 switch (c) {
1257 case LCD_ESCAPE_CHAR:
1258
1259 lcd_escape_len = 0;
1260 lcd_escape[lcd_escape_len] = 0;
1261 break;
1262 case '\b':
1263
1264 if (lcd_addr_x > 0) {
1265
1266
1267 if (lcd_addr_x < lcd_bwidth)
1268
1269 lcd_write_cmd(0x10);
1270 lcd_addr_x--;
1271 }
1272
1273 lcd_write_data(' ');
1274
1275 lcd_write_cmd(0x10);
1276 break;
1277 case '\014':
1278
1279 lcd_clear_fast();
1280 break;
1281 case '\n':
1282
1283
1284 for (; lcd_addr_x < lcd_bwidth; lcd_addr_x++)
1285 lcd_write_data(' ');
1286 lcd_addr_x = 0;
1287 lcd_addr_y = (lcd_addr_y + 1) % lcd_height;
1288 lcd_gotoxy();
1289 break;
1290 case '\r':
1291
1292 lcd_addr_x = 0;
1293 lcd_gotoxy();
1294 break;
1295 case '\t':
1296
1297 lcd_print(' ');
1298 break;
1299 default:
1300
1301 lcd_print(c);
1302 break;
1303 }
1304 }
1305
1306
1307
1308 if (lcd_escape_len >= 2) {
1309 int processed = 0;
1310
1311 if (!strcmp(lcd_escape, "[2J")) {
1312
1313 lcd_clear_fast();
1314 processed = 1;
1315 } else if (!strcmp(lcd_escape, "[H")) {
1316
1317 lcd_addr_x = lcd_addr_y = 0;
1318 lcd_gotoxy();
1319 processed = 1;
1320 }
1321
1322 else if ((lcd_escape_len >= 3) &&
1323 (lcd_escape[0] == '[') &&
1324 (lcd_escape[1] == 'L')) {
1325 processed = handle_lcd_special_code();
1326 }
1327
1328
1329
1330
1331 if (processed || (lcd_escape_len >= LCD_ESCAPE_LEN))
1332 lcd_escape_len = -1;
1333 }
1334 }
1335
1336 return tmp - buf;
1337}
1338
1339static int lcd_open(struct inode *inode, struct file *file)
1340{
1341 if (lcd_open_cnt)
1342 return -EBUSY;
1343
1344 if (file->f_mode & FMODE_READ)
1345 return -EPERM;
1346
1347 if (lcd_must_clear) {
1348 lcd_clear_display();
1349 lcd_must_clear = 0;
1350 }
1351 lcd_open_cnt++;
1352 return nonseekable_open(inode, file);
1353}
1354
1355static int lcd_release(struct inode *inode, struct file *file)
1356{
1357 lcd_open_cnt--;
1358 return 0;
1359}
1360
1361static const struct file_operations lcd_fops = {
1362 .write = lcd_write,
1363 .open = lcd_open,
1364 .release = lcd_release,
1365 .llseek = no_llseek,
1366};
1367
1368static struct miscdevice lcd_dev = {
1369 LCD_MINOR,
1370 "lcd",
1371 &lcd_fops
1372};
1373
1374
1375static void panel_lcd_print(const char *s)
1376{
1377 if (lcd_enabled && lcd_initialized)
1378 lcd_write(NULL, s, strlen(s), NULL);
1379}
1380
1381
1382static void lcd_init(void)
1383{
1384 switch (lcd_type) {
1385 case LCD_TYPE_OLD:
1386
1387 if (lcd_proto < 0)
1388 lcd_proto = LCD_PROTO_PARALLEL;
1389 if (lcd_charset < 0)
1390 lcd_charset = LCD_CHARSET_NORMAL;
1391 if (lcd_e_pin == PIN_NOT_SET)
1392 lcd_e_pin = PIN_STROBE;
1393 if (lcd_rs_pin == PIN_NOT_SET)
1394 lcd_rs_pin = PIN_AUTOLF;
1395
1396 if (lcd_width < 0)
1397 lcd_width = 40;
1398 if (lcd_bwidth < 0)
1399 lcd_bwidth = 40;
1400 if (lcd_hwidth < 0)
1401 lcd_hwidth = 64;
1402 if (lcd_height < 0)
1403 lcd_height = 2;
1404 break;
1405 case LCD_TYPE_KS0074:
1406
1407 if (lcd_proto < 0)
1408 lcd_proto = LCD_PROTO_SERIAL;
1409 if (lcd_charset < 0)
1410 lcd_charset = LCD_CHARSET_KS0074;
1411 if (lcd_bl_pin == PIN_NOT_SET)
1412 lcd_bl_pin = PIN_AUTOLF;
1413 if (lcd_cl_pin == PIN_NOT_SET)
1414 lcd_cl_pin = PIN_STROBE;
1415 if (lcd_da_pin == PIN_NOT_SET)
1416 lcd_da_pin = PIN_D0;
1417
1418 if (lcd_width < 0)
1419 lcd_width = 16;
1420 if (lcd_bwidth < 0)
1421 lcd_bwidth = 40;
1422 if (lcd_hwidth < 0)
1423 lcd_hwidth = 16;
1424 if (lcd_height < 0)
1425 lcd_height = 2;
1426 break;
1427 case LCD_TYPE_NEXCOM:
1428
1429 if (lcd_proto < 0)
1430 lcd_proto = LCD_PROTO_PARALLEL;
1431 if (lcd_charset < 0)
1432 lcd_charset = LCD_CHARSET_NORMAL;
1433 if (lcd_e_pin == PIN_NOT_SET)
1434 lcd_e_pin = PIN_AUTOLF;
1435 if (lcd_rs_pin == PIN_NOT_SET)
1436 lcd_rs_pin = PIN_SELECP;
1437 if (lcd_rw_pin == PIN_NOT_SET)
1438 lcd_rw_pin = PIN_INITP;
1439
1440 if (lcd_width < 0)
1441 lcd_width = 16;
1442 if (lcd_bwidth < 0)
1443 lcd_bwidth = 40;
1444 if (lcd_hwidth < 0)
1445 lcd_hwidth = 64;
1446 if (lcd_height < 0)
1447 lcd_height = 2;
1448 break;
1449 case LCD_TYPE_CUSTOM:
1450
1451 if (lcd_proto < 0)
1452 lcd_proto = DEFAULT_LCD_PROTO;
1453 if (lcd_charset < 0)
1454 lcd_charset = DEFAULT_LCD_CHARSET;
1455
1456 break;
1457 case LCD_TYPE_HANTRONIX:
1458
1459 default:
1460 if (lcd_proto < 0)
1461 lcd_proto = LCD_PROTO_PARALLEL;
1462 if (lcd_charset < 0)
1463 lcd_charset = LCD_CHARSET_NORMAL;
1464 if (lcd_e_pin == PIN_NOT_SET)
1465 lcd_e_pin = PIN_STROBE;
1466 if (lcd_rs_pin == PIN_NOT_SET)
1467 lcd_rs_pin = PIN_SELECP;
1468
1469 if (lcd_width < 0)
1470 lcd_width = 16;
1471 if (lcd_bwidth < 0)
1472 lcd_bwidth = 40;
1473 if (lcd_hwidth < 0)
1474 lcd_hwidth = 64;
1475 if (lcd_height < 0)
1476 lcd_height = 2;
1477 break;
1478 }
1479
1480
1481 if (lcd_width <= 0)
1482 lcd_width = DEFAULT_LCD_WIDTH;
1483 if (lcd_bwidth <= 0)
1484 lcd_bwidth = DEFAULT_LCD_BWIDTH;
1485 if (lcd_hwidth <= 0)
1486 lcd_hwidth = DEFAULT_LCD_HWIDTH;
1487 if (lcd_height <= 0)
1488 lcd_height = DEFAULT_LCD_HEIGHT;
1489
1490 if (lcd_proto == LCD_PROTO_SERIAL) {
1491 lcd_write_cmd = lcd_write_cmd_s;
1492 lcd_write_data = lcd_write_data_s;
1493 lcd_clear_fast = lcd_clear_fast_s;
1494
1495 if (lcd_cl_pin == PIN_NOT_SET)
1496 lcd_cl_pin = DEFAULT_LCD_PIN_SCL;
1497 if (lcd_da_pin == PIN_NOT_SET)
1498 lcd_da_pin = DEFAULT_LCD_PIN_SDA;
1499
1500 } else if (lcd_proto == LCD_PROTO_PARALLEL) {
1501 lcd_write_cmd = lcd_write_cmd_p8;
1502 lcd_write_data = lcd_write_data_p8;
1503 lcd_clear_fast = lcd_clear_fast_p8;
1504
1505 if (lcd_e_pin == PIN_NOT_SET)
1506 lcd_e_pin = DEFAULT_LCD_PIN_E;
1507 if (lcd_rs_pin == PIN_NOT_SET)
1508 lcd_rs_pin = DEFAULT_LCD_PIN_RS;
1509 if (lcd_rw_pin == PIN_NOT_SET)
1510 lcd_rw_pin = DEFAULT_LCD_PIN_RW;
1511 } else {
1512 lcd_write_cmd = lcd_write_cmd_tilcd;
1513 lcd_write_data = lcd_write_data_tilcd;
1514 lcd_clear_fast = lcd_clear_fast_tilcd;
1515 }
1516
1517 if (lcd_bl_pin == PIN_NOT_SET)
1518 lcd_bl_pin = DEFAULT_LCD_PIN_BL;
1519
1520 if (lcd_e_pin == PIN_NOT_SET)
1521 lcd_e_pin = PIN_NONE;
1522 if (lcd_rs_pin == PIN_NOT_SET)
1523 lcd_rs_pin = PIN_NONE;
1524 if (lcd_rw_pin == PIN_NOT_SET)
1525 lcd_rw_pin = PIN_NONE;
1526 if (lcd_bl_pin == PIN_NOT_SET)
1527 lcd_bl_pin = PIN_NONE;
1528 if (lcd_cl_pin == PIN_NOT_SET)
1529 lcd_cl_pin = PIN_NONE;
1530 if (lcd_da_pin == PIN_NOT_SET)
1531 lcd_da_pin = PIN_NONE;
1532
1533 if (lcd_charset < 0)
1534 lcd_charset = DEFAULT_LCD_CHARSET;
1535
1536 if (lcd_charset == LCD_CHARSET_KS0074)
1537 lcd_char_conv = lcd_char_conv_ks0074;
1538 else
1539 lcd_char_conv = NULL;
1540
1541 if (lcd_bl_pin != PIN_NONE)
1542 init_scan_timer();
1543
1544 pin_to_bits(lcd_e_pin, lcd_bits[LCD_PORT_D][LCD_BIT_E],
1545 lcd_bits[LCD_PORT_C][LCD_BIT_E]);
1546 pin_to_bits(lcd_rs_pin, lcd_bits[LCD_PORT_D][LCD_BIT_RS],
1547 lcd_bits[LCD_PORT_C][LCD_BIT_RS]);
1548 pin_to_bits(lcd_rw_pin, lcd_bits[LCD_PORT_D][LCD_BIT_RW],
1549 lcd_bits[LCD_PORT_C][LCD_BIT_RW]);
1550 pin_to_bits(lcd_bl_pin, lcd_bits[LCD_PORT_D][LCD_BIT_BL],
1551 lcd_bits[LCD_PORT_C][LCD_BIT_BL]);
1552 pin_to_bits(lcd_cl_pin, lcd_bits[LCD_PORT_D][LCD_BIT_CL],
1553 lcd_bits[LCD_PORT_C][LCD_BIT_CL]);
1554 pin_to_bits(lcd_da_pin, lcd_bits[LCD_PORT_D][LCD_BIT_DA],
1555 lcd_bits[LCD_PORT_C][LCD_BIT_DA]);
1556
1557
1558
1559
1560 lcd_initialized = 1;
1561 lcd_init_display();
1562
1563
1564#ifdef CONFIG_PANEL_CHANGE_MESSAGE
1565#ifdef CONFIG_PANEL_BOOT_MESSAGE
1566 panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE);
1567#endif
1568#else
1569 panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\nPanel-"
1570 PANEL_VERSION);
1571#endif
1572 lcd_addr_x = lcd_addr_y = 0;
1573
1574 lcd_must_clear = 1;
1575 lcd_gotoxy();
1576}
1577
1578
1579
1580
1581
1582static ssize_t keypad_read(struct file *file,
1583 char *buf, size_t count, loff_t *ppos)
1584{
1585
1586 unsigned i = *ppos;
1587 char *tmp = buf;
1588
1589 if (keypad_buflen == 0) {
1590 if (file->f_flags & O_NONBLOCK)
1591 return -EAGAIN;
1592
1593 interruptible_sleep_on(&keypad_read_wait);
1594 if (signal_pending(current))
1595 return -EINTR;
1596 }
1597
1598 for (; count-- > 0 && (keypad_buflen > 0);
1599 ++i, ++tmp, --keypad_buflen) {
1600 put_user(keypad_buffer[keypad_start], tmp);
1601 keypad_start = (keypad_start + 1) % KEYPAD_BUFFER;
1602 }
1603 *ppos = i;
1604
1605 return tmp - buf;
1606}
1607
1608static int keypad_open(struct inode *inode, struct file *file)
1609{
1610
1611 if (keypad_open_cnt)
1612 return -EBUSY;
1613
1614 if (file->f_mode & FMODE_WRITE)
1615 return -EPERM;
1616
1617 keypad_buflen = 0;
1618 keypad_open_cnt++;
1619 return 0;
1620}
1621
1622static int keypad_release(struct inode *inode, struct file *file)
1623{
1624 keypad_open_cnt--;
1625 return 0;
1626}
1627
1628static const struct file_operations keypad_fops = {
1629 .read = keypad_read,
1630 .open = keypad_open,
1631 .release = keypad_release,
1632 .llseek = default_llseek,
1633};
1634
1635static struct miscdevice keypad_dev = {
1636 KEYPAD_MINOR,
1637 "keypad",
1638 &keypad_fops
1639};
1640
1641static void keypad_send_key(const char *string, int max_len)
1642{
1643 if (init_in_progress)
1644 return;
1645
1646
1647 if (keypad_open_cnt > 0) {
1648 while (max_len-- && keypad_buflen < KEYPAD_BUFFER && *string) {
1649 keypad_buffer[(keypad_start + keypad_buflen++) %
1650 KEYPAD_BUFFER] = *string++;
1651 }
1652 wake_up_interruptible(&keypad_read_wait);
1653 }
1654}
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666static void phys_scan_contacts(void)
1667{
1668 int bit, bitval;
1669 char oldval;
1670 char bitmask;
1671 char gndmask;
1672
1673 phys_prev = phys_curr;
1674 phys_read_prev = phys_read;
1675 phys_read = 0;
1676
1677
1678 oldval = r_dtr(pprt) | scan_mask_o;
1679
1680 w_dtr(pprt, oldval & ~scan_mask_o);
1681
1682
1683 bitmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
1684
1685 w_dtr(pprt, oldval);
1686
1687
1688
1689
1690
1691
1692 gndmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
1693
1694
1695 phys_read |= (pmask_t) gndmask << 40;
1696
1697 if (bitmask != gndmask) {
1698
1699
1700
1701
1702 for (bit = 0; bit < 8; bit++) {
1703 bitval = 1 << bit;
1704
1705 if (!(scan_mask_o & bitval))
1706 continue;
1707
1708 w_dtr(pprt, oldval & ~bitval);
1709 bitmask = PNL_PINPUT(r_str(pprt)) & ~gndmask;
1710 phys_read |= (pmask_t) bitmask << (5 * bit);
1711 }
1712 w_dtr(pprt, oldval);
1713 }
1714
1715
1716 phys_curr = (phys_prev & (phys_read ^ phys_read_prev)) |
1717 (phys_read & ~(phys_read ^ phys_read_prev));
1718}
1719
1720static inline int input_state_high(struct logical_input *input)
1721{
1722#if 0
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740 if (((phys_prev & input->mask) == input->value)
1741 && ((phys_curr & input->mask) > input->value)) {
1742 input->state = INPUT_ST_LOW;
1743 return 1;
1744 }
1745#endif
1746
1747 if ((phys_curr & input->mask) == input->value) {
1748 if ((input->type == INPUT_TYPE_STD) &&
1749 (input->high_timer == 0)) {
1750 input->high_timer++;
1751 if (input->u.std.press_fct != NULL)
1752 input->u.std.press_fct(input->u.std.press_data);
1753 } else if (input->type == INPUT_TYPE_KBD) {
1754
1755 keypressed = 1;
1756
1757 if (input->high_timer == 0) {
1758 char *press_str = input->u.kbd.press_str;
1759 if (press_str[0]) {
1760 int s = sizeof(input->u.kbd.press_str);
1761 keypad_send_key(press_str, s);
1762 }
1763 }
1764
1765 if (input->u.kbd.repeat_str[0]) {
1766 char *repeat_str = input->u.kbd.repeat_str;
1767 if (input->high_timer >= KEYPAD_REP_START) {
1768 int s = sizeof(input->u.kbd.repeat_str);
1769 input->high_timer -= KEYPAD_REP_DELAY;
1770 keypad_send_key(repeat_str, s);
1771 }
1772
1773 inputs_stable = 0;
1774 }
1775
1776 if (input->high_timer < 255)
1777 input->high_timer++;
1778 }
1779 return 1;
1780 } else {
1781
1782 input->state = INPUT_ST_FALLING;
1783 input->fall_timer = 0;
1784 }
1785 return 0;
1786}
1787
1788static inline void input_state_falling(struct logical_input *input)
1789{
1790#if 0
1791
1792 if (((phys_prev & input->mask) == input->value)
1793 && ((phys_curr & input->mask) > input->value)) {
1794 input->state = INPUT_ST_LOW;
1795 return;
1796 }
1797#endif
1798
1799 if ((phys_curr & input->mask) == input->value) {
1800 if (input->type == INPUT_TYPE_KBD) {
1801
1802 keypressed = 1;
1803
1804 if (input->u.kbd.repeat_str[0]) {
1805 char *repeat_str = input->u.kbd.repeat_str;
1806 if (input->high_timer >= KEYPAD_REP_START) {
1807 int s = sizeof(input->u.kbd.repeat_str);
1808 input->high_timer -= KEYPAD_REP_DELAY;
1809 keypad_send_key(repeat_str, s);
1810 }
1811
1812 inputs_stable = 0;
1813 }
1814
1815 if (input->high_timer < 255)
1816 input->high_timer++;
1817 }
1818 input->state = INPUT_ST_HIGH;
1819 } else if (input->fall_timer >= input->fall_time) {
1820
1821 if (input->type == INPUT_TYPE_STD) {
1822 void (*release_fct)(int) = input->u.std.release_fct;
1823 if (release_fct != NULL)
1824 release_fct(input->u.std.release_data);
1825 } else if (input->type == INPUT_TYPE_KBD) {
1826 char *release_str = input->u.kbd.release_str;
1827 if (release_str[0]) {
1828 int s = sizeof(input->u.kbd.release_str);
1829 keypad_send_key(release_str, s);
1830 }
1831 }
1832
1833 input->state = INPUT_ST_LOW;
1834 } else {
1835 input->fall_timer++;
1836 inputs_stable = 0;
1837 }
1838}
1839
1840static void panel_process_inputs(void)
1841{
1842 struct list_head *item;
1843 struct logical_input *input;
1844
1845 keypressed = 0;
1846 inputs_stable = 1;
1847 list_for_each(item, &logical_inputs) {
1848 input = list_entry(item, struct logical_input, list);
1849
1850 switch (input->state) {
1851 case INPUT_ST_LOW:
1852 if ((phys_curr & input->mask) != input->value)
1853 break;
1854
1855
1856
1857
1858
1859
1860
1861 if ((phys_prev & input->mask) == input->value)
1862 break;
1863 input->rise_timer = 0;
1864 input->state = INPUT_ST_RISING;
1865
1866 case INPUT_ST_RISING:
1867 if ((phys_curr & input->mask) != input->value) {
1868 input->state = INPUT_ST_LOW;
1869 break;
1870 }
1871 if (input->rise_timer < input->rise_time) {
1872 inputs_stable = 0;
1873 input->rise_timer++;
1874 break;
1875 }
1876 input->high_timer = 0;
1877 input->state = INPUT_ST_HIGH;
1878
1879 case INPUT_ST_HIGH:
1880 if (input_state_high(input))
1881 break;
1882
1883 case INPUT_ST_FALLING:
1884 input_state_falling(input);
1885 }
1886 }
1887}
1888
1889static void panel_scan_timer(void)
1890{
1891 if (keypad_enabled && keypad_initialized) {
1892 if (spin_trylock_irq(&pprt_lock)) {
1893 phys_scan_contacts();
1894
1895
1896 spin_unlock_irq(&pprt_lock);
1897 }
1898
1899 if (!inputs_stable || phys_curr != phys_prev)
1900 panel_process_inputs();
1901 }
1902
1903 if (lcd_enabled && lcd_initialized) {
1904 if (keypressed) {
1905 if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0))
1906 lcd_backlight(1);
1907 light_tempo = FLASH_LIGHT_TEMPO;
1908 } else if (light_tempo > 0) {
1909 light_tempo--;
1910 if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0))
1911 lcd_backlight(0);
1912 }
1913 }
1914
1915 mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME);
1916}
1917
1918static void init_scan_timer(void)
1919{
1920 if (scan_timer.function != NULL)
1921 return;
1922
1923 init_timer(&scan_timer);
1924 scan_timer.expires = jiffies + INPUT_POLL_TIME;
1925 scan_timer.data = 0;
1926 scan_timer.function = (void *)&panel_scan_timer;
1927 add_timer(&scan_timer);
1928}
1929
1930
1931
1932
1933
1934
1935static int input_name2mask(const char *name, pmask_t *mask, pmask_t *value,
1936 char *imask, char *omask)
1937{
1938 static char sigtab[10] = "EeSsPpAaBb";
1939 char im, om;
1940 pmask_t m, v;
1941
1942 om = im = m = v = 0ULL;
1943 while (*name) {
1944 int in, out, bit, neg;
1945 for (in = 0; (in < sizeof(sigtab)) &&
1946 (sigtab[in] != *name); in++)
1947 ;
1948 if (in >= sizeof(sigtab))
1949 return 0;
1950 neg = (in & 1);
1951 in >>= 1;
1952 im |= (1 << in);
1953
1954 name++;
1955 if (isdigit(*name)) {
1956 out = *name - '0';
1957 om |= (1 << out);
1958 } else if (*name == '-')
1959 out = 8;
1960 else
1961 return 0;
1962
1963 bit = (out * 5) + in;
1964
1965 m |= 1ULL << bit;
1966 if (!neg)
1967 v |= 1ULL << bit;
1968 name++;
1969 }
1970 *mask = m;
1971 *value = v;
1972 if (imask)
1973 *imask |= im;
1974 if (omask)
1975 *omask |= om;
1976 return 1;
1977}
1978
1979
1980
1981
1982
1983static struct logical_input *panel_bind_key(const char *name, const char *press,
1984 const char *repeat,
1985 const char *release)
1986{
1987 struct logical_input *key;
1988
1989 key = kzalloc(sizeof(struct logical_input), GFP_KERNEL);
1990 if (!key)
1991 return NULL;
1992
1993 if (!input_name2mask(name, &key->mask, &key->value, &scan_mask_i,
1994 &scan_mask_o)) {
1995 kfree(key);
1996 return NULL;
1997 }
1998
1999 key->type = INPUT_TYPE_KBD;
2000 key->state = INPUT_ST_LOW;
2001 key->rise_time = 1;
2002 key->fall_time = 1;
2003
2004 strncpy(key->u.kbd.press_str, press, sizeof(key->u.kbd.press_str));
2005 strncpy(key->u.kbd.repeat_str, repeat, sizeof(key->u.kbd.repeat_str));
2006 strncpy(key->u.kbd.release_str, release,
2007 sizeof(key->u.kbd.release_str));
2008 list_add(&key->list, &logical_inputs);
2009 return key;
2010}
2011
2012#if 0
2013
2014
2015
2016
2017
2018
2019static struct logical_input *panel_bind_callback(char *name,
2020 void (*press_fct) (int),
2021 int press_data,
2022 void (*release_fct) (int),
2023 int release_data)
2024{
2025 struct logical_input *callback;
2026
2027 callback = kmalloc(sizeof(struct logical_input), GFP_KERNEL);
2028 if (!callback)
2029 return NULL;
2030
2031 memset(callback, 0, sizeof(struct logical_input));
2032 if (!input_name2mask(name, &callback->mask, &callback->value,
2033 &scan_mask_i, &scan_mask_o))
2034 return NULL;
2035
2036 callback->type = INPUT_TYPE_STD;
2037 callback->state = INPUT_ST_LOW;
2038 callback->rise_time = 1;
2039 callback->fall_time = 1;
2040 callback->u.std.press_fct = press_fct;
2041 callback->u.std.press_data = press_data;
2042 callback->u.std.release_fct = release_fct;
2043 callback->u.std.release_data = release_data;
2044 list_add(&callback->list, &logical_inputs);
2045 return callback;
2046}
2047#endif
2048
2049static void keypad_init(void)
2050{
2051 int keynum;
2052 init_waitqueue_head(&keypad_read_wait);
2053 keypad_buflen = 0;
2054
2055
2056
2057 for (keynum = 0; keypad_profile[keynum][0][0]; keynum++) {
2058 panel_bind_key(keypad_profile[keynum][0],
2059 keypad_profile[keynum][1],
2060 keypad_profile[keynum][2],
2061 keypad_profile[keynum][3]);
2062 }
2063
2064 init_scan_timer();
2065 keypad_initialized = 1;
2066}
2067
2068
2069
2070
2071
2072static int panel_notify_sys(struct notifier_block *this, unsigned long code,
2073 void *unused)
2074{
2075 if (lcd_enabled && lcd_initialized) {
2076 switch (code) {
2077 case SYS_DOWN:
2078 panel_lcd_print
2079 ("\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+");
2080 break;
2081 case SYS_HALT:
2082 panel_lcd_print
2083 ("\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+");
2084 break;
2085 case SYS_POWER_OFF:
2086 panel_lcd_print("\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+");
2087 break;
2088 default:
2089 break;
2090 }
2091 }
2092 return NOTIFY_DONE;
2093}
2094
2095static struct notifier_block panel_notifier = {
2096 panel_notify_sys,
2097 NULL,
2098 0
2099};
2100
2101static void panel_attach(struct parport *port)
2102{
2103 if (port->number != parport)
2104 return;
2105
2106 if (pprt) {
2107 pr_err("%s: port->number=%d parport=%d, already registered!\n",
2108 __func__, port->number, parport);
2109 return;
2110 }
2111
2112 pprt = parport_register_device(port, "panel", NULL, NULL,
2113 NULL,
2114
2115 0, (void *)&pprt);
2116 if (pprt == NULL) {
2117 pr_err("%s: port->number=%d parport=%d, parport_register_device() failed\n",
2118 __func__, port->number, parport);
2119 return;
2120 }
2121
2122 if (parport_claim(pprt)) {
2123 pr_err("could not claim access to parport%d. Aborting.\n",
2124 parport);
2125 goto err_unreg_device;
2126 }
2127
2128
2129
2130
2131 if (lcd_enabled) {
2132 lcd_init();
2133 if (misc_register(&lcd_dev))
2134 goto err_unreg_device;
2135 }
2136
2137 if (keypad_enabled) {
2138 keypad_init();
2139 if (misc_register(&keypad_dev))
2140 goto err_lcd_unreg;
2141 }
2142 return;
2143
2144err_lcd_unreg:
2145 if (lcd_enabled)
2146 misc_deregister(&lcd_dev);
2147err_unreg_device:
2148 parport_unregister_device(pprt);
2149 pprt = NULL;
2150}
2151
2152static void panel_detach(struct parport *port)
2153{
2154 if (port->number != parport)
2155 return;
2156
2157 if (!pprt) {
2158 pr_err("%s: port->number=%d parport=%d, nothing to unregister.\n",
2159 __func__, port->number, parport);
2160 return;
2161 }
2162
2163 if (keypad_enabled && keypad_initialized) {
2164 misc_deregister(&keypad_dev);
2165 keypad_initialized = 0;
2166 }
2167
2168 if (lcd_enabled && lcd_initialized) {
2169 misc_deregister(&lcd_dev);
2170 lcd_initialized = 0;
2171 }
2172
2173 parport_release(pprt);
2174 parport_unregister_device(pprt);
2175 pprt = NULL;
2176}
2177
2178static struct parport_driver panel_driver = {
2179 .name = "panel",
2180 .attach = panel_attach,
2181 .detach = panel_detach,
2182};
2183
2184
2185static int panel_init(void)
2186{
2187
2188 if (keypad_type < 0)
2189 keypad_type = keypad_enabled;
2190
2191 if (lcd_type < 0)
2192 lcd_type = lcd_enabled;
2193
2194 if (parport < 0)
2195 parport = DEFAULT_PARPORT;
2196
2197
2198 switch (profile) {
2199 case PANEL_PROFILE_CUSTOM:
2200
2201 if (keypad_type < 0)
2202 keypad_type = DEFAULT_KEYPAD;
2203 if (lcd_type < 0)
2204 lcd_type = DEFAULT_LCD;
2205 break;
2206 case PANEL_PROFILE_OLD:
2207
2208 if (keypad_type < 0)
2209 keypad_type = KEYPAD_TYPE_OLD;
2210 if (lcd_type < 0)
2211 lcd_type = LCD_TYPE_OLD;
2212 if (lcd_width < 0)
2213 lcd_width = 16;
2214 if (lcd_hwidth < 0)
2215 lcd_hwidth = 16;
2216 break;
2217 case PANEL_PROFILE_NEW:
2218
2219 if (keypad_type < 0)
2220 keypad_type = KEYPAD_TYPE_NEW;
2221 if (lcd_type < 0)
2222 lcd_type = LCD_TYPE_KS0074;
2223 break;
2224 case PANEL_PROFILE_HANTRONIX:
2225
2226 if (keypad_type < 0)
2227 keypad_type = KEYPAD_TYPE_NONE;
2228 if (lcd_type < 0)
2229 lcd_type = LCD_TYPE_HANTRONIX;
2230 break;
2231 case PANEL_PROFILE_NEXCOM:
2232
2233 if (keypad_type < 0)
2234 keypad_type = KEYPAD_TYPE_NEXCOM;
2235 if (lcd_type < 0)
2236 lcd_type = LCD_TYPE_NEXCOM;
2237 break;
2238 case PANEL_PROFILE_LARGE:
2239
2240 if (keypad_type < 0)
2241 keypad_type = KEYPAD_TYPE_OLD;
2242 if (lcd_type < 0)
2243 lcd_type = LCD_TYPE_OLD;
2244 break;
2245 }
2246
2247 lcd_enabled = (lcd_type > 0);
2248 keypad_enabled = (keypad_type > 0);
2249
2250 switch (keypad_type) {
2251 case KEYPAD_TYPE_OLD:
2252 keypad_profile = old_keypad_profile;
2253 break;
2254 case KEYPAD_TYPE_NEW:
2255 keypad_profile = new_keypad_profile;
2256 break;
2257 case KEYPAD_TYPE_NEXCOM:
2258 keypad_profile = nexcom_keypad_profile;
2259 break;
2260 default:
2261 keypad_profile = NULL;
2262 break;
2263 }
2264
2265
2266 init_in_progress = 1;
2267
2268 if (parport_register_driver(&panel_driver)) {
2269 pr_err("could not register with parport. Aborting.\n");
2270 return -EIO;
2271 }
2272
2273 if (!lcd_enabled && !keypad_enabled) {
2274
2275 if (pprt) {
2276 parport_release(pprt);
2277 parport_unregister_device(pprt);
2278 pprt = NULL;
2279 }
2280 parport_unregister_driver(&panel_driver);
2281 pr_err("driver version " PANEL_VERSION " disabled.\n");
2282 return -ENODEV;
2283 }
2284
2285 register_reboot_notifier(&panel_notifier);
2286
2287 if (pprt)
2288 pr_info("driver version " PANEL_VERSION
2289 " registered on parport%d (io=0x%lx).\n", parport,
2290 pprt->port->base);
2291 else
2292 pr_info("driver version " PANEL_VERSION
2293 " not yet registered\n");
2294
2295
2296 init_in_progress = 0;
2297 return 0;
2298}
2299
2300static int __init panel_init_module(void)
2301{
2302 return panel_init();
2303}
2304
2305static void __exit panel_cleanup_module(void)
2306{
2307 unregister_reboot_notifier(&panel_notifier);
2308
2309 if (scan_timer.function != NULL)
2310 del_timer(&scan_timer);
2311
2312 if (pprt != NULL) {
2313 if (keypad_enabled) {
2314 misc_deregister(&keypad_dev);
2315 keypad_initialized = 0;
2316 }
2317
2318 if (lcd_enabled) {
2319 panel_lcd_print("\x0cLCD driver " PANEL_VERSION
2320 "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-");
2321 misc_deregister(&lcd_dev);
2322 lcd_initialized = 0;
2323 }
2324
2325
2326 parport_release(pprt);
2327 parport_unregister_device(pprt);
2328 pprt = NULL;
2329 }
2330 parport_unregister_driver(&panel_driver);
2331}
2332
2333module_init(panel_init_module);
2334module_exit(panel_cleanup_module);
2335MODULE_AUTHOR("Willy Tarreau");
2336MODULE_LICENSE("GPL");
2337
2338
2339
2340
2341
2342
2343
2344