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/version.h>
55#include <linux/list.h>
56#include <linux/notifier.h>
57#include <linux/reboot.h>
58#include <generated/utsrelease.h>
59
60#include <linux/io.h>
61#include <linux/uaccess.h>
62#include <asm/system.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) do { parport_write_control((x)->port, (y)); } while (0)
141#define w_dtr(x, y) do { parport_write_data((x)->port, (y)); } while (0)
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
188LIST_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 unsigned char *lcd_char_conv;
531
532
533static 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
569char 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
580char 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
593char 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 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
672void 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(&pprt_lock);
761 bits.bl = on;
762 panel_set_bits();
763 spin_unlock(&pprt_lock);
764}
765
766
767static void lcd_write_cmd_s(int cmd)
768{
769 spin_lock(&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(&pprt_lock);
775}
776
777
778static void lcd_write_data_s(int data)
779{
780 spin_lock(&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(&pprt_lock);
786}
787
788
789static void lcd_write_cmd_p8(int cmd)
790{
791 spin_lock(&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(&pprt_lock);
808}
809
810
811static void lcd_write_data_p8(int data)
812{
813 spin_lock(&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(&pprt_lock);
830}
831
832
833static void lcd_write_cmd_tilcd(int cmd)
834{
835 spin_lock(&pprt_lock);
836
837 w_ctr(pprt, cmd);
838 udelay(60);
839 spin_unlock(&pprt_lock);
840}
841
842
843static void lcd_write_data_tilcd(int data)
844{
845 spin_lock(&pprt_lock);
846
847 w_dtr(pprt, data);
848 udelay(60);
849 spin_unlock(&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(&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(&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(&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(&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(&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(&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 char *endp;
1184
1185 if (*esc == 'x') {
1186 esc++;
1187 lcd_addr_x = simple_strtoul(esc, &endp, 10);
1188 esc = endp;
1189 } else if (*esc == 'y') {
1190 esc++;
1191 lcd_addr_y = simple_strtoul(esc, &endp, 10);
1192 esc = endp;
1193 } else
1194 break;
1195 }
1196
1197 lcd_gotoxy();
1198 processed = 1;
1199 break;
1200 }
1201
1202
1203 if (oldflags != lcd_flags) {
1204
1205 if ((oldflags ^ lcd_flags) &
1206 (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
1207
1208 lcd_write_cmd(0x08
1209 | ((lcd_flags & LCD_FLAG_D) ? 4 : 0)
1210 | ((lcd_flags & LCD_FLAG_C) ? 2 : 0)
1211 | ((lcd_flags & LCD_FLAG_B) ? 1 : 0));
1212
1213 else if ((oldflags ^ lcd_flags) & (LCD_FLAG_F | LCD_FLAG_N))
1214 lcd_write_cmd(0x30
1215 | ((lcd_flags & LCD_FLAG_F) ? 4 : 0)
1216 | ((lcd_flags & LCD_FLAG_N) ? 8 : 0));
1217
1218 else if ((oldflags ^ lcd_flags) & (LCD_FLAG_L)) {
1219 if (lcd_flags & (LCD_FLAG_L))
1220 lcd_backlight(1);
1221 else if (light_tempo == 0)
1222
1223
1224 lcd_backlight(0);
1225 }
1226 }
1227
1228 return processed;
1229}
1230
1231static ssize_t lcd_write(struct file *file,
1232 const char *buf, size_t count, loff_t *ppos)
1233{
1234 const char *tmp = buf;
1235 char c;
1236
1237 for (; count-- > 0; (ppos ? (*ppos)++ : 0), ++tmp) {
1238 if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
1239
1240
1241 schedule();
1242
1243 if (ppos == NULL && file == NULL)
1244
1245 c = *tmp;
1246 else if (get_user(c, tmp))
1247 return -EFAULT;
1248
1249
1250 if ((c != '\n') && lcd_escape_len >= 0) {
1251
1252 lcd_escape[lcd_escape_len++] = c;
1253 lcd_escape[lcd_escape_len] = 0;
1254 } else {
1255
1256 lcd_escape_len = -1;
1257
1258 switch (c) {
1259 case LCD_ESCAPE_CHAR:
1260
1261 lcd_escape_len = 0;
1262 lcd_escape[lcd_escape_len] = 0;
1263 break;
1264 case '\b':
1265
1266 if (lcd_addr_x > 0) {
1267
1268
1269 if (lcd_addr_x < lcd_bwidth)
1270
1271 lcd_write_cmd(0x10);
1272 lcd_addr_x--;
1273 }
1274
1275 lcd_write_data(' ');
1276
1277 lcd_write_cmd(0x10);
1278 break;
1279 case '\014':
1280
1281 lcd_clear_fast();
1282 break;
1283 case '\n':
1284
1285
1286 for (; lcd_addr_x < lcd_bwidth; lcd_addr_x++)
1287 lcd_write_data(' ');
1288 lcd_addr_x = 0;
1289 lcd_addr_y = (lcd_addr_y + 1) % lcd_height;
1290 lcd_gotoxy();
1291 break;
1292 case '\r':
1293
1294 lcd_addr_x = 0;
1295 lcd_gotoxy();
1296 break;
1297 case '\t':
1298
1299 lcd_print(' ');
1300 break;
1301 default:
1302
1303 lcd_print(c);
1304 break;
1305 }
1306 }
1307
1308
1309
1310 if (lcd_escape_len >= 2) {
1311 int processed = 0;
1312
1313 if (!strcmp(lcd_escape, "[2J")) {
1314
1315 lcd_clear_fast();
1316 processed = 1;
1317 } else if (!strcmp(lcd_escape, "[H")) {
1318
1319 lcd_addr_x = lcd_addr_y = 0;
1320 lcd_gotoxy();
1321 processed = 1;
1322 }
1323
1324 else if ((lcd_escape_len >= 3) &&
1325 (lcd_escape[0] == '[') &&
1326 (lcd_escape[1] == 'L')) {
1327 processed = handle_lcd_special_code();
1328 }
1329
1330
1331
1332
1333 if (processed || (lcd_escape_len >= LCD_ESCAPE_LEN))
1334 lcd_escape_len = -1;
1335 }
1336 }
1337
1338 return tmp - buf;
1339}
1340
1341static int lcd_open(struct inode *inode, struct file *file)
1342{
1343 if (lcd_open_cnt)
1344 return -EBUSY;
1345
1346 if (file->f_mode & FMODE_READ)
1347 return -EPERM;
1348
1349 if (lcd_must_clear) {
1350 lcd_clear_display();
1351 lcd_must_clear = 0;
1352 }
1353 lcd_open_cnt++;
1354 return nonseekable_open(inode, file);
1355}
1356
1357static int lcd_release(struct inode *inode, struct file *file)
1358{
1359 lcd_open_cnt--;
1360 return 0;
1361}
1362
1363static const struct file_operations lcd_fops = {
1364 .write = lcd_write,
1365 .open = lcd_open,
1366 .release = lcd_release,
1367 .llseek = no_llseek,
1368};
1369
1370static struct miscdevice lcd_dev = {
1371 LCD_MINOR,
1372 "lcd",
1373 &lcd_fops
1374};
1375
1376
1377void panel_lcd_print(char *s)
1378{
1379 if (lcd_enabled && lcd_initialized)
1380 lcd_write(NULL, s, strlen(s), NULL);
1381}
1382
1383
1384void lcd_init(void)
1385{
1386 switch (lcd_type) {
1387 case LCD_TYPE_OLD:
1388
1389 if (lcd_proto < 0)
1390 lcd_proto = LCD_PROTO_PARALLEL;
1391 if (lcd_charset < 0)
1392 lcd_charset = LCD_CHARSET_NORMAL;
1393 if (lcd_e_pin == PIN_NOT_SET)
1394 lcd_e_pin = PIN_STROBE;
1395 if (lcd_rs_pin == PIN_NOT_SET)
1396 lcd_rs_pin = PIN_AUTOLF;
1397
1398 if (lcd_width < 0)
1399 lcd_width = 40;
1400 if (lcd_bwidth < 0)
1401 lcd_bwidth = 40;
1402 if (lcd_hwidth < 0)
1403 lcd_hwidth = 64;
1404 if (lcd_height < 0)
1405 lcd_height = 2;
1406 break;
1407 case LCD_TYPE_KS0074:
1408
1409 if (lcd_proto < 0)
1410 lcd_proto = LCD_PROTO_SERIAL;
1411 if (lcd_charset < 0)
1412 lcd_charset = LCD_CHARSET_KS0074;
1413 if (lcd_bl_pin == PIN_NOT_SET)
1414 lcd_bl_pin = PIN_AUTOLF;
1415 if (lcd_cl_pin == PIN_NOT_SET)
1416 lcd_cl_pin = PIN_STROBE;
1417 if (lcd_da_pin == PIN_NOT_SET)
1418 lcd_da_pin = PIN_D0;
1419
1420 if (lcd_width < 0)
1421 lcd_width = 16;
1422 if (lcd_bwidth < 0)
1423 lcd_bwidth = 40;
1424 if (lcd_hwidth < 0)
1425 lcd_hwidth = 16;
1426 if (lcd_height < 0)
1427 lcd_height = 2;
1428 break;
1429 case LCD_TYPE_NEXCOM:
1430
1431 if (lcd_proto < 0)
1432 lcd_proto = LCD_PROTO_PARALLEL;
1433 if (lcd_charset < 0)
1434 lcd_charset = LCD_CHARSET_NORMAL;
1435 if (lcd_e_pin == PIN_NOT_SET)
1436 lcd_e_pin = PIN_AUTOLF;
1437 if (lcd_rs_pin == PIN_NOT_SET)
1438 lcd_rs_pin = PIN_SELECP;
1439 if (lcd_rw_pin == PIN_NOT_SET)
1440 lcd_rw_pin = PIN_INITP;
1441
1442 if (lcd_width < 0)
1443 lcd_width = 16;
1444 if (lcd_bwidth < 0)
1445 lcd_bwidth = 40;
1446 if (lcd_hwidth < 0)
1447 lcd_hwidth = 64;
1448 if (lcd_height < 0)
1449 lcd_height = 2;
1450 break;
1451 case LCD_TYPE_CUSTOM:
1452
1453 if (lcd_proto < 0)
1454 lcd_proto = DEFAULT_LCD_PROTO;
1455 if (lcd_charset < 0)
1456 lcd_charset = DEFAULT_LCD_CHARSET;
1457
1458 break;
1459 case LCD_TYPE_HANTRONIX:
1460
1461 default:
1462 if (lcd_proto < 0)
1463 lcd_proto = LCD_PROTO_PARALLEL;
1464 if (lcd_charset < 0)
1465 lcd_charset = LCD_CHARSET_NORMAL;
1466 if (lcd_e_pin == PIN_NOT_SET)
1467 lcd_e_pin = PIN_STROBE;
1468 if (lcd_rs_pin == PIN_NOT_SET)
1469 lcd_rs_pin = PIN_SELECP;
1470
1471 if (lcd_width < 0)
1472 lcd_width = 16;
1473 if (lcd_bwidth < 0)
1474 lcd_bwidth = 40;
1475 if (lcd_hwidth < 0)
1476 lcd_hwidth = 64;
1477 if (lcd_height < 0)
1478 lcd_height = 2;
1479 break;
1480 }
1481
1482
1483 if (lcd_width <= 0)
1484 lcd_width = DEFAULT_LCD_WIDTH;
1485 if (lcd_bwidth <= 0)
1486 lcd_bwidth = DEFAULT_LCD_BWIDTH;
1487 if (lcd_hwidth <= 0)
1488 lcd_hwidth = DEFAULT_LCD_HWIDTH;
1489 if (lcd_height <= 0)
1490 lcd_height = DEFAULT_LCD_HEIGHT;
1491
1492 if (lcd_proto == LCD_PROTO_SERIAL) {
1493 lcd_write_cmd = lcd_write_cmd_s;
1494 lcd_write_data = lcd_write_data_s;
1495 lcd_clear_fast = lcd_clear_fast_s;
1496
1497 if (lcd_cl_pin == PIN_NOT_SET)
1498 lcd_cl_pin = DEFAULT_LCD_PIN_SCL;
1499 if (lcd_da_pin == PIN_NOT_SET)
1500 lcd_da_pin = DEFAULT_LCD_PIN_SDA;
1501
1502 } else if (lcd_proto == LCD_PROTO_PARALLEL) {
1503 lcd_write_cmd = lcd_write_cmd_p8;
1504 lcd_write_data = lcd_write_data_p8;
1505 lcd_clear_fast = lcd_clear_fast_p8;
1506
1507 if (lcd_e_pin == PIN_NOT_SET)
1508 lcd_e_pin = DEFAULT_LCD_PIN_E;
1509 if (lcd_rs_pin == PIN_NOT_SET)
1510 lcd_rs_pin = DEFAULT_LCD_PIN_RS;
1511 if (lcd_rw_pin == PIN_NOT_SET)
1512 lcd_rw_pin = DEFAULT_LCD_PIN_RW;
1513 } else {
1514 lcd_write_cmd = lcd_write_cmd_tilcd;
1515 lcd_write_data = lcd_write_data_tilcd;
1516 lcd_clear_fast = lcd_clear_fast_tilcd;
1517 }
1518
1519 if (lcd_bl_pin == PIN_NOT_SET)
1520 lcd_bl_pin = DEFAULT_LCD_PIN_BL;
1521
1522 if (lcd_e_pin == PIN_NOT_SET)
1523 lcd_e_pin = PIN_NONE;
1524 if (lcd_rs_pin == PIN_NOT_SET)
1525 lcd_rs_pin = PIN_NONE;
1526 if (lcd_rw_pin == PIN_NOT_SET)
1527 lcd_rw_pin = PIN_NONE;
1528 if (lcd_bl_pin == PIN_NOT_SET)
1529 lcd_bl_pin = PIN_NONE;
1530 if (lcd_cl_pin == PIN_NOT_SET)
1531 lcd_cl_pin = PIN_NONE;
1532 if (lcd_da_pin == PIN_NOT_SET)
1533 lcd_da_pin = PIN_NONE;
1534
1535 if (lcd_charset < 0)
1536 lcd_charset = DEFAULT_LCD_CHARSET;
1537
1538 if (lcd_charset == LCD_CHARSET_KS0074)
1539 lcd_char_conv = lcd_char_conv_ks0074;
1540 else
1541 lcd_char_conv = NULL;
1542
1543 if (lcd_bl_pin != PIN_NONE)
1544 init_scan_timer();
1545
1546 pin_to_bits(lcd_e_pin, lcd_bits[LCD_PORT_D][LCD_BIT_E],
1547 lcd_bits[LCD_PORT_C][LCD_BIT_E]);
1548 pin_to_bits(lcd_rs_pin, lcd_bits[LCD_PORT_D][LCD_BIT_RS],
1549 lcd_bits[LCD_PORT_C][LCD_BIT_RS]);
1550 pin_to_bits(lcd_rw_pin, lcd_bits[LCD_PORT_D][LCD_BIT_RW],
1551 lcd_bits[LCD_PORT_C][LCD_BIT_RW]);
1552 pin_to_bits(lcd_bl_pin, lcd_bits[LCD_PORT_D][LCD_BIT_BL],
1553 lcd_bits[LCD_PORT_C][LCD_BIT_BL]);
1554 pin_to_bits(lcd_cl_pin, lcd_bits[LCD_PORT_D][LCD_BIT_CL],
1555 lcd_bits[LCD_PORT_C][LCD_BIT_CL]);
1556 pin_to_bits(lcd_da_pin, lcd_bits[LCD_PORT_D][LCD_BIT_DA],
1557 lcd_bits[LCD_PORT_C][LCD_BIT_DA]);
1558
1559
1560
1561
1562 lcd_initialized = 1;
1563 lcd_init_display();
1564
1565
1566#ifdef CONFIG_PANEL_CHANGE_MESSAGE
1567#ifdef CONFIG_PANEL_BOOT_MESSAGE
1568 panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE);
1569#endif
1570#else
1571 panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\nPanel-"
1572 PANEL_VERSION);
1573#endif
1574 lcd_addr_x = lcd_addr_y = 0;
1575
1576 lcd_must_clear = 1;
1577 lcd_gotoxy();
1578}
1579
1580
1581
1582
1583
1584static ssize_t keypad_read(struct file *file,
1585 char *buf, size_t count, loff_t *ppos)
1586{
1587
1588 unsigned i = *ppos;
1589 char *tmp = buf;
1590
1591 if (keypad_buflen == 0) {
1592 if (file->f_flags & O_NONBLOCK)
1593 return -EAGAIN;
1594
1595 interruptible_sleep_on(&keypad_read_wait);
1596 if (signal_pending(current))
1597 return -EINTR;
1598 }
1599
1600 for (; count-- > 0 && (keypad_buflen > 0);
1601 ++i, ++tmp, --keypad_buflen) {
1602 put_user(keypad_buffer[keypad_start], tmp);
1603 keypad_start = (keypad_start + 1) % KEYPAD_BUFFER;
1604 }
1605 *ppos = i;
1606
1607 return tmp - buf;
1608}
1609
1610static int keypad_open(struct inode *inode, struct file *file)
1611{
1612
1613 if (keypad_open_cnt)
1614 return -EBUSY;
1615
1616 if (file->f_mode & FMODE_WRITE)
1617 return -EPERM;
1618
1619 keypad_buflen = 0;
1620 keypad_open_cnt++;
1621 return 0;
1622}
1623
1624static int keypad_release(struct inode *inode, struct file *file)
1625{
1626 keypad_open_cnt--;
1627 return 0;
1628}
1629
1630static const struct file_operations keypad_fops = {
1631 .read = keypad_read,
1632 .open = keypad_open,
1633 .release = keypad_release,
1634 .llseek = default_llseek,
1635};
1636
1637static struct miscdevice keypad_dev = {
1638 KEYPAD_MINOR,
1639 "keypad",
1640 &keypad_fops
1641};
1642
1643static void keypad_send_key(char *string, int max_len)
1644{
1645 if (init_in_progress)
1646 return;
1647
1648
1649 if (keypad_open_cnt > 0) {
1650 while (max_len-- && keypad_buflen < KEYPAD_BUFFER && *string) {
1651 keypad_buffer[(keypad_start + keypad_buflen++) %
1652 KEYPAD_BUFFER] = *string++;
1653 }
1654 wake_up_interruptible(&keypad_read_wait);
1655 }
1656}
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668static void phys_scan_contacts(void)
1669{
1670 int bit, bitval;
1671 char oldval;
1672 char bitmask;
1673 char gndmask;
1674
1675 phys_prev = phys_curr;
1676 phys_read_prev = phys_read;
1677 phys_read = 0;
1678
1679
1680 oldval = r_dtr(pprt) | scan_mask_o;
1681
1682 w_dtr(pprt, oldval & ~scan_mask_o);
1683
1684
1685 bitmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
1686
1687 w_dtr(pprt, oldval);
1688
1689
1690
1691
1692
1693
1694 gndmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
1695
1696
1697 phys_read |= (pmask_t) gndmask << 40;
1698
1699 if (bitmask != gndmask) {
1700
1701
1702
1703
1704 for (bit = 0; bit < 8; bit++) {
1705 bitval = 1 << bit;
1706
1707 if (!(scan_mask_o & bitval))
1708 continue;
1709
1710 w_dtr(pprt, oldval & ~bitval);
1711 bitmask = PNL_PINPUT(r_str(pprt)) & ~gndmask;
1712 phys_read |= (pmask_t) bitmask << (5 * bit);
1713 }
1714 w_dtr(pprt, oldval);
1715 }
1716
1717
1718 phys_curr = (phys_prev & (phys_read ^ phys_read_prev)) |
1719 (phys_read & ~(phys_read ^ phys_read_prev));
1720}
1721
1722static inline int input_state_high(struct logical_input *input)
1723{
1724#if 0
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742 if (((phys_prev & input->mask) == input->value)
1743 && ((phys_curr & input->mask) > input->value)) {
1744 input->state = INPUT_ST_LOW;
1745 return 1;
1746 }
1747#endif
1748
1749 if ((phys_curr & input->mask) == input->value) {
1750 if ((input->type == INPUT_TYPE_STD) &&
1751 (input->high_timer == 0)) {
1752 input->high_timer++;
1753 if (input->u.std.press_fct != NULL)
1754 input->u.std.press_fct(input->u.std.press_data);
1755 } else if (input->type == INPUT_TYPE_KBD) {
1756
1757 keypressed = 1;
1758
1759 if (input->high_timer == 0) {
1760 char *press_str = input->u.kbd.press_str;
1761 if (press_str[0])
1762 keypad_send_key(press_str,
1763 sizeof(press_str));
1764 }
1765
1766 if (input->u.kbd.repeat_str[0]) {
1767 char *repeat_str = input->u.kbd.repeat_str;
1768 if (input->high_timer >= KEYPAD_REP_START) {
1769 input->high_timer -= KEYPAD_REP_DELAY;
1770 keypad_send_key(repeat_str,
1771 sizeof(repeat_str));
1772 }
1773
1774 inputs_stable = 0;
1775 }
1776
1777 if (input->high_timer < 255)
1778 input->high_timer++;
1779 }
1780 return 1;
1781 } else {
1782
1783 input->state = INPUT_ST_FALLING;
1784 input->fall_timer = 0;
1785 }
1786 return 0;
1787}
1788
1789static inline void input_state_falling(struct logical_input *input)
1790{
1791#if 0
1792
1793 if (((phys_prev & input->mask) == input->value)
1794 && ((phys_curr & input->mask) > input->value)) {
1795 input->state = INPUT_ST_LOW;
1796 return;
1797 }
1798#endif
1799
1800 if ((phys_curr & input->mask) == input->value) {
1801 if (input->type == INPUT_TYPE_KBD) {
1802
1803 keypressed = 1;
1804
1805 if (input->u.kbd.repeat_str[0]) {
1806 char *repeat_str = input->u.kbd.repeat_str;
1807 if (input->high_timer >= KEYPAD_REP_START)
1808 input->high_timer -= KEYPAD_REP_DELAY;
1809 keypad_send_key(repeat_str,
1810 sizeof(repeat_str));
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 keypad_send_key(release_str,
1829 sizeof(release_str));
1830 }
1831
1832 input->state = INPUT_ST_LOW;
1833 } else {
1834 input->fall_timer++;
1835 inputs_stable = 0;
1836 }
1837}
1838
1839static void panel_process_inputs(void)
1840{
1841 struct list_head *item;
1842 struct logical_input *input;
1843
1844#if 0
1845 printk(KERN_DEBUG
1846 "entering panel_process_inputs with pp=%016Lx & pc=%016Lx\n",
1847 phys_prev, phys_curr);
1848#endif
1849
1850 keypressed = 0;
1851 inputs_stable = 1;
1852 list_for_each(item, &logical_inputs) {
1853 input = list_entry(item, struct logical_input, list);
1854
1855 switch (input->state) {
1856 case INPUT_ST_LOW:
1857 if ((phys_curr & input->mask) != input->value)
1858 break;
1859
1860
1861
1862
1863
1864
1865
1866 if ((phys_prev & input->mask) == input->value)
1867 break;
1868 input->rise_timer = 0;
1869 input->state = INPUT_ST_RISING;
1870
1871 case INPUT_ST_RISING:
1872 if ((phys_curr & input->mask) != input->value) {
1873 input->state = INPUT_ST_LOW;
1874 break;
1875 }
1876 if (input->rise_timer < input->rise_time) {
1877 inputs_stable = 0;
1878 input->rise_timer++;
1879 break;
1880 }
1881 input->high_timer = 0;
1882 input->state = INPUT_ST_HIGH;
1883
1884 case INPUT_ST_HIGH:
1885 if (input_state_high(input))
1886 break;
1887
1888 case INPUT_ST_FALLING:
1889 input_state_falling(input);
1890 }
1891 }
1892}
1893
1894static void panel_scan_timer(void)
1895{
1896 if (keypad_enabled && keypad_initialized) {
1897 if (spin_trylock(&pprt_lock)) {
1898 phys_scan_contacts();
1899
1900
1901 spin_unlock(&pprt_lock);
1902 }
1903
1904 if (!inputs_stable || phys_curr != phys_prev)
1905 panel_process_inputs();
1906 }
1907
1908 if (lcd_enabled && lcd_initialized) {
1909 if (keypressed) {
1910 if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0))
1911 lcd_backlight(1);
1912 light_tempo = FLASH_LIGHT_TEMPO;
1913 } else if (light_tempo > 0) {
1914 light_tempo--;
1915 if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0))
1916 lcd_backlight(0);
1917 }
1918 }
1919
1920 mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME);
1921}
1922
1923static void init_scan_timer(void)
1924{
1925 if (scan_timer.function != NULL)
1926 return;
1927
1928 init_timer(&scan_timer);
1929 scan_timer.expires = jiffies + INPUT_POLL_TIME;
1930 scan_timer.data = 0;
1931 scan_timer.function = (void *)&panel_scan_timer;
1932 add_timer(&scan_timer);
1933}
1934
1935
1936
1937
1938
1939
1940static int input_name2mask(char *name, pmask_t *mask, pmask_t *value,
1941 char *imask, char *omask)
1942{
1943 static char sigtab[10] = "EeSsPpAaBb";
1944 char im, om;
1945 pmask_t m, v;
1946
1947 om = im = m = v = 0ULL;
1948 while (*name) {
1949 int in, out, bit, neg;
1950 for (in = 0; (in < sizeof(sigtab)) &&
1951 (sigtab[in] != *name); in++)
1952 ;
1953 if (in >= sizeof(sigtab))
1954 return 0;
1955 neg = (in & 1);
1956 in >>= 1;
1957 im |= (1 << in);
1958
1959 name++;
1960 if (isdigit(*name)) {
1961 out = *name - '0';
1962 om |= (1 << out);
1963 } else if (*name == '-')
1964 out = 8;
1965 else
1966 return 0;
1967
1968 bit = (out * 5) + in;
1969
1970 m |= 1ULL << bit;
1971 if (!neg)
1972 v |= 1ULL << bit;
1973 name++;
1974 }
1975 *mask = m;
1976 *value = v;
1977 if (imask)
1978 *imask |= im;
1979 if (omask)
1980 *omask |= om;
1981 return 1;
1982}
1983
1984
1985
1986
1987
1988static struct logical_input *panel_bind_key(char *name, char *press,
1989 char *repeat, char *release)
1990{
1991 struct logical_input *key;
1992
1993 key = kzalloc(sizeof(struct logical_input), GFP_KERNEL);
1994 if (!key) {
1995 printk(KERN_ERR "panel: not enough memory\n");
1996 return NULL;
1997 }
1998 if (!input_name2mask(name, &key->mask, &key->value, &scan_mask_i,
1999 &scan_mask_o)) {
2000 kfree(key);
2001 return NULL;
2002 }
2003
2004 key->type = INPUT_TYPE_KBD;
2005 key->state = INPUT_ST_LOW;
2006 key->rise_time = 1;
2007 key->fall_time = 1;
2008
2009#if 0
2010 printk(KERN_DEBUG "bind: <%s> : m=%016Lx v=%016Lx\n", name, key->mask,
2011 key->value);
2012#endif
2013 strncpy(key->u.kbd.press_str, press, sizeof(key->u.kbd.press_str));
2014 strncpy(key->u.kbd.repeat_str, repeat, sizeof(key->u.kbd.repeat_str));
2015 strncpy(key->u.kbd.release_str, release,
2016 sizeof(key->u.kbd.release_str));
2017 list_add(&key->list, &logical_inputs);
2018 return key;
2019}
2020
2021#if 0
2022
2023
2024
2025
2026
2027
2028static struct logical_input *panel_bind_callback(char *name,
2029 void (*press_fct) (int),
2030 int press_data,
2031 void (*release_fct) (int),
2032 int release_data)
2033{
2034 struct logical_input *callback;
2035
2036 callback = kmalloc(sizeof(struct logical_input), GFP_KERNEL);
2037 if (!callback) {
2038 printk(KERN_ERR "panel: not enough memory\n");
2039 return NULL;
2040 }
2041 memset(callback, 0, sizeof(struct logical_input));
2042 if (!input_name2mask(name, &callback->mask, &callback->value,
2043 &scan_mask_i, &scan_mask_o))
2044 return NULL;
2045
2046 callback->type = INPUT_TYPE_STD;
2047 callback->state = INPUT_ST_LOW;
2048 callback->rise_time = 1;
2049 callback->fall_time = 1;
2050 callback->u.std.press_fct = press_fct;
2051 callback->u.std.press_data = press_data;
2052 callback->u.std.release_fct = release_fct;
2053 callback->u.std.release_data = release_data;
2054 list_add(&callback->list, &logical_inputs);
2055 return callback;
2056}
2057#endif
2058
2059static void keypad_init(void)
2060{
2061 int keynum;
2062 init_waitqueue_head(&keypad_read_wait);
2063 keypad_buflen = 0;
2064
2065
2066
2067 for (keynum = 0; keypad_profile[keynum][0][0]; keynum++) {
2068 panel_bind_key(keypad_profile[keynum][0],
2069 keypad_profile[keynum][1],
2070 keypad_profile[keynum][2],
2071 keypad_profile[keynum][3]);
2072 }
2073
2074 init_scan_timer();
2075 keypad_initialized = 1;
2076}
2077
2078
2079
2080
2081
2082static int panel_notify_sys(struct notifier_block *this, unsigned long code,
2083 void *unused)
2084{
2085 if (lcd_enabled && lcd_initialized) {
2086 switch (code) {
2087 case SYS_DOWN:
2088 panel_lcd_print
2089 ("\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+");
2090 break;
2091 case SYS_HALT:
2092 panel_lcd_print
2093 ("\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+");
2094 break;
2095 case SYS_POWER_OFF:
2096 panel_lcd_print("\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+");
2097 break;
2098 default:
2099 break;
2100 }
2101 }
2102 return NOTIFY_DONE;
2103}
2104
2105static struct notifier_block panel_notifier = {
2106 panel_notify_sys,
2107 NULL,
2108 0
2109};
2110
2111static void panel_attach(struct parport *port)
2112{
2113 if (port->number != parport)
2114 return;
2115
2116 if (pprt) {
2117 printk(KERN_ERR
2118 "panel_attach(): port->number=%d parport=%d, "
2119 "already registered !\n",
2120 port->number, parport);
2121 return;
2122 }
2123
2124 pprt = parport_register_device(port, "panel", NULL, NULL,
2125 NULL,
2126
2127 0, (void *)&pprt);
2128 if (pprt == NULL) {
2129 pr_err("panel_attach(): port->number=%d parport=%d, "
2130 "parport_register_device() failed\n",
2131 port->number, parport);
2132 return;
2133 }
2134
2135 if (parport_claim(pprt)) {
2136 printk(KERN_ERR
2137 "Panel: could not claim access to parport%d. "
2138 "Aborting.\n", parport);
2139 goto err_unreg_device;
2140 }
2141
2142
2143
2144
2145 if (lcd_enabled) {
2146 lcd_init();
2147 if (misc_register(&lcd_dev))
2148 goto err_unreg_device;
2149 }
2150
2151 if (keypad_enabled) {
2152 keypad_init();
2153 if (misc_register(&keypad_dev))
2154 goto err_lcd_unreg;
2155 }
2156 return;
2157
2158err_lcd_unreg:
2159 if (lcd_enabled)
2160 misc_deregister(&lcd_dev);
2161err_unreg_device:
2162 parport_unregister_device(pprt);
2163 pprt = NULL;
2164}
2165
2166static void panel_detach(struct parport *port)
2167{
2168 if (port->number != parport)
2169 return;
2170
2171 if (!pprt) {
2172 printk(KERN_ERR
2173 "panel_detach(): port->number=%d parport=%d, "
2174 "nothing to unregister.\n",
2175 port->number, parport);
2176 return;
2177 }
2178
2179 if (keypad_enabled && keypad_initialized) {
2180 misc_deregister(&keypad_dev);
2181 keypad_initialized = 0;
2182 }
2183
2184 if (lcd_enabled && lcd_initialized) {
2185 misc_deregister(&lcd_dev);
2186 lcd_initialized = 0;
2187 }
2188
2189 parport_release(pprt);
2190 parport_unregister_device(pprt);
2191 pprt = NULL;
2192}
2193
2194static struct parport_driver panel_driver = {
2195 .name = "panel",
2196 .attach = panel_attach,
2197 .detach = panel_detach,
2198};
2199
2200
2201int panel_init(void)
2202{
2203
2204 if (keypad_type < 0)
2205 keypad_type = keypad_enabled;
2206
2207 if (lcd_type < 0)
2208 lcd_type = lcd_enabled;
2209
2210 if (parport < 0)
2211 parport = DEFAULT_PARPORT;
2212
2213
2214 switch (profile) {
2215 case PANEL_PROFILE_CUSTOM:
2216
2217 if (keypad_type < 0)
2218 keypad_type = DEFAULT_KEYPAD;
2219 if (lcd_type < 0)
2220 lcd_type = DEFAULT_LCD;
2221 break;
2222 case PANEL_PROFILE_OLD:
2223
2224 if (keypad_type < 0)
2225 keypad_type = KEYPAD_TYPE_OLD;
2226 if (lcd_type < 0)
2227 lcd_type = LCD_TYPE_OLD;
2228 if (lcd_width < 0)
2229 lcd_width = 16;
2230 if (lcd_hwidth < 0)
2231 lcd_hwidth = 16;
2232 break;
2233 case PANEL_PROFILE_NEW:
2234
2235 if (keypad_type < 0)
2236 keypad_type = KEYPAD_TYPE_NEW;
2237 if (lcd_type < 0)
2238 lcd_type = LCD_TYPE_KS0074;
2239 break;
2240 case PANEL_PROFILE_HANTRONIX:
2241
2242 if (keypad_type < 0)
2243 keypad_type = KEYPAD_TYPE_NONE;
2244 if (lcd_type < 0)
2245 lcd_type = LCD_TYPE_HANTRONIX;
2246 break;
2247 case PANEL_PROFILE_NEXCOM:
2248
2249 if (keypad_type < 0)
2250 keypad_type = KEYPAD_TYPE_NEXCOM;
2251 if (lcd_type < 0)
2252 lcd_type = LCD_TYPE_NEXCOM;
2253 break;
2254 case PANEL_PROFILE_LARGE:
2255
2256 if (keypad_type < 0)
2257 keypad_type = KEYPAD_TYPE_OLD;
2258 if (lcd_type < 0)
2259 lcd_type = LCD_TYPE_OLD;
2260 break;
2261 }
2262
2263 lcd_enabled = (lcd_type > 0);
2264 keypad_enabled = (keypad_type > 0);
2265
2266 switch (keypad_type) {
2267 case KEYPAD_TYPE_OLD:
2268 keypad_profile = old_keypad_profile;
2269 break;
2270 case KEYPAD_TYPE_NEW:
2271 keypad_profile = new_keypad_profile;
2272 break;
2273 case KEYPAD_TYPE_NEXCOM:
2274 keypad_profile = nexcom_keypad_profile;
2275 break;
2276 default:
2277 keypad_profile = NULL;
2278 break;
2279 }
2280
2281
2282 init_in_progress = 1;
2283
2284 if (parport_register_driver(&panel_driver)) {
2285 printk(KERN_ERR
2286 "Panel: could not register with parport. Aborting.\n");
2287 return -EIO;
2288 }
2289
2290 if (!lcd_enabled && !keypad_enabled) {
2291
2292 if (pprt) {
2293 parport_release(pprt);
2294 parport_unregister_device(pprt);
2295 pprt = NULL;
2296 }
2297 parport_unregister_driver(&panel_driver);
2298 printk(KERN_ERR "Panel driver version " PANEL_VERSION
2299 " disabled.\n");
2300 return -ENODEV;
2301 }
2302
2303 register_reboot_notifier(&panel_notifier);
2304
2305 if (pprt)
2306 printk(KERN_INFO "Panel driver version " PANEL_VERSION
2307 " registered on parport%d (io=0x%lx).\n", parport,
2308 pprt->port->base);
2309 else
2310 printk(KERN_INFO "Panel driver version " PANEL_VERSION
2311 " not yet registered\n");
2312
2313
2314 init_in_progress = 0;
2315 return 0;
2316}
2317
2318static int __init panel_init_module(void)
2319{
2320 return panel_init();
2321}
2322
2323static void __exit panel_cleanup_module(void)
2324{
2325 unregister_reboot_notifier(&panel_notifier);
2326
2327 if (scan_timer.function != NULL)
2328 del_timer(&scan_timer);
2329
2330 if (pprt != NULL) {
2331 if (keypad_enabled) {
2332 misc_deregister(&keypad_dev);
2333 keypad_initialized = 0;
2334 }
2335
2336 if (lcd_enabled) {
2337 panel_lcd_print("\x0cLCD driver " PANEL_VERSION
2338 "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-");
2339 misc_deregister(&lcd_dev);
2340 lcd_initialized = 0;
2341 }
2342
2343
2344 parport_release(pprt);
2345 parport_unregister_device(pprt);
2346 pprt = NULL;
2347 }
2348 parport_unregister_driver(&panel_driver);
2349}
2350
2351module_init(panel_init_module);
2352module_exit(panel_cleanup_module);
2353MODULE_AUTHOR("Willy Tarreau");
2354MODULE_LICENSE("GPL");
2355
2356
2357
2358
2359
2360
2361
2362