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