diff options
Diffstat (limited to 'drivers/misc/panel.c')
-rw-r--r-- | drivers/misc/panel.c | 191 |
1 files changed, 96 insertions, 95 deletions
diff --git a/drivers/misc/panel.c b/drivers/misc/panel.c index 6030ac5b8c63..ef2ece0f26af 100644 --- a/drivers/misc/panel.c +++ b/drivers/misc/panel.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <linux/list.h> | 56 | #include <linux/list.h> |
57 | #include <linux/notifier.h> | 57 | #include <linux/notifier.h> |
58 | #include <linux/reboot.h> | 58 | #include <linux/reboot.h> |
59 | #include <linux/workqueue.h> | ||
59 | #include <generated/utsrelease.h> | 60 | #include <generated/utsrelease.h> |
60 | 61 | ||
61 | #include <linux/io.h> | 62 | #include <linux/io.h> |
@@ -64,8 +65,6 @@ | |||
64 | #define LCD_MINOR 156 | 65 | #define LCD_MINOR 156 |
65 | #define KEYPAD_MINOR 185 | 66 | #define KEYPAD_MINOR 185 |
66 | 67 | ||
67 | #define PANEL_VERSION "0.9.5" | ||
68 | |||
69 | #define LCD_MAXBYTES 256 /* max burst write */ | 68 | #define LCD_MAXBYTES 256 /* max burst write */ |
70 | 69 | ||
71 | #define KEYPAD_BUFFER 64 | 70 | #define KEYPAD_BUFFER 64 |
@@ -77,8 +76,8 @@ | |||
77 | /* a key repeats this times INPUT_POLL_TIME */ | 76 | /* a key repeats this times INPUT_POLL_TIME */ |
78 | #define KEYPAD_REP_DELAY (2) | 77 | #define KEYPAD_REP_DELAY (2) |
79 | 78 | ||
80 | /* keep the light on this times INPUT_POLL_TIME for each flash */ | 79 | /* keep the light on this many seconds for each flash */ |
81 | #define FLASH_LIGHT_TEMPO (200) | 80 | #define FLASH_LIGHT_TEMPO (4) |
82 | 81 | ||
83 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ | 82 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ |
84 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) | 83 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) |
@@ -121,8 +120,6 @@ | |||
121 | #define PIN_SELECP 17 | 120 | #define PIN_SELECP 17 |
122 | #define PIN_NOT_SET 127 | 121 | #define PIN_NOT_SET 127 |
123 | 122 | ||
124 | #define LCD_FLAG_S 0x0001 | ||
125 | #define LCD_FLAG_ID 0x0002 | ||
126 | #define LCD_FLAG_B 0x0004 /* blink on */ | 123 | #define LCD_FLAG_B 0x0004 /* blink on */ |
127 | #define LCD_FLAG_C 0x0008 /* cursor on */ | 124 | #define LCD_FLAG_C 0x0008 /* cursor on */ |
128 | #define LCD_FLAG_D 0x0010 /* display on */ | 125 | #define LCD_FLAG_D 0x0010 /* display on */ |
@@ -256,7 +253,10 @@ static struct { | |||
256 | int hwidth; | 253 | int hwidth; |
257 | int charset; | 254 | int charset; |
258 | int proto; | 255 | int proto; |
259 | int light_tempo; | 256 | |
257 | struct delayed_work bl_work; | ||
258 | struct mutex bl_tempo_lock; /* Protects access to bl_tempo */ | ||
259 | bool bl_tempo; | ||
260 | 260 | ||
261 | /* TODO: use union here? */ | 261 | /* TODO: use union here? */ |
262 | struct { | 262 | struct { |
@@ -661,8 +661,6 @@ static void lcd_get_bits(unsigned int port, int *val) | |||
661 | } | 661 | } |
662 | } | 662 | } |
663 | 663 | ||
664 | static void init_scan_timer(void); | ||
665 | |||
666 | /* sets data port bits according to current signals values */ | 664 | /* sets data port bits according to current signals values */ |
667 | static int set_data_bits(void) | 665 | static int set_data_bits(void) |
668 | { | 666 | { |
@@ -794,11 +792,8 @@ static void lcd_send_serial(int byte) | |||
794 | } | 792 | } |
795 | 793 | ||
796 | /* turn the backlight on or off */ | 794 | /* turn the backlight on or off */ |
797 | static void lcd_backlight(int on) | 795 | static void __lcd_backlight(int on) |
798 | { | 796 | { |
799 | if (lcd.pins.bl == PIN_NONE) | ||
800 | return; | ||
801 | |||
802 | /* The backlight is activated by setting the AUTOFEED line to +5V */ | 797 | /* The backlight is activated by setting the AUTOFEED line to +5V */ |
803 | spin_lock_irq(&pprt_lock); | 798 | spin_lock_irq(&pprt_lock); |
804 | if (on) | 799 | if (on) |
@@ -809,6 +804,44 @@ static void lcd_backlight(int on) | |||
809 | spin_unlock_irq(&pprt_lock); | 804 | spin_unlock_irq(&pprt_lock); |
810 | } | 805 | } |
811 | 806 | ||
807 | static void lcd_backlight(int on) | ||
808 | { | ||
809 | if (lcd.pins.bl == PIN_NONE) | ||
810 | return; | ||
811 | |||
812 | mutex_lock(&lcd.bl_tempo_lock); | ||
813 | if (!lcd.bl_tempo) | ||
814 | __lcd_backlight(on); | ||
815 | mutex_unlock(&lcd.bl_tempo_lock); | ||
816 | } | ||
817 | |||
818 | static void lcd_bl_off(struct work_struct *work) | ||
819 | { | ||
820 | mutex_lock(&lcd.bl_tempo_lock); | ||
821 | if (lcd.bl_tempo) { | ||
822 | lcd.bl_tempo = false; | ||
823 | if (!(lcd.flags & LCD_FLAG_L)) | ||
824 | __lcd_backlight(0); | ||
825 | } | ||
826 | mutex_unlock(&lcd.bl_tempo_lock); | ||
827 | } | ||
828 | |||
829 | /* turn the backlight on for a little while */ | ||
830 | static void lcd_poke(void) | ||
831 | { | ||
832 | if (lcd.pins.bl == PIN_NONE) | ||
833 | return; | ||
834 | |||
835 | cancel_delayed_work_sync(&lcd.bl_work); | ||
836 | |||
837 | mutex_lock(&lcd.bl_tempo_lock); | ||
838 | if (!lcd.bl_tempo && !(lcd.flags & LCD_FLAG_L)) | ||
839 | __lcd_backlight(1); | ||
840 | lcd.bl_tempo = true; | ||
841 | schedule_delayed_work(&lcd.bl_work, FLASH_LIGHT_TEMPO * HZ); | ||
842 | mutex_unlock(&lcd.bl_tempo_lock); | ||
843 | } | ||
844 | |||
812 | /* send a command to the LCD panel in serial mode */ | 845 | /* send a command to the LCD panel in serial mode */ |
813 | static void lcd_write_cmd_s(int cmd) | 846 | static void lcd_write_cmd_s(int cmd) |
814 | { | 847 | { |
@@ -907,6 +940,13 @@ static void lcd_gotoxy(void) | |||
907 | (lcd.hwidth - 1) : lcd.bwidth - 1)); | 940 | (lcd.hwidth - 1) : lcd.bwidth - 1)); |
908 | } | 941 | } |
909 | 942 | ||
943 | static void lcd_home(void) | ||
944 | { | ||
945 | lcd.addr.x = 0; | ||
946 | lcd.addr.y = 0; | ||
947 | lcd_gotoxy(); | ||
948 | } | ||
949 | |||
910 | static void lcd_print(char c) | 950 | static void lcd_print(char c) |
911 | { | 951 | { |
912 | if (lcd.addr.x < lcd.bwidth) { | 952 | if (lcd.addr.x < lcd.bwidth) { |
@@ -925,9 +965,7 @@ static void lcd_clear_fast_s(void) | |||
925 | { | 965 | { |
926 | int pos; | 966 | int pos; |
927 | 967 | ||
928 | lcd.addr.x = 0; | 968 | lcd_home(); |
929 | lcd.addr.y = 0; | ||
930 | lcd_gotoxy(); | ||
931 | 969 | ||
932 | spin_lock_irq(&pprt_lock); | 970 | spin_lock_irq(&pprt_lock); |
933 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 971 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { |
@@ -939,9 +977,7 @@ static void lcd_clear_fast_s(void) | |||
939 | } | 977 | } |
940 | spin_unlock_irq(&pprt_lock); | 978 | spin_unlock_irq(&pprt_lock); |
941 | 979 | ||
942 | lcd.addr.x = 0; | 980 | lcd_home(); |
943 | lcd.addr.y = 0; | ||
944 | lcd_gotoxy(); | ||
945 | } | 981 | } |
946 | 982 | ||
947 | /* fills the display with spaces and resets X/Y */ | 983 | /* fills the display with spaces and resets X/Y */ |
@@ -949,9 +985,7 @@ static void lcd_clear_fast_p8(void) | |||
949 | { | 985 | { |
950 | int pos; | 986 | int pos; |
951 | 987 | ||
952 | lcd.addr.x = 0; | 988 | lcd_home(); |
953 | lcd.addr.y = 0; | ||
954 | lcd_gotoxy(); | ||
955 | 989 | ||
956 | spin_lock_irq(&pprt_lock); | 990 | spin_lock_irq(&pprt_lock); |
957 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 991 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { |
@@ -977,9 +1011,7 @@ static void lcd_clear_fast_p8(void) | |||
977 | } | 1011 | } |
978 | spin_unlock_irq(&pprt_lock); | 1012 | spin_unlock_irq(&pprt_lock); |
979 | 1013 | ||
980 | lcd.addr.x = 0; | 1014 | lcd_home(); |
981 | lcd.addr.y = 0; | ||
982 | lcd_gotoxy(); | ||
983 | } | 1015 | } |
984 | 1016 | ||
985 | /* fills the display with spaces and resets X/Y */ | 1017 | /* fills the display with spaces and resets X/Y */ |
@@ -987,9 +1019,7 @@ static void lcd_clear_fast_tilcd(void) | |||
987 | { | 1019 | { |
988 | int pos; | 1020 | int pos; |
989 | 1021 | ||
990 | lcd.addr.x = 0; | 1022 | lcd_home(); |
991 | lcd.addr.y = 0; | ||
992 | lcd_gotoxy(); | ||
993 | 1023 | ||
994 | spin_lock_irq(&pprt_lock); | 1024 | spin_lock_irq(&pprt_lock); |
995 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 1025 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { |
@@ -1000,9 +1030,7 @@ static void lcd_clear_fast_tilcd(void) | |||
1000 | 1030 | ||
1001 | spin_unlock_irq(&pprt_lock); | 1031 | spin_unlock_irq(&pprt_lock); |
1002 | 1032 | ||
1003 | lcd.addr.x = 0; | 1033 | lcd_home(); |
1004 | lcd.addr.y = 0; | ||
1005 | lcd_gotoxy(); | ||
1006 | } | 1034 | } |
1007 | 1035 | ||
1008 | /* clears the display and resets X/Y */ | 1036 | /* clears the display and resets X/Y */ |
@@ -1108,13 +1136,8 @@ static inline int handle_lcd_special_code(void) | |||
1108 | processed = 1; | 1136 | processed = 1; |
1109 | break; | 1137 | break; |
1110 | case '*': | 1138 | case '*': |
1111 | /* flash back light using the keypad timer */ | 1139 | /* flash back light */ |
1112 | if (scan_timer.function) { | 1140 | lcd_poke(); |
1113 | if (lcd.light_tempo == 0 && | ||
1114 | ((lcd.flags & LCD_FLAG_L) == 0)) | ||
1115 | lcd_backlight(1); | ||
1116 | lcd.light_tempo = FLASH_LIGHT_TEMPO; | ||
1117 | } | ||
1118 | processed = 1; | 1141 | processed = 1; |
1119 | break; | 1142 | break; |
1120 | case 'f': /* Small Font */ | 1143 | case 'f': /* Small Font */ |
@@ -1278,21 +1301,14 @@ static inline int handle_lcd_special_code(void) | |||
1278 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | 1301 | lcd_write_cmd(LCD_CMD_FUNCTION_SET |
1279 | | LCD_CMD_DATA_LEN_8BITS | 1302 | | LCD_CMD_DATA_LEN_8BITS |
1280 | | ((lcd.flags & LCD_FLAG_F) | 1303 | | ((lcd.flags & LCD_FLAG_F) |
1281 | ? LCD_CMD_TWO_LINES : 0) | ||
1282 | | ((lcd.flags & LCD_FLAG_N) | ||
1283 | ? LCD_CMD_FONT_5X10_DOTS | 1304 | ? LCD_CMD_FONT_5X10_DOTS |
1305 | : 0) | ||
1306 | | ((lcd.flags & LCD_FLAG_N) | ||
1307 | ? LCD_CMD_TWO_LINES | ||
1284 | : 0)); | 1308 | : 0)); |
1285 | /* check whether L flag was changed */ | 1309 | /* check whether L flag was changed */ |
1286 | else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) { | 1310 | else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) |
1287 | if (lcd.flags & (LCD_FLAG_L)) | 1311 | lcd_backlight(!!(lcd.flags & LCD_FLAG_L)); |
1288 | lcd_backlight(1); | ||
1289 | else if (lcd.light_tempo == 0) | ||
1290 | /* | ||
1291 | * switch off the light only when the tempo | ||
1292 | * lighting is gone | ||
1293 | */ | ||
1294 | lcd_backlight(0); | ||
1295 | } | ||
1296 | } | 1312 | } |
1297 | 1313 | ||
1298 | return processed; | 1314 | return processed; |
@@ -1376,9 +1392,7 @@ static void lcd_write_char(char c) | |||
1376 | processed = 1; | 1392 | processed = 1; |
1377 | } else if (!strcmp(lcd.esc_seq.buf, "[H")) { | 1393 | } else if (!strcmp(lcd.esc_seq.buf, "[H")) { |
1378 | /* cursor to home */ | 1394 | /* cursor to home */ |
1379 | lcd.addr.x = 0; | 1395 | lcd_home(); |
1380 | lcd.addr.y = 0; | ||
1381 | lcd_gotoxy(); | ||
1382 | processed = 1; | 1396 | processed = 1; |
1383 | } | 1397 | } |
1384 | /* codes starting with ^[[L */ | 1398 | /* codes starting with ^[[L */ |
@@ -1625,8 +1639,10 @@ static void lcd_init(void) | |||
1625 | else | 1639 | else |
1626 | lcd_char_conv = NULL; | 1640 | lcd_char_conv = NULL; |
1627 | 1641 | ||
1628 | if (lcd.pins.bl != PIN_NONE) | 1642 | if (lcd.pins.bl != PIN_NONE) { |
1629 | init_scan_timer(); | 1643 | mutex_init(&lcd.bl_tempo_lock); |
1644 | INIT_DELAYED_WORK(&lcd.bl_work, lcd_bl_off); | ||
1645 | } | ||
1630 | 1646 | ||
1631 | pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], | 1647 | pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], |
1632 | lcd_bits[LCD_PORT_C][LCD_BIT_E]); | 1648 | lcd_bits[LCD_PORT_C][LCD_BIT_E]); |
@@ -1655,14 +1671,11 @@ static void lcd_init(void) | |||
1655 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); | 1671 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); |
1656 | #endif | 1672 | #endif |
1657 | #else | 1673 | #else |
1658 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\nPanel-" | 1674 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE); |
1659 | PANEL_VERSION); | ||
1660 | #endif | 1675 | #endif |
1661 | lcd.addr.x = 0; | ||
1662 | lcd.addr.y = 0; | ||
1663 | /* clear the display on the next device opening */ | 1676 | /* clear the display on the next device opening */ |
1664 | lcd.must_clear = true; | 1677 | lcd.must_clear = true; |
1665 | lcd_gotoxy(); | 1678 | lcd_home(); |
1666 | } | 1679 | } |
1667 | 1680 | ||
1668 | /* | 1681 | /* |
@@ -1997,19 +2010,8 @@ static void panel_scan_timer(void) | |||
1997 | panel_process_inputs(); | 2010 | panel_process_inputs(); |
1998 | } | 2011 | } |
1999 | 2012 | ||
2000 | if (lcd.enabled && lcd.initialized) { | 2013 | if (keypressed && lcd.enabled && lcd.initialized) |
2001 | if (keypressed) { | 2014 | lcd_poke(); |
2002 | if (lcd.light_tempo == 0 && | ||
2003 | ((lcd.flags & LCD_FLAG_L) == 0)) | ||
2004 | lcd_backlight(1); | ||
2005 | lcd.light_tempo = FLASH_LIGHT_TEMPO; | ||
2006 | } else if (lcd.light_tempo > 0) { | ||
2007 | lcd.light_tempo--; | ||
2008 | if (lcd.light_tempo == 0 && | ||
2009 | ((lcd.flags & LCD_FLAG_L) == 0)) | ||
2010 | lcd_backlight(0); | ||
2011 | } | ||
2012 | } | ||
2013 | 2015 | ||
2014 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); | 2016 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); |
2015 | } | 2017 | } |
@@ -2270,25 +2272,26 @@ static void panel_detach(struct parport *port) | |||
2270 | if (scan_timer.function) | 2272 | if (scan_timer.function) |
2271 | del_timer_sync(&scan_timer); | 2273 | del_timer_sync(&scan_timer); |
2272 | 2274 | ||
2273 | if (pprt) { | 2275 | if (keypad.enabled) { |
2274 | if (keypad.enabled) { | 2276 | misc_deregister(&keypad_dev); |
2275 | misc_deregister(&keypad_dev); | 2277 | keypad_initialized = 0; |
2276 | keypad_initialized = 0; | 2278 | } |
2277 | } | ||
2278 | 2279 | ||
2279 | if (lcd.enabled) { | 2280 | if (lcd.enabled) { |
2280 | panel_lcd_print("\x0cLCD driver " PANEL_VERSION | 2281 | panel_lcd_print("\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-"); |
2281 | "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-"); | 2282 | misc_deregister(&lcd_dev); |
2282 | misc_deregister(&lcd_dev); | 2283 | if (lcd.pins.bl != PIN_NONE) { |
2283 | lcd.initialized = false; | 2284 | cancel_delayed_work_sync(&lcd.bl_work); |
2285 | __lcd_backlight(0); | ||
2284 | } | 2286 | } |
2285 | 2287 | lcd.initialized = false; | |
2286 | /* TODO: free all input signals */ | ||
2287 | parport_release(pprt); | ||
2288 | parport_unregister_device(pprt); | ||
2289 | pprt = NULL; | ||
2290 | unregister_reboot_notifier(&panel_notifier); | ||
2291 | } | 2288 | } |
2289 | |||
2290 | /* TODO: free all input signals */ | ||
2291 | parport_release(pprt); | ||
2292 | parport_unregister_device(pprt); | ||
2293 | pprt = NULL; | ||
2294 | unregister_reboot_notifier(&panel_notifier); | ||
2292 | } | 2295 | } |
2293 | 2296 | ||
2294 | static struct parport_driver panel_driver = { | 2297 | static struct parport_driver panel_driver = { |
@@ -2400,7 +2403,7 @@ static int __init panel_init_module(void) | |||
2400 | 2403 | ||
2401 | if (!lcd.enabled && !keypad.enabled) { | 2404 | if (!lcd.enabled && !keypad.enabled) { |
2402 | /* no device enabled, let's exit */ | 2405 | /* no device enabled, let's exit */ |
2403 | pr_err("driver version " PANEL_VERSION " disabled.\n"); | 2406 | pr_err("panel driver disabled.\n"); |
2404 | return -ENODEV; | 2407 | return -ENODEV; |
2405 | } | 2408 | } |
2406 | 2409 | ||
@@ -2411,12 +2414,10 @@ static int __init panel_init_module(void) | |||
2411 | } | 2414 | } |
2412 | 2415 | ||
2413 | if (pprt) | 2416 | if (pprt) |
2414 | pr_info("driver version " PANEL_VERSION | 2417 | pr_info("panel driver registered on parport%d (io=0x%lx).\n", |
2415 | " registered on parport%d (io=0x%lx).\n", parport, | 2418 | parport, pprt->port->base); |
2416 | pprt->port->base); | ||
2417 | else | 2419 | else |
2418 | pr_info("driver version " PANEL_VERSION | 2420 | pr_info("panel driver not yet registered\n"); |
2419 | " not yet registered\n"); | ||
2420 | return 0; | 2421 | return 0; |
2421 | } | 2422 | } |
2422 | 2423 | ||