diff options
author | Kevin Cernekee <cernekee@gmail.com> | 2013-02-14 01:19:59 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-02-14 12:17:57 -0500 |
commit | b5d6b851eab7f346ea5e69f46247b363b32b3670 (patch) | |
tree | 10ada693aa80f6ea6bce2aacef57dee3b51d74df /drivers/input/mouse/alps.c | |
parent | 24ba9707829818daab711eed7e41313d5e56d0b4 (diff) |
Input: ALPS - rework detection sequence
If the E6 report test passes, get the E7 and EC reports right away and
then try to match an entry in the table.
Pass in the alps_data struct, so that the detection code will be able to
set operating parameters based on information found during detection.
Change the version (psmouse->model) to report the protocol version only,
in preparation for supporting models that do not show up in the ID table.
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Tested-by: Dave Turvene <dturvene@dahetral.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r-- | drivers/input/mouse/alps.c | 124 |
1 files changed, 52 insertions, 72 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 1ca854b0b012..e6a27a5cbb1d 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -1451,86 +1451,76 @@ static int alps_hw_init(struct psmouse *psmouse) | |||
1451 | return ret; | 1451 | return ret; |
1452 | } | 1452 | } |
1453 | 1453 | ||
1454 | static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) | 1454 | static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv, |
1455 | unsigned char *e7, unsigned char *ec) | ||
1455 | { | 1456 | { |
1456 | static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; | 1457 | const struct alps_model_info *model; |
1457 | unsigned char param[4]; | ||
1458 | const struct alps_model_info *model = NULL; | ||
1459 | int i; | 1458 | int i; |
1460 | 1459 | ||
1460 | for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { | ||
1461 | model = &alps_model_data[i]; | ||
1462 | |||
1463 | if (!memcmp(e7, model->signature, sizeof(model->signature)) && | ||
1464 | (!model->command_mode_resp || | ||
1465 | model->command_mode_resp == ec[2])) { | ||
1466 | |||
1467 | priv->proto_version = model->proto_version; | ||
1468 | priv->flags = model->flags; | ||
1469 | priv->byte0 = model->byte0; | ||
1470 | priv->mask0 = model->mask0; | ||
1471 | |||
1472 | return 0; | ||
1473 | } | ||
1474 | } | ||
1475 | |||
1476 | return -EINVAL; | ||
1477 | } | ||
1478 | |||
1479 | static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) | ||
1480 | { | ||
1481 | unsigned char e6[4], e7[4], ec[4]; | ||
1482 | |||
1461 | /* | 1483 | /* |
1462 | * First try "E6 report". | 1484 | * First try "E6 report". |
1463 | * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed. | 1485 | * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed. |
1464 | * The bits 0-2 of the first byte will be 1s if some buttons are | 1486 | * The bits 0-2 of the first byte will be 1s if some buttons are |
1465 | * pressed. | 1487 | * pressed. |
1466 | */ | 1488 | */ |
1467 | if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, PSMOUSE_CMD_SETSCALE11, | 1489 | if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, |
1468 | param)) | 1490 | PSMOUSE_CMD_SETSCALE11, e6)) |
1469 | return NULL; | 1491 | return -EIO; |
1470 | 1492 | ||
1471 | if ((param[0] & 0xf8) != 0 || param[1] != 0 || | 1493 | if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100)) |
1472 | (param[2] != 10 && param[2] != 100)) | 1494 | return -EINVAL; |
1473 | return NULL; | ||
1474 | 1495 | ||
1475 | /* | 1496 | /* |
1476 | * Now try "E7 report". Allowed responses are in | 1497 | * Now get the "E7" and "EC" reports. These will uniquely identify |
1477 | * alps_model_data[].signature | 1498 | * most ALPS touchpads. |
1478 | */ | 1499 | */ |
1479 | if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, PSMOUSE_CMD_SETSCALE21, | 1500 | if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, |
1480 | param)) | 1501 | PSMOUSE_CMD_SETSCALE21, e7) || |
1481 | return NULL; | 1502 | alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, |
1482 | 1503 | PSMOUSE_CMD_RESET_WRAP, ec) || | |
1483 | if (version) { | 1504 | alps_exit_command_mode(psmouse)) |
1484 | for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++) | 1505 | return -EIO; |
1485 | /* empty */; | ||
1486 | *version = (param[0] << 8) | (param[1] << 4) | i; | ||
1487 | } | ||
1488 | |||
1489 | for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { | ||
1490 | if (!memcmp(param, alps_model_data[i].signature, | ||
1491 | sizeof(alps_model_data[i].signature))) { | ||
1492 | model = alps_model_data + i; | ||
1493 | break; | ||
1494 | } | ||
1495 | } | ||
1496 | 1506 | ||
1497 | if (model && model->proto_version > ALPS_PROTO_V2) { | 1507 | if (alps_match_table(psmouse, priv, e7, ec) == 0) |
1498 | /* | 1508 | return 0; |
1499 | * Need to check command mode response to identify | ||
1500 | * model | ||
1501 | */ | ||
1502 | model = NULL; | ||
1503 | if (alps_enter_command_mode(psmouse, param)) { | ||
1504 | psmouse_warn(psmouse, | ||
1505 | "touchpad failed to enter command mode\n"); | ||
1506 | } else { | ||
1507 | for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { | ||
1508 | if (alps_model_data[i].proto_version > ALPS_PROTO_V2 && | ||
1509 | alps_model_data[i].command_mode_resp == param[0]) { | ||
1510 | model = alps_model_data + i; | ||
1511 | break; | ||
1512 | } | ||
1513 | } | ||
1514 | alps_exit_command_mode(psmouse); | ||
1515 | 1509 | ||
1516 | if (!model) | 1510 | psmouse_info(psmouse, |
1517 | psmouse_dbg(psmouse, | 1511 | "Unknown ALPS touchpad: E7=%2.2x %2.2x %2.2x, EC=%2.2x %2.2x %2.2x\n", |
1518 | "Unknown command mode response %2.2x\n", | 1512 | e7[0], e7[1], e7[2], ec[0], ec[1], ec[2]); |
1519 | param[0]); | ||
1520 | } | ||
1521 | } | ||
1522 | 1513 | ||
1523 | return model; | 1514 | return -EINVAL; |
1524 | } | 1515 | } |
1525 | 1516 | ||
1526 | static int alps_reconnect(struct psmouse *psmouse) | 1517 | static int alps_reconnect(struct psmouse *psmouse) |
1527 | { | 1518 | { |
1528 | const struct alps_model_info *model; | 1519 | struct alps_data *priv = psmouse->private; |
1529 | 1520 | ||
1530 | psmouse_reset(psmouse); | 1521 | psmouse_reset(psmouse); |
1531 | 1522 | ||
1532 | model = alps_get_model(psmouse, NULL); | 1523 | if (alps_identify(psmouse, priv) < 0) |
1533 | if (!model) | ||
1534 | return -1; | 1524 | return -1; |
1535 | 1525 | ||
1536 | return alps_hw_init(psmouse); | 1526 | return alps_hw_init(psmouse); |
@@ -1549,9 +1539,7 @@ static void alps_disconnect(struct psmouse *psmouse) | |||
1549 | int alps_init(struct psmouse *psmouse) | 1539 | int alps_init(struct psmouse *psmouse) |
1550 | { | 1540 | { |
1551 | struct alps_data *priv; | 1541 | struct alps_data *priv; |
1552 | const struct alps_model_info *model; | ||
1553 | struct input_dev *dev1 = psmouse->dev, *dev2; | 1542 | struct input_dev *dev1 = psmouse->dev, *dev2; |
1554 | int version; | ||
1555 | 1543 | ||
1556 | priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); | 1544 | priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); |
1557 | dev2 = input_allocate_device(); | 1545 | dev2 = input_allocate_device(); |
@@ -1565,15 +1553,9 @@ int alps_init(struct psmouse *psmouse) | |||
1565 | 1553 | ||
1566 | psmouse_reset(psmouse); | 1554 | psmouse_reset(psmouse); |
1567 | 1555 | ||
1568 | model = alps_get_model(psmouse, &version); | 1556 | if (alps_identify(psmouse, priv) < 0) |
1569 | if (!model) | ||
1570 | goto init_fail; | 1557 | goto init_fail; |
1571 | 1558 | ||
1572 | priv->proto_version = model->proto_version; | ||
1573 | priv->byte0 = model->byte0; | ||
1574 | priv->mask0 = model->mask0; | ||
1575 | priv->flags = model->flags; | ||
1576 | |||
1577 | if (alps_hw_init(psmouse)) | 1559 | if (alps_hw_init(psmouse)) |
1578 | goto init_fail; | 1560 | goto init_fail; |
1579 | 1561 | ||
@@ -1678,18 +1660,16 @@ init_fail: | |||
1678 | 1660 | ||
1679 | int alps_detect(struct psmouse *psmouse, bool set_properties) | 1661 | int alps_detect(struct psmouse *psmouse, bool set_properties) |
1680 | { | 1662 | { |
1681 | int version; | 1663 | struct alps_data dummy; |
1682 | const struct alps_model_info *model; | ||
1683 | 1664 | ||
1684 | model = alps_get_model(psmouse, &version); | 1665 | if (alps_identify(psmouse, &dummy) < 0) |
1685 | if (!model) | ||
1686 | return -1; | 1666 | return -1; |
1687 | 1667 | ||
1688 | if (set_properties) { | 1668 | if (set_properties) { |
1689 | psmouse->vendor = "ALPS"; | 1669 | psmouse->vendor = "ALPS"; |
1690 | psmouse->name = model->flags & ALPS_DUALPOINT ? | 1670 | psmouse->name = dummy.flags & ALPS_DUALPOINT ? |
1691 | "DualPoint TouchPad" : "GlidePoint"; | 1671 | "DualPoint TouchPad" : "GlidePoint"; |
1692 | psmouse->model = version; | 1672 | psmouse->model = dummy.proto_version << 8; |
1693 | } | 1673 | } |
1694 | return 0; | 1674 | return 0; |
1695 | } | 1675 | } |