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