aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/panel.c')
-rw-r--r--drivers/misc/panel.c191
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
664static 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 */
667static int set_data_bits(void) 665static 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 */
797static void lcd_backlight(int on) 795static 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
807static 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
818static 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 */
830static 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 */
813static void lcd_write_cmd_s(int cmd) 846static 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
943static void lcd_home(void)
944{
945 lcd.addr.x = 0;
946 lcd.addr.y = 0;
947 lcd_gotoxy();
948}
949
910static void lcd_print(char c) 950static 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
2294static struct parport_driver panel_driver = { 2297static 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