aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJarod Wilson <jarod@redhat.com>2010-09-15 14:56:03 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-20 23:06:07 -0400
commit693508df9824ecc2bf308a35b58159aa2fecf91f (patch)
treee94c9218ae5a459bb19b7bb0d05d2a7799fb6c26 /drivers
parenteaf2bcc923ed6c56da8f856e7dc380321433fbda (diff)
V4L/DVB: IR/imon: protect ictx's kc and last_keycode w/spinlock
Lest we get our keycodes wrong... Thus far, in practice, I've not found it to actually matter, but its one of the issues raised in https://bugzilla.kernel.org/show_bug.cgi?id=16351 that wasn't addressed by converting to using native IR keydown/up functions. Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/IR/imon.c52
1 files changed, 46 insertions, 6 deletions
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
index d36fe7239782..4b73b8eaf7dc 100644
--- a/drivers/media/IR/imon.c
+++ b/drivers/media/IR/imon.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD 2 * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD
3 * 3 *
4 * Copyright(C) 2009 Jarod Wilson <jarod@wilsonet.com> 4 * Copyright(C) 2010 Jarod Wilson <jarod@wilsonet.com>
5 * Portions based on the original lirc_imon driver, 5 * Portions based on the original lirc_imon driver,
6 * Copyright(C) 2004 Venky Raju(dev@venky.ws) 6 * Copyright(C) 2004 Venky Raju(dev@venky.ws)
7 * 7 *
@@ -125,6 +125,7 @@ struct imon_context {
125 struct input_dev *idev; /* input device for panel & IR mouse */ 125 struct input_dev *idev; /* input device for panel & IR mouse */
126 struct input_dev *touch; /* input device for touchscreen */ 126 struct input_dev *touch; /* input device for touchscreen */
127 127
128 spinlock_t kc_lock; /* make sure we get keycodes right */
128 u32 kc; /* current input keycode */ 129 u32 kc; /* current input keycode */
129 u32 last_keycode; /* last reported input keycode */ 130 u32 last_keycode; /* last reported input keycode */
130 u32 rc_scancode; /* the computed remote scancode */ 131 u32 rc_scancode; /* the computed remote scancode */
@@ -1210,6 +1211,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
1210 u8 right_shift = 1; 1211 u8 right_shift = 1;
1211 bool mouse_input = true; 1212 bool mouse_input = true;
1212 int dir = 0; 1213 int dir = 0;
1214 unsigned long flags;
1215
1216 spin_lock_irqsave(&ictx->kc_lock, flags);
1213 1217
1214 /* newer iMON device PAD or mouse button */ 1218 /* newer iMON device PAD or mouse button */
1215 if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { 1219 if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
@@ -1241,6 +1245,8 @@ static bool imon_mouse_event(struct imon_context *ictx,
1241 } else 1245 } else
1242 mouse_input = false; 1246 mouse_input = false;
1243 1247
1248 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1249
1244 if (mouse_input) { 1250 if (mouse_input) {
1245 dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); 1251 dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
1246 1252
@@ -1255,7 +1261,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
1255 buf[1] >> right_shift & 0x1); 1261 buf[1] >> right_shift & 0x1);
1256 } 1262 }
1257 input_sync(ictx->idev); 1263 input_sync(ictx->idev);
1264 spin_lock_irqsave(&ictx->kc_lock, flags);
1258 ictx->last_keycode = ictx->kc; 1265 ictx->last_keycode = ictx->kc;
1266 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1259 } 1267 }
1260 1268
1261 return mouse_input; 1269 return mouse_input;
@@ -1278,6 +1286,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
1278 char rel_x = 0x00, rel_y = 0x00; 1286 char rel_x = 0x00, rel_y = 0x00;
1279 u16 timeout, threshold; 1287 u16 timeout, threshold;
1280 u32 scancode = KEY_RESERVED; 1288 u32 scancode = KEY_RESERVED;
1289 unsigned long flags;
1281 1290
1282 /* 1291 /*
1283 * The imon directional pad functions more like a touchpad. Bytes 3 & 4 1292 * The imon directional pad functions more like a touchpad. Bytes 3 & 4
@@ -1301,7 +1310,11 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
1301 dir = stabilize((int)rel_x, (int)rel_y, 1310 dir = stabilize((int)rel_x, (int)rel_y,
1302 timeout, threshold); 1311 timeout, threshold);
1303 if (!dir) { 1312 if (!dir) {
1313 spin_lock_irqsave(&ictx->kc_lock,
1314 flags);
1304 ictx->kc = KEY_UNKNOWN; 1315 ictx->kc = KEY_UNKNOWN;
1316 spin_unlock_irqrestore(&ictx->kc_lock,
1317 flags);
1305 return; 1318 return;
1306 } 1319 }
1307 buf[2] = dir & 0xFF; 1320 buf[2] = dir & 0xFF;
@@ -1363,7 +1376,9 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
1363 dir = stabilize((int)rel_x, (int)rel_y, 1376 dir = stabilize((int)rel_x, (int)rel_y,
1364 timeout, threshold); 1377 timeout, threshold);
1365 if (!dir) { 1378 if (!dir) {
1379 spin_lock_irqsave(&ictx->kc_lock, flags);
1366 ictx->kc = KEY_UNKNOWN; 1380 ictx->kc = KEY_UNKNOWN;
1381 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1367 return; 1382 return;
1368 } 1383 }
1369 buf[2] = dir & 0xFF; 1384 buf[2] = dir & 0xFF;
@@ -1392,8 +1407,11 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
1392 } 1407 }
1393 } 1408 }
1394 1409
1395 if (scancode) 1410 if (scancode) {
1411 spin_lock_irqsave(&ictx->kc_lock, flags);
1396 ictx->kc = imon_remote_key_lookup(ictx, scancode); 1412 ictx->kc = imon_remote_key_lookup(ictx, scancode);
1413 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1414 }
1397} 1415}
1398 1416
1399/** 1417/**
@@ -1405,6 +1423,9 @@ static int imon_parse_press_type(struct imon_context *ictx,
1405 unsigned char *buf, u8 ktype) 1423 unsigned char *buf, u8 ktype)
1406{ 1424{
1407 int press_type = 0; 1425 int press_type = 0;
1426 unsigned long flags;
1427
1428 spin_lock_irqsave(&ictx->kc_lock, flags);
1408 1429
1409 /* key release of 0x02XXXXXX key */ 1430 /* key release of 0x02XXXXXX key */
1410 if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00) 1431 if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
@@ -1437,6 +1458,8 @@ static int imon_parse_press_type(struct imon_context *ictx,
1437 else 1458 else
1438 press_type = 1; 1459 press_type = 1;
1439 1460
1461 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1462
1440 return press_type; 1463 return press_type;
1441} 1464}
1442 1465
@@ -1449,6 +1472,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
1449 int len = urb->actual_length; 1472 int len = urb->actual_length;
1450 unsigned char *buf = urb->transfer_buffer; 1473 unsigned char *buf = urb->transfer_buffer;
1451 struct device *dev = ictx->dev; 1474 struct device *dev = ictx->dev;
1475 unsigned long flags;
1452 u32 kc; 1476 u32 kc;
1453 bool norelease = false; 1477 bool norelease = false;
1454 int i; 1478 int i;
@@ -1486,6 +1510,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
1486 } 1510 }
1487 } 1511 }
1488 1512
1513 spin_lock_irqsave(&ictx->kc_lock, flags);
1489 /* keyboard/mouse mode toggle button */ 1514 /* keyboard/mouse mode toggle button */
1490 if (kc == KEY_KEYBOARD && !ictx->release_code) { 1515 if (kc == KEY_KEYBOARD && !ictx->release_code) {
1491 ictx->last_keycode = kc; 1516 ictx->last_keycode = kc;
@@ -1493,6 +1518,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
1493 ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; 1518 ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
1494 dev_dbg(dev, "toggling to %s mode\n", 1519 dev_dbg(dev, "toggling to %s mode\n",
1495 ictx->pad_mouse ? "mouse" : "keyboard"); 1520 ictx->pad_mouse ? "mouse" : "keyboard");
1521 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1496 return; 1522 return;
1497 } else { 1523 } else {
1498 ictx->pad_mouse = 0; 1524 ictx->pad_mouse = 0;
@@ -1501,6 +1527,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
1501 } 1527 }
1502 1528
1503 ictx->kc = kc; 1529 ictx->kc = kc;
1530 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1504 1531
1505 /* send touchscreen events through input subsystem if touchpad data */ 1532 /* send touchscreen events through input subsystem if touchpad data */
1506 if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && 1533 if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
@@ -1534,8 +1561,10 @@ static void imon_incoming_packet(struct imon_context *ictx,
1534 if (press_type < 0) 1561 if (press_type < 0)
1535 goto not_input_data; 1562 goto not_input_data;
1536 1563
1564 spin_lock_irqsave(&ictx->kc_lock, flags);
1537 if (ictx->kc == KEY_UNKNOWN) 1565 if (ictx->kc == KEY_UNKNOWN)
1538 goto unknown_key; 1566 goto unknown_key;
1567 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1539 1568
1540 if (ktype != IMON_KEY_PANEL) { 1569 if (ktype != IMON_KEY_PANEL) {
1541 if (press_type == 0) 1570 if (press_type == 0)
@@ -1543,33 +1572,43 @@ static void imon_incoming_packet(struct imon_context *ictx,
1543 else { 1572 else {
1544 ir_keydown(ictx->rdev, ictx->rc_scancode, 1573 ir_keydown(ictx->rdev, ictx->rc_scancode,
1545 ictx->rc_toggle); 1574 ictx->rc_toggle);
1575 spin_lock_irqsave(&ictx->kc_lock, flags);
1546 ictx->last_keycode = ictx->kc; 1576 ictx->last_keycode = ictx->kc;
1577 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1547 } 1578 }
1548 return; 1579 return;
1549 } 1580 }
1550 1581
1551 /* Only panel type events left to process now */ 1582 /* Only panel type events left to process now */
1583 spin_lock_irqsave(&ictx->kc_lock, flags);
1584
1552 /* KEY_MUTE repeats from knob need to be suppressed */ 1585 /* KEY_MUTE repeats from knob need to be suppressed */
1553 if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { 1586 if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
1554 do_gettimeofday(&t); 1587 do_gettimeofday(&t);
1555 msec = tv2int(&t, &prev_time); 1588 msec = tv2int(&t, &prev_time);
1556 prev_time = t; 1589 prev_time = t;
1557 if (msec < idev->rep[REP_DELAY]) 1590 if (msec < idev->rep[REP_DELAY]) {
1591 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1558 return; 1592 return;
1593 }
1559 } 1594 }
1595 kc = ictx->kc;
1596
1597 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1560 1598
1561 input_report_key(idev, ictx->kc, press_type); 1599 input_report_key(idev, kc, press_type);
1562 input_sync(idev); 1600 input_sync(idev);
1563 1601
1564 /* panel keys don't generate a release */ 1602 /* panel keys don't generate a release */
1565 input_report_key(idev, ictx->kc, 0); 1603 input_report_key(idev, kc, 0);
1566 input_sync(idev); 1604 input_sync(idev);
1567 1605
1568 ictx->last_keycode = ictx->kc; 1606 ictx->last_keycode = kc;
1569 1607
1570 return; 1608 return;
1571 1609
1572unknown_key: 1610unknown_key:
1611 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1573 dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, 1612 dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
1574 (long long)scancode); 1613 (long long)scancode);
1575 return; 1614 return;
@@ -1927,6 +1966,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
1927 } 1966 }
1928 1967
1929 mutex_init(&ictx->lock); 1968 mutex_init(&ictx->lock);
1969 spin_lock_init(&ictx->kc_lock);
1930 1970
1931 mutex_lock(&ictx->lock); 1971 mutex_lock(&ictx->lock);
1932 1972