aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/auxdisplay/charlcd.c95
1 files changed, 78 insertions, 17 deletions
diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 674ffbae1c65..e92f3e25f51d 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -11,6 +11,7 @@
11 */ 11 */
12 12
13#include <linux/atomic.h> 13#include <linux/atomic.h>
14#include <linux/ctype.h>
14#include <linux/delay.h> 15#include <linux/delay.h>
15#include <linux/fs.h> 16#include <linux/fs.h>
16#include <linux/miscdevice.h> 17#include <linux/miscdevice.h>
@@ -294,6 +295,79 @@ static int charlcd_init_display(struct charlcd *lcd)
294} 295}
295 296
296/* 297/*
298 * Parses an unsigned integer from a string, until a non-digit character
299 * is found. The empty string is not accepted. No overflow checks are done.
300 *
301 * Returns whether the parsing was successful. Only in that case
302 * the output parameters are written to.
303 *
304 * TODO: If the kernel adds an inplace version of kstrtoul(), this function
305 * could be easily replaced by that.
306 */
307static bool parse_n(const char *s, unsigned long *res, const char **next_s)
308{
309 if (!isdigit(*s))
310 return false;
311
312 *res = 0;
313 while (isdigit(*s)) {
314 *res = *res * 10 + (*s - '0');
315 ++s;
316 }
317
318 *next_s = s;
319 return true;
320}
321
322/*
323 * Parses a movement command of the form "(.*);", where the group can be
324 * any number of subcommands of the form "(x|y)[0-9]+".
325 *
326 * Returns whether the command is valid. The position arguments are
327 * only written if the parsing was successful.
328 *
329 * For instance:
330 * - ";" returns (<original x>, <original y>).
331 * - "x1;" returns (1, <original y>).
332 * - "y2x1;" returns (1, 2).
333 * - "x12y34x56;" returns (56, 34).
334 * - "" fails.
335 * - "x" fails.
336 * - "x;" fails.
337 * - "x1" fails.
338 * - "xy12;" fails.
339 * - "x12yy12;" fails.
340 * - "xx" fails.
341 */
342static bool parse_xy(const char *s, unsigned long *x, unsigned long *y)
343{
344 unsigned long new_x = *x;
345 unsigned long new_y = *y;
346
347 for (;;) {
348 if (!*s)
349 return false;
350
351 if (*s == ';')
352 break;
353
354 if (*s == 'x') {
355 if (!parse_n(s + 1, &new_x, &s))
356 return false;
357 } else if (*s == 'y') {
358 if (!parse_n(s + 1, &new_y, &s))
359 return false;
360 } else {
361 return false;
362 }
363 }
364
365 *x = new_x;
366 *y = new_y;
367 return true;
368}
369
370/*
297 * These are the file operation function for user access to /dev/lcd 371 * These are the file operation function for user access to /dev/lcd
298 * This function can also be called from inside the kernel, by 372 * This function can also be called from inside the kernel, by
299 * setting file and ppos to NULL. 373 * setting file and ppos to NULL.
@@ -471,24 +545,11 @@ static inline int handle_lcd_special_code(struct charlcd *lcd)
471 } 545 }
472 case 'x': /* gotoxy : LxXXX[yYYY]; */ 546 case 'x': /* gotoxy : LxXXX[yYYY]; */
473 case 'y': /* gotoxy : LyYYY[xXXX]; */ 547 case 'y': /* gotoxy : LyYYY[xXXX]; */
474 if (!strchr(esc, ';')) 548 /* If the command is valid, move to the new address */
475 break; 549 if (parse_xy(esc, &priv->addr.x, &priv->addr.y))
476 550 charlcd_gotoxy(lcd);
477 while (*esc) {
478 if (*esc == 'x') {
479 esc++;
480 if (kstrtoul(esc, 10, &priv->addr.x) < 0)
481 break;
482 } else if (*esc == 'y') {
483 esc++;
484 if (kstrtoul(esc, 10, &priv->addr.y) < 0)
485 break;
486 } else {
487 break;
488 }
489 }
490 551
491 charlcd_gotoxy(lcd); 552 /* Regardless of its validity, mark as processed */
492 processed = 1; 553 processed = 1;
493 break; 554 break;
494 } 555 }