diff options
Diffstat (limited to 'drivers/staging/panel/panel.c')
| -rw-r--r-- | drivers/staging/panel/panel.c | 353 | 
1 files changed, 194 insertions, 159 deletions
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index cbc15c12098..4e9229363c3 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -171,8 +171,8 @@ struct logical_input {  	union {  		struct {	/* valid when type == INPUT_TYPE_STD */ -			void (*press_fct) (int); -			void (*release_fct) (int); +			void (*press_fct)(int); +			void (*release_fct)(int);  			int press_data;  			int release_data;  		} std; @@ -417,9 +417,9 @@ static char lcd_must_clear;  static char lcd_left_shift;  static char init_in_progress; -static void (*lcd_write_cmd) (int); -static void (*lcd_write_data) (int); -static void (*lcd_clear_fast) (void); +static void (*lcd_write_cmd)(int); +static void (*lcd_write_data)(int); +static void (*lcd_clear_fast)(void);  static DEFINE_SPINLOCK(pprt_lock);  static struct timer_list scan_timer; @@ -457,14 +457,12 @@ MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead");  static int lcd_type = -1;  module_param(lcd_type, int, 0000);  MODULE_PARM_DESC(lcd_type, -		 "LCD type: 0=none, 1=old //, 2=serial ks0074, " -		 "3=hantronix //, 4=nexcom //, 5=compiled-in"); +		 "LCD type: 0=none, 1=old //, 2=serial ks0074, 3=hantronix //, 4=nexcom //, 5=compiled-in");  static int lcd_proto = -1;  module_param(lcd_proto, int, 0000);  MODULE_PARM_DESC(lcd_proto, -		"LCD communication: 0=parallel (//), 1=serial," -		"2=TI LCD Interface"); +		 "LCD communication: 0=parallel (//), 1=serial, 2=TI LCD Interface");  static int lcd_charset = -1;  module_param(lcd_charset, int, 0000); @@ -473,8 +471,7 @@ MODULE_PARM_DESC(lcd_charset, "LCD character set: 0=standard, 1=KS0074");  static int keypad_type = -1;  module_param(keypad_type, int, 0000);  MODULE_PARM_DESC(keypad_type, -		 "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, " -		 "3=nexcom 4 keys"); +		 "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, 3=nexcom 4 keys");  static int profile = DEFAULT_PROFILE;  module_param(profile, int, 0000); @@ -494,38 +491,32 @@ MODULE_PARM_DESC(profile,  static int lcd_e_pin  = PIN_NOT_SET;  module_param(lcd_e_pin, int, 0000);  MODULE_PARM_DESC(lcd_e_pin, -		 "# of the // port pin connected to LCD 'E' signal, " -		 "with polarity (-17..17)"); +		 "# of the // port pin connected to LCD 'E' signal, with polarity (-17..17)");  static int lcd_rs_pin = PIN_NOT_SET;  module_param(lcd_rs_pin, int, 0000);  MODULE_PARM_DESC(lcd_rs_pin, -		 "# of the // port pin connected to LCD 'RS' signal, " -		 "with polarity (-17..17)"); +		 "# of the // port pin connected to LCD 'RS' signal, with polarity (-17..17)");  static int lcd_rw_pin = PIN_NOT_SET;  module_param(lcd_rw_pin, int, 0000);  MODULE_PARM_DESC(lcd_rw_pin, -		 "# of the // port pin connected to LCD 'RW' signal, " -		 "with polarity (-17..17)"); +		 "# of the // port pin connected to LCD 'RW' signal, with polarity (-17..17)");  static int lcd_bl_pin = PIN_NOT_SET;  module_param(lcd_bl_pin, int, 0000);  MODULE_PARM_DESC(lcd_bl_pin, -		 "# of the // port pin connected to LCD backlight, " -		 "with polarity (-17..17)"); +		 "# of the // port pin connected to LCD backlight, with polarity (-17..17)");  static int lcd_da_pin = PIN_NOT_SET;  module_param(lcd_da_pin, int, 0000);  MODULE_PARM_DESC(lcd_da_pin, -		 "# of the // port pin connected to serial LCD 'SDA' " -		 "signal, with polarity (-17..17)"); +		 "# of the // port pin connected to serial LCD 'SDA' signal, with polarity (-17..17)");  static int lcd_cl_pin = PIN_NOT_SET;  module_param(lcd_cl_pin, int, 0000);  MODULE_PARM_DESC(lcd_cl_pin, -		 "# of the // port pin connected to serial LCD 'SCL' " -		 "signal, with polarity (-17..17)"); +		 "# of the // port pin connected to serial LCD 'SCL' signal, with polarity (-17..17)");  static const unsigned char *lcd_char_conv; @@ -673,8 +664,12 @@ static void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val)  {  	int d_bit, c_bit, inv; -	d_val[0] = c_val[0] = d_val[1] = c_val[1] = 0; -	d_val[2] = c_val[2] = 0xFF; +	d_val[0] = 0; +	c_val[0] = 0; +	d_val[1] = 0; +	c_val[1] = 0; +	d_val[2] = 0xFF; +	c_val[2] = 0xFF;  	if (pin == 0)  		return; @@ -683,7 +678,8 @@ static void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val)  	if (inv)  		pin = -pin; -	d_bit = c_bit = 0; +	d_bit = 0; +	c_bit = 0;  	switch (pin) {  	case PIN_STROBE:	/* strobe, inverted */ @@ -720,10 +716,9 @@ static void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val)  /* sleeps that many milliseconds with a reschedule */  static void long_sleep(int ms)  { - -	if (in_interrupt()) +	if (in_interrupt()) {  		mdelay(ms); -	else { +	} else {  		current->state = TASK_INTERRUPTIBLE;  		schedule_timeout((ms * HZ + 999) / 1000);  	} @@ -876,7 +871,9 @@ static void lcd_print(char c)  static void lcd_clear_fast_s(void)  {  	int pos; -	lcd_addr_x = lcd_addr_y = 0; + +	lcd_addr_x = 0; +	lcd_addr_y = 0;  	lcd_gotoxy();  	spin_lock_irq(&pprt_lock); @@ -888,7 +885,8 @@ static void lcd_clear_fast_s(void)  	}  	spin_unlock_irq(&pprt_lock); -	lcd_addr_x = lcd_addr_y = 0; +	lcd_addr_x = 0; +	lcd_addr_y = 0;  	lcd_gotoxy();  } @@ -896,7 +894,9 @@ static void lcd_clear_fast_s(void)  static void lcd_clear_fast_p8(void)  {  	int pos; -	lcd_addr_x = lcd_addr_y = 0; + +	lcd_addr_x = 0; +	lcd_addr_y = 0;  	lcd_gotoxy();  	spin_lock_irq(&pprt_lock); @@ -923,7 +923,8 @@ static void lcd_clear_fast_p8(void)  	}  	spin_unlock_irq(&pprt_lock); -	lcd_addr_x = lcd_addr_y = 0; +	lcd_addr_x = 0; +	lcd_addr_y = 0;  	lcd_gotoxy();  } @@ -931,7 +932,9 @@ static void lcd_clear_fast_p8(void)  static void lcd_clear_fast_tilcd(void)  {  	int pos; -	lcd_addr_x = lcd_addr_y = 0; + +	lcd_addr_x = 0; +	lcd_addr_y = 0;  	lcd_gotoxy();  	spin_lock_irq(&pprt_lock); @@ -943,7 +946,8 @@ static void lcd_clear_fast_tilcd(void)  	spin_unlock_irq(&pprt_lock); -	lcd_addr_x = lcd_addr_y = 0; +	lcd_addr_x = 0; +	lcd_addr_y = 0;  	lcd_gotoxy();  } @@ -951,14 +955,14 @@ static void lcd_clear_fast_tilcd(void)  static void lcd_clear_display(void)  {  	lcd_write_cmd(0x01);	/* clear display */ -	lcd_addr_x = lcd_addr_y = 0; +	lcd_addr_x = 0; +	lcd_addr_y = 0;  	/* we must wait a few milliseconds (15) */  	long_sleep(15);  }  static void lcd_init_display(void)  { -  	lcd_flags = ((lcd_height > 1) ? LCD_FLAG_N : 0)  	    | LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B; @@ -1101,6 +1105,7 @@ static inline int handle_lcd_special_code(void)  		break;  	case 'k': {	/* kill end of line */  		int x; +  		for (x = lcd_addr_x; x < lcd_bwidth; x++)  			lcd_write_data(' '); @@ -1146,13 +1151,13 @@ static inline int handle_lcd_special_code(void)  		value = 0;  		while (*esc && cgoffset < 8) {  			shift ^= 4; -			if (*esc >= '0' && *esc <= '9') +			if (*esc >= '0' && *esc <= '9') {  				value |= (*esc - '0') << shift; -			else if (*esc >= 'A' && *esc <= 'Z') +			} else if (*esc >= 'A' && *esc <= 'Z') {  				value |= (*esc - 'A' + 10) << shift; -			else if (*esc >= 'a' && *esc <= 'z') +			} else if (*esc >= 'a' && *esc <= 'z') {  				value |= (*esc - 'a' + 10) << shift; -			else { +			} else {  				esc++;  				continue;  			} @@ -1188,8 +1193,9 @@ static inline int handle_lcd_special_code(void)  				esc++;  				if (kstrtoul(esc, 10, &lcd_addr_y) < 0)  					break; -			} else +			} else {  				break; +			}  		}  		lcd_gotoxy(); @@ -1226,111 +1232,114 @@ static inline int handle_lcd_special_code(void)  	return processed;  } +static void lcd_write_char(char c) +{ +	/* first, we'll test if we're in escape mode */ +	if ((c != '\n') && lcd_escape_len >= 0) { +		/* yes, let's add this char to the buffer */ +		lcd_escape[lcd_escape_len++] = c; +		lcd_escape[lcd_escape_len] = 0; +	} else { +		/* aborts any previous escape sequence */ +		lcd_escape_len = -1; + +		switch (c) { +		case LCD_ESCAPE_CHAR: +			/* start of an escape sequence */ +			lcd_escape_len = 0; +			lcd_escape[lcd_escape_len] = 0; +			break; +		case '\b': +			/* go back one char and clear it */ +			if (lcd_addr_x > 0) { +				/* check if we're not at the +				   end of the line */ +				if (lcd_addr_x < lcd_bwidth) +					/* back one char */ +					lcd_write_cmd(0x10); +				lcd_addr_x--; +			} +			/* replace with a space */ +			lcd_write_data(' '); +			/* back one char again */ +			lcd_write_cmd(0x10); +			break; +		case '\014': +			/* quickly clear the display */ +			lcd_clear_fast(); +			break; +		case '\n': +			/* flush the remainder of the current line and +			   go to the beginning of the next line */ +			for (; lcd_addr_x < lcd_bwidth; lcd_addr_x++) +				lcd_write_data(' '); +			lcd_addr_x = 0; +			lcd_addr_y = (lcd_addr_y + 1) % lcd_height; +			lcd_gotoxy(); +			break; +		case '\r': +			/* go to the beginning of the same line */ +			lcd_addr_x = 0; +			lcd_gotoxy(); +			break; +		case '\t': +			/* print a space instead of the tab */ +			lcd_print(' '); +			break; +		default: +			/* simply print this char */ +			lcd_print(c); +			break; +		} +	} + +	/* now we'll see if we're in an escape mode and if the current +	   escape sequence can be understood. */ +	if (lcd_escape_len >= 2) { +		int processed = 0; + +		if (!strcmp(lcd_escape, "[2J")) { +			/* clear the display */ +			lcd_clear_fast(); +			processed = 1; +		} else if (!strcmp(lcd_escape, "[H")) { +			/* cursor to home */ +			lcd_addr_x = 0; +			lcd_addr_y = 0; +			lcd_gotoxy(); +			processed = 1; +		} +		/* codes starting with ^[[L */ +		else if ((lcd_escape_len >= 3) && +			 (lcd_escape[0] == '[') && +			 (lcd_escape[1] == 'L')) { +			processed = handle_lcd_special_code(); +		} + +		/* LCD special escape codes */ +		/* flush the escape sequence if it's been processed +		   or if it is getting too long. */ +		if (processed || (lcd_escape_len >= LCD_ESCAPE_LEN)) +			lcd_escape_len = -1; +	} /* escape codes */ +} +  static ssize_t lcd_write(struct file *file, -			 const char *buf, size_t count, loff_t *ppos) +			 const char __user *buf, size_t count, loff_t *ppos)  { -	const char *tmp = buf; +	const char __user *tmp = buf;  	char c; -	for (; count-- > 0; (ppos ? (*ppos)++ : 0), ++tmp) { +	for (; count-- > 0; (*ppos)++, tmp++) {  		if (!in_interrupt() && (((count + 1) & 0x1f) == 0))  			/* let's be a little nice with other processes  			   that need some CPU */  			schedule(); -		if (ppos == NULL && file == NULL) -			/* let's not use get_user() from the kernel ! */ -			c = *tmp; -		else if (get_user(c, tmp)) +		if (get_user(c, tmp))  			return -EFAULT; -		/* first, we'll test if we're in escape mode */ -		if ((c != '\n') && lcd_escape_len >= 0) { -			/* yes, let's add this char to the buffer */ -			lcd_escape[lcd_escape_len++] = c; -			lcd_escape[lcd_escape_len] = 0; -		} else { -			/* aborts any previous escape sequence */ -			lcd_escape_len = -1; - -			switch (c) { -			case LCD_ESCAPE_CHAR: -				/* start of an escape sequence */ -				lcd_escape_len = 0; -				lcd_escape[lcd_escape_len] = 0; -				break; -			case '\b': -				/* go back one char and clear it */ -				if (lcd_addr_x > 0) { -					/* check if we're not at the -					   end of the line */ -					if (lcd_addr_x < lcd_bwidth) -						/* back one char */ -						lcd_write_cmd(0x10); -					lcd_addr_x--; -				} -				/* replace with a space */ -				lcd_write_data(' '); -				/* back one char again */ -				lcd_write_cmd(0x10); -				break; -			case '\014': -				/* quickly clear the display */ -				lcd_clear_fast(); -				break; -			case '\n': -				/* flush the remainder of the current line and -				   go to the beginning of the next line */ -				for (; lcd_addr_x < lcd_bwidth; lcd_addr_x++) -					lcd_write_data(' '); -				lcd_addr_x = 0; -				lcd_addr_y = (lcd_addr_y + 1) % lcd_height; -				lcd_gotoxy(); -				break; -			case '\r': -				/* go to the beginning of the same line */ -				lcd_addr_x = 0; -				lcd_gotoxy(); -				break; -			case '\t': -				/* print a space instead of the tab */ -				lcd_print(' '); -				break; -			default: -				/* simply print this char */ -				lcd_print(c); -				break; -			} -		} - -		/* now we'll see if we're in an escape mode and if the current -		   escape sequence can be understood. */ -		if (lcd_escape_len >= 2) { -			int processed = 0; - -			if (!strcmp(lcd_escape, "[2J")) { -				/* clear the display */ -				lcd_clear_fast(); -				processed = 1; -			} else if (!strcmp(lcd_escape, "[H")) { -				/* cursor to home */ -				lcd_addr_x = lcd_addr_y = 0; -				lcd_gotoxy(); -				processed = 1; -			} -			/* codes starting with ^[[L */ -			else if ((lcd_escape_len >= 3) && -				 (lcd_escape[0] == '[') && -				 (lcd_escape[1] == 'L')) { -				processed = handle_lcd_special_code(); -			} - -			/* LCD special escape codes */ -			/* flush the escape sequence if it's been processed -			   or if it is getting too long. */ -			if (processed || (lcd_escape_len >= LCD_ESCAPE_LEN)) -				lcd_escape_len = -1; -		} /* escape codes */ +		lcd_write_char(c);  	}  	return tmp - buf; @@ -1374,8 +1383,19 @@ static struct miscdevice lcd_dev = {  /* public function usable from the kernel for any purpose */  static void panel_lcd_print(const char *s)  { -	if (lcd_enabled && lcd_initialized) -		lcd_write(NULL, s, strlen(s), NULL); +	const char *tmp = s; +	int count = strlen(s); + +	if (lcd_enabled && lcd_initialized) { +		for (; count-- > 0; tmp++) { +			if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) +				/* let's be a little nice with other processes +				   that need some CPU */ +				schedule(); + +			lcd_write_char(*tmp); +		} +	}  }  /* initialize the LCD driver */ @@ -1569,7 +1589,8 @@ static void lcd_init(void)  	panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\nPanel-"  			PANEL_VERSION);  #endif -	lcd_addr_x = lcd_addr_y = 0; +	lcd_addr_x = 0; +	lcd_addr_y = 0;  	/* clear the display on the next device opening */  	lcd_must_clear = 1;  	lcd_gotoxy(); @@ -1580,18 +1601,17 @@ static void lcd_init(void)   */  static ssize_t keypad_read(struct file *file, -			   char *buf, size_t count, loff_t *ppos) +			   char __user *buf, size_t count, loff_t *ppos)  { -  	unsigned i = *ppos; -	char *tmp = buf; +	char __user *tmp = buf;  	if (keypad_buflen == 0) {  		if (file->f_flags & O_NONBLOCK)  			return -EAGAIN; -		interruptible_sleep_on(&keypad_read_wait); -		if (signal_pending(current)) +		if (wait_event_interruptible(keypad_read_wait, +					     keypad_buflen != 0))  			return -EINTR;  	} @@ -1607,7 +1627,6 @@ static ssize_t keypad_read(struct file *file,  static int keypad_open(struct inode *inode, struct file *file)  { -  	if (keypad_open_cnt)  		return -EBUSY;	/* open only once at a time */ @@ -1737,8 +1756,8 @@ static inline int input_state_high(struct logical_input *input)  	 * release function.  	 * eg: 0 -(press A)-> A -(press B)-> AB : don't match A's release.  	 */ -	if (((phys_prev & input->mask) == input->value) -	    && ((phys_curr & input->mask) > input->value)) { +	if (((phys_prev & input->mask) == input->value) && +	    ((phys_curr & input->mask) >  input->value)) {  		input->state = INPUT_ST_LOW; /* invalidate */  		return 1;  	} @@ -1756,16 +1775,20 @@ static inline int input_state_high(struct logical_input *input)  			if (input->high_timer == 0) {  				char *press_str = input->u.kbd.press_str; +  				if (press_str[0]) {  					int s = sizeof(input->u.kbd.press_str); +  					keypad_send_key(press_str, s);  				}  			}  			if (input->u.kbd.repeat_str[0]) {  				char *repeat_str = input->u.kbd.repeat_str; +  				if (input->high_timer >= KEYPAD_REP_START) {  					int s = sizeof(input->u.kbd.repeat_str); +  					input->high_timer -= KEYPAD_REP_DELAY;  					keypad_send_key(repeat_str, s);  				} @@ -1789,8 +1812,8 @@ static inline void input_state_falling(struct logical_input *input)  {  #if 0  	/* FIXME !!! same comment as in input_state_high */ -	if (((phys_prev & input->mask) == input->value) -	    && ((phys_curr & input->mask) > input->value)) { +	if (((phys_prev & input->mask) == input->value) && +	    ((phys_curr & input->mask) >  input->value)) {  		input->state = INPUT_ST_LOW;	/* invalidate */  		return;  	} @@ -1803,8 +1826,10 @@ static inline void input_state_falling(struct logical_input *input)  			if (input->u.kbd.repeat_str[0]) {  				char *repeat_str = input->u.kbd.repeat_str; +  				if (input->high_timer >= KEYPAD_REP_START) {  					int s = sizeof(input->u.kbd.repeat_str); +  					input->high_timer -= KEYPAD_REP_DELAY;  					keypad_send_key(repeat_str, s);  				} @@ -1820,12 +1845,15 @@ static inline void input_state_falling(struct logical_input *input)  		/* call release event */  		if (input->type == INPUT_TYPE_STD) {  			void (*release_fct)(int) = input->u.std.release_fct; +  			if (release_fct != NULL)  				release_fct(input->u.std.release_data);  		} else if (input->type == INPUT_TYPE_KBD) {  			char *release_str = input->u.kbd.release_str; +  			if (release_str[0]) {  				int s = sizeof(input->u.kbd.release_str); +  				keypad_send_key(release_str, s);  			}  		} @@ -1939,12 +1967,17 @@ static int input_name2mask(const char *name, pmask_t *mask, pmask_t *value,  	char im, om;  	pmask_t m, v; -	om = im = m = v = 0ULL; +	om = 0ULL; +	im = 0ULL; +	m = 0ULL; +	v = 0ULL;  	while (*name) {  		int in, out, bit, neg; -		for (in = 0; (in < sizeof(sigtab)) && -			     (sigtab[in] != *name); in++) + +		for (in = 0; (in < sizeof(sigtab)) && (sigtab[in] != *name); +		     in++)  			; +  		if (in >= sizeof(sigtab))  			return 0;	/* input name not found */  		neg = (in & 1);	/* odd (lower) names are negated */ @@ -1955,10 +1988,11 @@ static int input_name2mask(const char *name, pmask_t *mask, pmask_t *value,  		if (isdigit(*name)) {  			out = *name - '0';  			om |= (1 << out); -		} else if (*name == '-') +		} else if (*name == '-') {  			out = 8; -		else +		} else {  			return 0;	/* unknown bit name */ +		}  		bit = (out * 5) + in; @@ -1986,7 +2020,7 @@ static struct logical_input *panel_bind_key(const char *name, const char *press,  {  	struct logical_input *key; -	key = kzalloc(sizeof(struct logical_input), GFP_KERNEL); +	key = kzalloc(sizeof(*key), GFP_KERNEL);  	if (!key)  		return NULL; @@ -2017,14 +2051,14 @@ static struct logical_input *panel_bind_key(const char *name, const char *press,   * be bound.   */  static struct logical_input *panel_bind_callback(char *name, -						 void (*press_fct) (int), +						 void (*press_fct)(int),  						 int press_data, -						 void (*release_fct) (int), +						 void (*release_fct)(int),  						 int release_data)  {  	struct logical_input *callback; -	callback = kmalloc(sizeof(struct logical_input), GFP_KERNEL); +	callback = kmalloc(sizeof(*callback), GFP_KERNEL);  	if (!callback)  		return NULL; @@ -2049,6 +2083,7 @@ static struct logical_input *panel_bind_callback(char *name,  static void keypad_init(void)  {  	int keynum; +  	init_waitqueue_head(&keypad_read_wait);  	keypad_buflen = 0;	/* flushes any eventual noisy keystroke */ @@ -2307,7 +2342,7 @@ static void __exit panel_cleanup_module(void)  	unregister_reboot_notifier(&panel_notifier);  	if (scan_timer.function != NULL) -		del_timer(&scan_timer); +		del_timer_sync(&scan_timer);  	if (pprt != NULL) {  		if (keypad_enabled) {  | 
