diff options
author | Jarod Wilson <jarod@redhat.com> | 2010-09-15 14:56:03 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-20 23:06:07 -0400 |
commit | 693508df9824ecc2bf308a35b58159aa2fecf91f (patch) | |
tree | e94c9218ae5a459bb19b7bb0d05d2a7799fb6c26 /drivers | |
parent | eaf2bcc923ed6c56da8f856e7dc380321433fbda (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.c | 52 |
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 | ||
1572 | unknown_key: | 1610 | unknown_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 | ||