Merge branch 'psmouse' into next
Merge various PS/2 handling improvements.
This commit is contained in:
@ -827,7 +827,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
|
||||
unsigned char *packet = psmouse->packet;
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
struct input_dev *dev2 = priv->dev2;
|
||||
int x, y, z, left, right, middle;
|
||||
int x, y, z;
|
||||
|
||||
/*
|
||||
* We can use Byte5 to distinguish if the packet is from Touchpad
|
||||
@ -847,9 +847,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
|
||||
x = packet[1] | ((packet[3] & 0x20) << 2);
|
||||
y = packet[2] | ((packet[3] & 0x40) << 1);
|
||||
z = packet[4];
|
||||
left = packet[3] & 0x01;
|
||||
right = packet[3] & 0x02;
|
||||
middle = packet[3] & 0x04;
|
||||
|
||||
/* To prevent the cursor jump when finger lifted */
|
||||
if (x == 0x7F && y == 0x7F && z == 0x7F)
|
||||
@ -859,9 +856,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
|
||||
input_report_rel(dev2, REL_X, (char)x / 4);
|
||||
input_report_rel(dev2, REL_Y, -((char)y / 4));
|
||||
|
||||
input_report_key(dev2, BTN_LEFT, left);
|
||||
input_report_key(dev2, BTN_RIGHT, right);
|
||||
input_report_key(dev2, BTN_MIDDLE, middle);
|
||||
psmouse_report_standard_buttons(dev2, packet[3]);
|
||||
|
||||
input_sync(dev2);
|
||||
return;
|
||||
@ -871,8 +866,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
|
||||
x = packet[1] | ((packet[3] & 0x78) << 4);
|
||||
y = packet[2] | ((packet[4] & 0x78) << 4);
|
||||
z = packet[5];
|
||||
left = packet[3] & 0x01;
|
||||
right = packet[3] & 0x02;
|
||||
|
||||
if (z > 30)
|
||||
input_report_key(dev, BTN_TOUCH, 1);
|
||||
@ -888,8 +881,8 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
|
||||
input_report_key(dev, BTN_TOOL_FINGER, z > 0);
|
||||
|
||||
/* v6 touchpad does not have middle button */
|
||||
input_report_key(dev, BTN_LEFT, left);
|
||||
input_report_key(dev, BTN_RIGHT, right);
|
||||
packet[3] &= ~BIT(2);
|
||||
psmouse_report_standard_buttons(dev2, packet[3]);
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
@ -1098,7 +1091,7 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
|
||||
struct alps_data *priv = psmouse->private;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
struct input_dev *dev2 = priv->dev2;
|
||||
int x, y, z, left, right, middle;
|
||||
int x, y, z;
|
||||
|
||||
/* It should be a DualPoint when received trackstick packet */
|
||||
if (!(priv->flags & ALPS_DUALPOINT)) {
|
||||
@ -1112,16 +1105,10 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
|
||||
((packet[3] & 0x20) << 1);
|
||||
z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
|
||||
|
||||
left = (packet[1] & 0x01);
|
||||
right = (packet[1] & 0x02) >> 1;
|
||||
middle = (packet[1] & 0x04) >> 2;
|
||||
|
||||
input_report_rel(dev2, REL_X, (char)x);
|
||||
input_report_rel(dev2, REL_Y, -((char)y));
|
||||
|
||||
input_report_key(dev2, BTN_LEFT, left);
|
||||
input_report_key(dev2, BTN_RIGHT, right);
|
||||
input_report_key(dev2, BTN_MIDDLE, middle);
|
||||
psmouse_report_standard_buttons(dev2, packet[1]);
|
||||
|
||||
input_sync(dev2);
|
||||
}
|
||||
@ -1503,10 +1490,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
|
||||
alps_report_buttons(dev, dev2,
|
||||
packet[0] & 1, packet[0] & 2, packet[0] & 4);
|
||||
|
||||
input_report_rel(dev, REL_X,
|
||||
packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
|
||||
input_report_rel(dev, REL_Y,
|
||||
packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
|
||||
psmouse_report_standard_motion(dev, packet);
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c,
|
||||
unsigned char *param)
|
||||
{
|
||||
if (psmouse_sliced_command(psmouse, c) ||
|
||||
if (ps2_sliced_command(&psmouse->ps2dev, c) ||
|
||||
ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
|
||||
psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c);
|
||||
return -1;
|
||||
@ -107,8 +107,8 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
|
||||
|
||||
switch (etd->hw_version) {
|
||||
case 1:
|
||||
if (psmouse_sliced_command(psmouse, ETP_REGISTER_READ) ||
|
||||
psmouse_sliced_command(psmouse, reg) ||
|
||||
if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_READ) ||
|
||||
ps2_sliced_command(&psmouse->ps2dev, reg) ||
|
||||
ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
|
||||
rc = -1;
|
||||
}
|
||||
@ -162,9 +162,9 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
|
||||
|
||||
switch (etd->hw_version) {
|
||||
case 1:
|
||||
if (psmouse_sliced_command(psmouse, ETP_REGISTER_WRITE) ||
|
||||
psmouse_sliced_command(psmouse, reg) ||
|
||||
psmouse_sliced_command(psmouse, val) ||
|
||||
if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_WRITE) ||
|
||||
ps2_sliced_command(&psmouse->ps2dev, reg) ||
|
||||
ps2_sliced_command(&psmouse->ps2dev, val) ||
|
||||
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) {
|
||||
rc = -1;
|
||||
}
|
||||
@ -279,8 +279,8 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
|
||||
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
|
||||
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
|
||||
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
|
||||
psmouse_report_standard_buttons(dev, packet[0]);
|
||||
|
||||
if (etd->fw_version < 0x020000 &&
|
||||
(etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) {
|
||||
@ -390,8 +390,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
|
||||
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
|
||||
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
|
||||
input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
psmouse_report_standard_buttons(dev, packet[0]);
|
||||
if (etd->reports_pressure) {
|
||||
input_report_abs(dev, ABS_PRESSURE, pres);
|
||||
input_report_abs(dev, ABS_TOOL_WIDTH, width);
|
||||
@ -434,9 +433,7 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
|
||||
x = packet[4] - (int)((packet[1]^0x80) << 1);
|
||||
y = (int)((packet[2]^0x80) << 1) - packet[5];
|
||||
|
||||
input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04);
|
||||
psmouse_report_standard_buttons(tp_dev, packet[0]);
|
||||
|
||||
input_report_rel(tp_dev, REL_X, x);
|
||||
input_report_rel(tp_dev, REL_Y, y);
|
||||
@ -526,12 +523,10 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
|
||||
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
|
||||
|
||||
/* For clickpads map both buttons to BTN_LEFT */
|
||||
if (etd->fw_version & 0x001000) {
|
||||
if (etd->fw_version & 0x001000)
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
|
||||
} else {
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
}
|
||||
else
|
||||
psmouse_report_standard_buttons(dev, packet[0]);
|
||||
|
||||
input_report_abs(dev, ABS_PRESSURE, pres);
|
||||
input_report_abs(dev, ABS_TOOL_WIDTH, width);
|
||||
@ -546,13 +541,10 @@ static void elantech_input_sync_v4(struct psmouse *psmouse)
|
||||
unsigned char *packet = psmouse->packet;
|
||||
|
||||
/* For clickpads map both buttons to BTN_LEFT */
|
||||
if (etd->fw_version & 0x001000) {
|
||||
if (etd->fw_version & 0x001000)
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
|
||||
} else {
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
input_report_key(dev, BTN_MIDDLE, packet[0] & 0x04);
|
||||
}
|
||||
else
|
||||
psmouse_report_standard_buttons(dev, packet[0]);
|
||||
|
||||
input_mt_report_pointer_emulation(dev, true);
|
||||
input_sync(dev);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/libps2.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psmouse.h"
|
||||
#include "lifebook.h"
|
||||
@ -136,7 +137,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
|
||||
struct lifebook_data *priv = psmouse->private;
|
||||
struct input_dev *dev1 = psmouse->dev;
|
||||
struct input_dev *dev2 = priv ? priv->dev2 : NULL;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
u8 *packet = psmouse->packet;
|
||||
bool relative_packet = packet[0] & 0x08;
|
||||
|
||||
if (relative_packet || !lifebook_use_6byte_proto) {
|
||||
@ -188,14 +189,10 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
|
||||
}
|
||||
|
||||
if (dev2) {
|
||||
if (relative_packet) {
|
||||
input_report_rel(dev2, REL_X,
|
||||
((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
|
||||
input_report_rel(dev2, REL_Y,
|
||||
-(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
|
||||
}
|
||||
input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
|
||||
input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
|
||||
if (relative_packet)
|
||||
psmouse_report_standard_motion(dev2, packet);
|
||||
|
||||
psmouse_report_standard_buttons(dev2, packet[0]);
|
||||
input_sync(dev2);
|
||||
}
|
||||
|
||||
@ -205,10 +202,12 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
|
||||
static int lifebook_absolute_mode(struct psmouse *psmouse)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param;
|
||||
u8 param;
|
||||
int error;
|
||||
|
||||
if (psmouse_reset(psmouse))
|
||||
return -1;
|
||||
error = psmouse_reset(psmouse);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Enable absolute output -- ps2_command fails always but if
|
||||
@ -224,15 +223,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
|
||||
static void lifebook_relative_mode(struct psmouse *psmouse)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param = 0x06;
|
||||
u8 param = 0x06;
|
||||
|
||||
ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
|
||||
}
|
||||
|
||||
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
|
||||
{
|
||||
static const unsigned char params[] = { 0, 1, 2, 2, 3 };
|
||||
unsigned char p;
|
||||
static const u8 params[] = { 0, 1, 2, 2, 3 };
|
||||
u8 p;
|
||||
|
||||
if (resolution == 0 || resolution > 400)
|
||||
resolution = 400;
|
||||
@ -257,11 +256,11 @@ static void lifebook_disconnect(struct psmouse *psmouse)
|
||||
int lifebook_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
if (!lifebook_present)
|
||||
return -1;
|
||||
return -ENXIO;
|
||||
|
||||
if (desired_serio_phys &&
|
||||
strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
|
||||
return -1;
|
||||
return -ENXIO;
|
||||
|
||||
if (set_properties) {
|
||||
psmouse->vendor = "Fujitsu";
|
||||
@ -294,10 +293,10 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
|
||||
dev2->id.version = 0x0000;
|
||||
dev2->dev.parent = &psmouse->ps2dev.serio->dev;
|
||||
|
||||
dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
|
||||
dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
|
||||
dev2->keybit[BIT_WORD(BTN_LEFT)] =
|
||||
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
|
||||
input_set_capability(dev2, EV_REL, REL_X);
|
||||
input_set_capability(dev2, EV_REL, REL_Y);
|
||||
input_set_capability(dev2, EV_KEY, BTN_LEFT);
|
||||
input_set_capability(dev2, EV_KEY, BTN_RIGHT);
|
||||
|
||||
error = input_register_device(priv->dev2);
|
||||
if (error)
|
||||
@ -316,21 +315,26 @@ int lifebook_init(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *dev1 = psmouse->dev;
|
||||
int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
|
||||
int error;
|
||||
|
||||
if (lifebook_absolute_mode(psmouse))
|
||||
return -1;
|
||||
error = lifebook_absolute_mode(psmouse);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
|
||||
dev1->relbit[0] = 0;
|
||||
dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0;
|
||||
dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
/* Clear default capabilities */
|
||||
bitmap_zero(dev1->evbit, EV_CNT);
|
||||
bitmap_zero(dev1->relbit, REL_CNT);
|
||||
bitmap_zero(dev1->keybit, KEY_CNT);
|
||||
|
||||
input_set_capability(dev1, EV_KEY, BTN_TOUCH);
|
||||
input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
|
||||
input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
|
||||
|
||||
if (!desired_serio_phys) {
|
||||
if (lifebook_create_relative_device(psmouse)) {
|
||||
error = lifebook_create_relative_device(psmouse);
|
||||
if (error) {
|
||||
lifebook_relative_mode(psmouse);
|
||||
return -1;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,9 +9,11 @@
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/libps2.h>
|
||||
#include <linux/types.h>
|
||||
#include "psmouse.h"
|
||||
#include "logips2pp.h"
|
||||
|
||||
@ -22,12 +24,12 @@
|
||||
#define PS2PP_KIND_TRACKMAN 4
|
||||
|
||||
/* Logitech mouse features */
|
||||
#define PS2PP_WHEEL 0x01
|
||||
#define PS2PP_HWHEEL 0x02
|
||||
#define PS2PP_SIDE_BTN 0x04
|
||||
#define PS2PP_EXTRA_BTN 0x08
|
||||
#define PS2PP_TASK_BTN 0x10
|
||||
#define PS2PP_NAV_BTN 0x20
|
||||
#define PS2PP_WHEEL BIT(0)
|
||||
#define PS2PP_HWHEEL BIT(1)
|
||||
#define PS2PP_SIDE_BTN BIT(2)
|
||||
#define PS2PP_EXTRA_BTN BIT(3)
|
||||
#define PS2PP_TASK_BTN BIT(4)
|
||||
#define PS2PP_NAV_BTN BIT(5)
|
||||
|
||||
struct ps2pp_info {
|
||||
u8 model;
|
||||
@ -42,7 +44,7 @@ struct ps2pp_info {
|
||||
static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
u8 *packet = psmouse->packet;
|
||||
|
||||
if (psmouse->pktcnt < 3)
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
@ -58,28 +60,30 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
|
||||
|
||||
case 0x0d: /* Mouse extra info */
|
||||
|
||||
input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
|
||||
(int) (packet[2] & 8) - (int) (packet[2] & 7));
|
||||
input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
|
||||
input_report_rel(dev,
|
||||
packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
|
||||
-sign_extend32(packet[2], 3));
|
||||
input_report_key(dev, BTN_SIDE, packet[2] & BIT(4));
|
||||
input_report_key(dev, BTN_EXTRA, packet[2] & BIT(5));
|
||||
|
||||
break;
|
||||
|
||||
case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
|
||||
|
||||
input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
|
||||
input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
|
||||
input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
|
||||
input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
|
||||
input_report_key(dev, BTN_SIDE, packet[2] & BIT(0));
|
||||
input_report_key(dev, BTN_EXTRA, packet[2] & BIT(1));
|
||||
input_report_key(dev, BTN_TASK, packet[2] & BIT(2));
|
||||
input_report_key(dev, BTN_BACK, packet[2] & BIT(3));
|
||||
input_report_key(dev, BTN_FORWARD, packet[2] & BIT(4));
|
||||
|
||||
break;
|
||||
|
||||
case 0x0f: /* TouchPad extra info */
|
||||
|
||||
input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
|
||||
(int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
|
||||
packet[0] = packet[2] | 0x08;
|
||||
input_report_rel(dev,
|
||||
packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
|
||||
-sign_extend32(packet[2] >> 4, 3));
|
||||
packet[0] = packet[2] | BIT(3);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -88,16 +92,14 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
|
||||
(packet[1] >> 4) | (packet[0] & 0x30));
|
||||
break;
|
||||
}
|
||||
|
||||
psmouse_report_standard_buttons(dev, packet[0]);
|
||||
|
||||
} else {
|
||||
/* Standard PS/2 motion data */
|
||||
input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
|
||||
input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
|
||||
psmouse_report_standard_packet(dev, packet);
|
||||
}
|
||||
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 1);
|
||||
input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
|
||||
input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return PSMOUSE_FULL_PACKET;
|
||||
@ -111,13 +113,17 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
|
||||
* Ugly.
|
||||
*/
|
||||
|
||||
static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
|
||||
static int ps2pp_cmd(struct psmouse *psmouse, u8 *param, u8 command)
|
||||
{
|
||||
if (psmouse_sliced_command(psmouse, command))
|
||||
return -1;
|
||||
int error;
|
||||
|
||||
if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300))
|
||||
return -1;
|
||||
error = ps2_sliced_command(&psmouse->ps2dev, command);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -133,7 +139,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
|
||||
static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[4];
|
||||
u8 param[4];
|
||||
|
||||
ps2pp_cmd(psmouse, param, 0x32);
|
||||
|
||||
@ -171,7 +177,7 @@ static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
|
||||
}
|
||||
|
||||
PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
|
||||
ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
|
||||
ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
|
||||
|
||||
/*
|
||||
* Support 800 dpi resolution _only_ if the user wants it (there are good
|
||||
@ -179,11 +185,12 @@ PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
|
||||
* also good reasons to use it, let the user decide).
|
||||
*/
|
||||
|
||||
static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution)
|
||||
static void ps2pp_set_resolution(struct psmouse *psmouse,
|
||||
unsigned int resolution)
|
||||
{
|
||||
if (resolution > 400) {
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param = 3;
|
||||
u8 param = 3;
|
||||
|
||||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
@ -196,7 +203,8 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio
|
||||
|
||||
static void ps2pp_disconnect(struct psmouse *psmouse)
|
||||
{
|
||||
device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr);
|
||||
device_remove_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_smartscroll.dattr);
|
||||
}
|
||||
|
||||
static const struct ps2pp_info *get_model_info(unsigned char model)
|
||||
@ -269,24 +277,24 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
|
||||
struct input_dev *input_dev = psmouse->dev;
|
||||
|
||||
if (model_info->features & PS2PP_SIDE_BTN)
|
||||
__set_bit(BTN_SIDE, input_dev->keybit);
|
||||
input_set_capability(input_dev, EV_KEY, BTN_SIDE);
|
||||
|
||||
if (model_info->features & PS2PP_EXTRA_BTN)
|
||||
__set_bit(BTN_EXTRA, input_dev->keybit);
|
||||
input_set_capability(input_dev, EV_KEY, BTN_EXTRA);
|
||||
|
||||
if (model_info->features & PS2PP_TASK_BTN)
|
||||
__set_bit(BTN_TASK, input_dev->keybit);
|
||||
input_set_capability(input_dev, EV_KEY, BTN_TASK);
|
||||
|
||||
if (model_info->features & PS2PP_NAV_BTN) {
|
||||
__set_bit(BTN_FORWARD, input_dev->keybit);
|
||||
__set_bit(BTN_BACK, input_dev->keybit);
|
||||
input_set_capability(input_dev, EV_KEY, BTN_FORWARD);
|
||||
input_set_capability(input_dev, EV_KEY, BTN_BACK);
|
||||
}
|
||||
|
||||
if (model_info->features & PS2PP_WHEEL)
|
||||
__set_bit(REL_WHEEL, input_dev->relbit);
|
||||
input_set_capability(input_dev, EV_REL, REL_WHEEL);
|
||||
|
||||
if (model_info->features & PS2PP_HWHEEL)
|
||||
__set_bit(REL_HWHEEL, input_dev->relbit);
|
||||
input_set_capability(input_dev, EV_REL, REL_HWHEEL);
|
||||
|
||||
switch (model_info->kind) {
|
||||
|
||||
@ -318,6 +326,30 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
|
||||
}
|
||||
}
|
||||
|
||||
static int ps2pp_setup_protocol(struct psmouse *psmouse,
|
||||
const struct ps2pp_info *model_info)
|
||||
{
|
||||
int error;
|
||||
|
||||
psmouse->protocol_handler = ps2pp_process_byte;
|
||||
psmouse->pktsize = 3;
|
||||
|
||||
if (model_info->kind != PS2PP_KIND_TP3) {
|
||||
psmouse->set_resolution = ps2pp_set_resolution;
|
||||
psmouse->disconnect = ps2pp_disconnect;
|
||||
|
||||
error = device_create_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_smartscroll.dattr);
|
||||
if (error) {
|
||||
psmouse_err(psmouse,
|
||||
"failed to create smartscroll sysfs attribute, error: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Logitech magic init. Detect whether the mouse is a Logitech one
|
||||
@ -328,9 +360,9 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
|
||||
int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[4];
|
||||
unsigned char model, buttons;
|
||||
const struct ps2pp_info *model_info;
|
||||
u8 param[4];
|
||||
u8 model, buttons;
|
||||
bool use_ps2pp = false;
|
||||
int error;
|
||||
|
||||
@ -346,7 +378,7 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
|
||||
buttons = param[1];
|
||||
|
||||
if (!model || !buttons)
|
||||
return -1;
|
||||
return -ENXIO;
|
||||
|
||||
model_info = get_model_info(model);
|
||||
if (model_info) {
|
||||
@ -368,7 +400,8 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
|
||||
|
||||
param[0] = 0;
|
||||
if (!ps2_command(ps2dev, param, 0x13d1) &&
|
||||
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
|
||||
param[0] == 0x06 && param[1] == 0x00 &&
|
||||
param[2] == 0x14) {
|
||||
use_ps2pp = true;
|
||||
}
|
||||
|
||||
@ -387,7 +420,9 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
|
||||
}
|
||||
|
||||
} else {
|
||||
psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model);
|
||||
psmouse_warn(psmouse,
|
||||
"Detected unknown Logitech mouse model %d\n",
|
||||
model);
|
||||
}
|
||||
|
||||
if (set_properties) {
|
||||
@ -395,31 +430,18 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
|
||||
psmouse->model = model;
|
||||
|
||||
if (use_ps2pp) {
|
||||
psmouse->protocol_handler = ps2pp_process_byte;
|
||||
psmouse->pktsize = 3;
|
||||
|
||||
if (model_info->kind != PS2PP_KIND_TP3) {
|
||||
psmouse->set_resolution = ps2pp_set_resolution;
|
||||
psmouse->disconnect = ps2pp_disconnect;
|
||||
|
||||
error = device_create_file(&ps2dev->serio->dev,
|
||||
&psmouse_attr_smartscroll.dattr);
|
||||
if (error) {
|
||||
psmouse_err(psmouse,
|
||||
"failed to create smartscroll sysfs attribute, error: %d\n",
|
||||
error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
error = ps2pp_setup_protocol(psmouse, model_info);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (buttons >= 3)
|
||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
|
||||
|
||||
if (model_info)
|
||||
ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
|
||||
}
|
||||
|
||||
return use_ps2pp ? 0 : -1;
|
||||
return use_ps2pp ? 0 : -ENXIO;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
#define psmouse_fmt(fmt) fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
@ -23,6 +24,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/libps2.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "psmouse.h"
|
||||
#include "synaptics.h"
|
||||
@ -68,6 +70,10 @@ static bool psmouse_smartscroll = true;
|
||||
module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
|
||||
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
|
||||
|
||||
static bool psmouse_a4tech_2wheels;
|
||||
module_param_named(a4tech_workaround, psmouse_a4tech_2wheels, bool, 0644);
|
||||
MODULE_PARM_DESC(a4tech_workaround, "A4Tech second scroll wheel workaround, 1 = enabled, 0 = disabled (default).");
|
||||
|
||||
static unsigned int psmouse_resetafter = 5;
|
||||
module_param_named(resetafter, psmouse_resetafter, uint, 0644);
|
||||
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
|
||||
@ -116,13 +122,30 @@ static DEFINE_MUTEX(psmouse_mutex);
|
||||
|
||||
static struct workqueue_struct *kpsmoused_wq;
|
||||
|
||||
static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
|
||||
void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
|
||||
{
|
||||
input_report_key(dev, BTN_LEFT, buttons & BIT(0));
|
||||
input_report_key(dev, BTN_MIDDLE, buttons & BIT(2));
|
||||
input_report_key(dev, BTN_RIGHT, buttons & BIT(1));
|
||||
}
|
||||
|
||||
void psmouse_report_standard_motion(struct input_dev *dev, u8 *packet)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
x = packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0;
|
||||
y = packet[2] ? packet[2] - ((packet[0] << 3) & 0x100) : 0;
|
||||
|
||||
input_report_rel(dev, REL_X, x);
|
||||
input_report_rel(dev, REL_Y, -y);
|
||||
}
|
||||
|
||||
void psmouse_report_standard_packet(struct input_dev *dev, u8 *packet)
|
||||
{
|
||||
psmouse_report_standard_buttons(dev, packet[0]);
|
||||
psmouse_report_standard_motion(dev, packet);
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_process_byte() analyzes the PS/2 data stream and reports
|
||||
* relevant events to the input module once full packet has arrived.
|
||||
@ -130,7 +153,8 @@ static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
|
||||
psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
u8 *packet = psmouse->packet;
|
||||
int wheel;
|
||||
|
||||
if (psmouse->pktcnt < psmouse->pktsize)
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
@ -140,39 +164,52 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
|
||||
switch (psmouse->protocol->type) {
|
||||
case PSMOUSE_IMPS:
|
||||
/* IntelliMouse has scroll wheel */
|
||||
input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
|
||||
input_report_rel(dev, REL_WHEEL, -(s8) packet[3]);
|
||||
break;
|
||||
|
||||
case PSMOUSE_IMEX:
|
||||
/* Scroll wheel and buttons on IntelliMouse Explorer */
|
||||
switch (packet[3] & 0xC0) {
|
||||
case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
|
||||
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
|
||||
input_report_rel(dev, REL_WHEEL,
|
||||
-sign_extend32(packet[3], 5));
|
||||
break;
|
||||
case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
|
||||
input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
|
||||
input_report_rel(dev, REL_HWHEEL,
|
||||
-sign_extend32(packet[3], 5));
|
||||
break;
|
||||
case 0x00:
|
||||
case 0xC0:
|
||||
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
|
||||
input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
|
||||
wheel = sign_extend32(packet[3], 3);
|
||||
|
||||
/*
|
||||
* Some A4Tech mice have two scroll wheels, with first
|
||||
* one reporting +/-1 in the lower nibble, and second
|
||||
* one reporting +/-2.
|
||||
*/
|
||||
if (psmouse_a4tech_2wheels && abs(wheel) > 1)
|
||||
input_report_rel(dev, REL_HWHEEL, wheel / 2);
|
||||
else
|
||||
input_report_rel(dev, REL_WHEEL, -wheel);
|
||||
|
||||
input_report_key(dev, BTN_SIDE, BIT(4));
|
||||
input_report_key(dev, BTN_EXTRA, BIT(5));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PSMOUSE_GENPS:
|
||||
/* Report scroll buttons on NetMice */
|
||||
input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
|
||||
input_report_rel(dev, REL_WHEEL, -(s8) packet[3]);
|
||||
|
||||
/* Extra buttons on Genius NewNet 3D */
|
||||
input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
|
||||
input_report_key(dev, BTN_SIDE, BIT(6));
|
||||
input_report_key(dev, BTN_EXTRA, BIT(7));
|
||||
break;
|
||||
|
||||
case PSMOUSE_THINKPS:
|
||||
/* Extra button on ThinkingMouse */
|
||||
input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, BIT(3));
|
||||
|
||||
/*
|
||||
* Without this bit of weirdness moving up gives wildly
|
||||
@ -186,8 +223,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
|
||||
* Cortron PS2 Trackball reports SIDE button in the
|
||||
* 4th bit of the first byte.
|
||||
*/
|
||||
input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1);
|
||||
packet[0] |= 0x08;
|
||||
input_report_key(dev, BTN_SIDE, BIT(3));
|
||||
packet[0] |= BIT(3);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -195,11 +232,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
|
||||
}
|
||||
|
||||
/* Generic PS/2 Mouse */
|
||||
psmouse_report_standard_buttons(dev,
|
||||
packet[0] | psmouse->extra_buttons);
|
||||
|
||||
input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
|
||||
input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
|
||||
packet[0] |= psmouse->extra_buttons;
|
||||
psmouse_report_standard_packet(dev, packet);
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
@ -255,7 +289,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
|
||||
psmouse_notice(psmouse,
|
||||
"issuing reconnect request\n");
|
||||
serio_reconnect(psmouse->ps2dev.serio);
|
||||
return -1;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
psmouse->pktcnt = 0;
|
||||
@ -306,7 +340,7 @@ static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data)
|
||||
* for normal processing or gathering them as command response.
|
||||
*/
|
||||
static irqreturn_t psmouse_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
u8 data, unsigned int flags)
|
||||
{
|
||||
struct psmouse *psmouse = serio_get_drvdata(serio);
|
||||
|
||||
@ -397,41 +431,20 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
|
||||
* using sliced syntax, understood by advanced devices, such as Logitech
|
||||
* or Synaptics touchpads. The command is encoded as:
|
||||
* 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
|
||||
* is the command.
|
||||
*/
|
||||
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
|
||||
return -1;
|
||||
|
||||
for (i = 6; i >= 0; i -= 2) {
|
||||
unsigned char d = (command >> i) & 3;
|
||||
if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_reset() resets the mouse into power-on state.
|
||||
*/
|
||||
int psmouse_reset(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[2];
|
||||
u8 param[2];
|
||||
int error;
|
||||
|
||||
if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT))
|
||||
return -1;
|
||||
error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
|
||||
return -1;
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -441,8 +454,8 @@ int psmouse_reset(struct psmouse *psmouse)
|
||||
*/
|
||||
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
|
||||
{
|
||||
static const unsigned char params[] = { 0, 1, 2, 2, 3 };
|
||||
unsigned char p;
|
||||
static const u8 params[] = { 0, 1, 2, 2, 3 };
|
||||
u8 p;
|
||||
|
||||
if (resolution == 0 || resolution > 200)
|
||||
resolution = 200;
|
||||
@ -457,11 +470,12 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
|
||||
*/
|
||||
static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
|
||||
{
|
||||
static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
|
||||
unsigned char r;
|
||||
static const u8 rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
|
||||
u8 r;
|
||||
int i = 0;
|
||||
|
||||
while (rates[i] > rate) i++;
|
||||
while (rates[i] > rate)
|
||||
i++;
|
||||
r = rates[i];
|
||||
ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
|
||||
psmouse->rate = r;
|
||||
@ -533,7 +547,7 @@ bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[])
|
||||
static int genius_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[4];
|
||||
u8 param[4];
|
||||
|
||||
param[0] = 3;
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
||||
@ -543,7 +557,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties)
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
|
||||
|
||||
if (param[0] != 0x00 || param[1] != 0x33 || param[2] != 0x55)
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
|
||||
if (set_properties) {
|
||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
@ -565,7 +579,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties)
|
||||
static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[2];
|
||||
u8 param[2];
|
||||
|
||||
param[0] = 200;
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
|
||||
@ -576,7 +590,7 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
|
||||
|
||||
if (param[0] != 3)
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
|
||||
if (set_properties) {
|
||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
@ -598,7 +612,7 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
|
||||
static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[2];
|
||||
u8 param[2];
|
||||
|
||||
intellimouse_detect(psmouse, 0);
|
||||
|
||||
@ -611,7 +625,7 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
|
||||
|
||||
if (param[0] != 4)
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
|
||||
/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
|
||||
param[0] = 200;
|
||||
@ -644,8 +658,8 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
|
||||
static int thinking_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[2];
|
||||
static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
|
||||
u8 param[2];
|
||||
static const u8 seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
|
||||
int i;
|
||||
|
||||
param[0] = 10;
|
||||
@ -659,7 +673,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties)
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
|
||||
|
||||
if (param[0] != 2)
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
|
||||
if (set_properties) {
|
||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
@ -687,7 +701,7 @@ static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
|
||||
* We have no way of figuring true number of buttons so let's
|
||||
* assume that the device has 3.
|
||||
*/
|
||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -942,20 +956,17 @@ static void psmouse_apply_defaults(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *input_dev = psmouse->dev;
|
||||
|
||||
memset(input_dev->evbit, 0, sizeof(input_dev->evbit));
|
||||
memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
|
||||
memset(input_dev->relbit, 0, sizeof(input_dev->relbit));
|
||||
memset(input_dev->absbit, 0, sizeof(input_dev->absbit));
|
||||
memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit));
|
||||
bitmap_zero(input_dev->evbit, EV_CNT);
|
||||
bitmap_zero(input_dev->keybit, KEY_CNT);
|
||||
bitmap_zero(input_dev->relbit, REL_CNT);
|
||||
bitmap_zero(input_dev->absbit, ABS_CNT);
|
||||
bitmap_zero(input_dev->mscbit, MSC_CNT);
|
||||
|
||||
__set_bit(EV_KEY, input_dev->evbit);
|
||||
__set_bit(EV_REL, input_dev->evbit);
|
||||
input_set_capability(input_dev, EV_KEY, BTN_LEFT);
|
||||
input_set_capability(input_dev, EV_KEY, BTN_RIGHT);
|
||||
|
||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||
__set_bit(BTN_RIGHT, input_dev->keybit);
|
||||
|
||||
__set_bit(REL_X, input_dev->relbit);
|
||||
__set_bit(REL_Y, input_dev->relbit);
|
||||
input_set_capability(input_dev, EV_REL, REL_X);
|
||||
input_set_capability(input_dev, EV_REL, REL_Y);
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
|
||||
@ -1225,7 +1236,8 @@ static int psmouse_extensions(struct psmouse *psmouse,
|
||||
static int psmouse_probe(struct psmouse *psmouse)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[2];
|
||||
u8 param[2];
|
||||
int error;
|
||||
|
||||
/*
|
||||
* First, we check if it's a mouse. It should send 0x00 or 0x03 in
|
||||
@ -1234,20 +1246,22 @@ static int psmouse_probe(struct psmouse *psmouse)
|
||||
* subsequent ID queries, probably due to a firmware bug.
|
||||
*/
|
||||
param[0] = 0xa5;
|
||||
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
|
||||
return -1;
|
||||
error = ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (param[0] != 0x00 && param[0] != 0x03 &&
|
||||
param[0] != 0x04 && param[0] != 0xff)
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Then we reset and disable the mouse so that it doesn't generate
|
||||
* events.
|
||||
*/
|
||||
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
|
||||
psmouse_warn(psmouse, "Failed to reset mouse on %s\n",
|
||||
ps2dev->serio->phys);
|
||||
error = ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
|
||||
if (error)
|
||||
psmouse_warn(psmouse, "Failed to reset mouse on %s: %d\n",
|
||||
ps2dev->serio->phys, error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1288,10 +1302,13 @@ int psmouse_activate(struct psmouse *psmouse)
|
||||
*/
|
||||
int psmouse_deactivate(struct psmouse *psmouse)
|
||||
{
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
|
||||
psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
|
||||
psmouse->ps2dev.serio->phys);
|
||||
return -1;
|
||||
int error;
|
||||
|
||||
error = ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE);
|
||||
if (error) {
|
||||
psmouse_warn(psmouse, "Failed to deactivate mouse on %s: %d\n",
|
||||
psmouse->ps2dev.serio->phys, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
|
@ -131,7 +131,6 @@ struct psmouse {
|
||||
|
||||
void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
|
||||
unsigned long delay);
|
||||
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
|
||||
int psmouse_reset(struct psmouse *psmouse);
|
||||
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
|
||||
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
|
||||
@ -140,6 +139,10 @@ int psmouse_activate(struct psmouse *psmouse);
|
||||
int psmouse_deactivate(struct psmouse *psmouse);
|
||||
bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]);
|
||||
|
||||
void psmouse_report_standard_buttons(struct input_dev *, u8 buttons);
|
||||
void psmouse_report_standard_motion(struct input_dev *, u8 *packet);
|
||||
void psmouse_report_standard_packet(struct input_dev *, u8 *packet);
|
||||
|
||||
struct psmouse_attribute {
|
||||
struct device_attribute dattr;
|
||||
void *data;
|
||||
|
@ -710,7 +710,6 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
|
||||
unsigned char *packet = psmouse->packet;
|
||||
unsigned char button_status = 0, lscroll = 0, rscroll = 0;
|
||||
unsigned short abs_x, abs_y, fgrs = 0;
|
||||
int rel_x, rel_y;
|
||||
|
||||
if (psmouse->pktcnt < 4)
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
@ -840,15 +839,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
|
||||
/*
|
||||
* Standard PS/2 Mouse
|
||||
*/
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 1);
|
||||
input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
|
||||
input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
|
||||
|
||||
rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
|
||||
rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
|
||||
|
||||
input_report_rel(dev, REL_X, rel_x);
|
||||
input_report_rel(dev, REL_Y, rel_y);
|
||||
psmouse_report_standard_packet(dev, packet);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode)
|
||||
u8 param[1];
|
||||
int error;
|
||||
|
||||
error = psmouse_sliced_command(psmouse, mode);
|
||||
error = ps2_sliced_command(&psmouse->ps2dev, mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -190,7 +190,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = psmouse_sliced_command(psmouse, cmd);
|
||||
error = ps2_sliced_command(&psmouse->ps2dev, cmd);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -547,7 +547,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
|
||||
static u8 param = 0xc8;
|
||||
int error;
|
||||
|
||||
error = psmouse_sliced_command(psmouse, SYN_QUE_MODEL);
|
||||
error = ps2_sliced_command(&psmouse->ps2dev, SYN_QUE_MODEL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -614,7 +614,7 @@ static int synaptics_pt_write(struct serio *serio, u8 c)
|
||||
u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
|
||||
int error;
|
||||
|
||||
error = psmouse_sliced_command(parent, c);
|
||||
error = ps2_sliced_command(&parent->ps2dev, c);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -33,18 +33,15 @@ static const char * const trackpoint_variants[] = {
|
||||
*/
|
||||
static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
|
||||
{
|
||||
u8 results[2];
|
||||
int tries = 0;
|
||||
u8 param[2] = { TP_POR };
|
||||
int err;
|
||||
|
||||
/* Issue POR command, and repeat up to once if 0xFC00 received */
|
||||
do {
|
||||
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
|
||||
ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR)))
|
||||
return -1;
|
||||
} while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2);
|
||||
err = ps2_command(ps2dev, param, MAKE_PS2_CMD(1, 2, TP_COMMAND));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Check for success response -- 0xAA00 */
|
||||
if (results[0] != 0xAA || results[1] != 0x00)
|
||||
if (param[0] != 0xAA || param[1] != 0x00)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
@ -55,49 +52,39 @@ static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
|
||||
*/
|
||||
static int trackpoint_read(struct ps2dev *ps2dev, u8 loc, u8 *results)
|
||||
{
|
||||
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
|
||||
ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {
|
||||
return -1;
|
||||
}
|
||||
results[0] = loc;
|
||||
|
||||
return 0;
|
||||
return ps2_command(ps2dev, results, MAKE_PS2_CMD(1, 1, TP_COMMAND));
|
||||
}
|
||||
|
||||
static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
|
||||
{
|
||||
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
|
||||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||
|
||||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
|
||||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) {
|
||||
return -1;
|
||||
}
|
||||
u8 param[3] = { TP_WRITE_MEM, loc, val };
|
||||
|
||||
return 0;
|
||||
return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
|
||||
}
|
||||
|
||||
static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
|
||||
{
|
||||
u8 param[3] = { TP_TOGGLE, loc, mask };
|
||||
|
||||
/* Bad things will happen if the loc param isn't in this range */
|
||||
if (loc < 0x20 || loc >= 0x2F)
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
|
||||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) ||
|
||||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
|
||||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
|
||||
}
|
||||
|
||||
static int trackpoint_update_bit(struct ps2dev *ps2dev,
|
||||
u8 loc, u8 mask, u8 value)
|
||||
{
|
||||
int retval = 0;
|
||||
int retval;
|
||||
u8 data;
|
||||
|
||||
trackpoint_read(ps2dev, loc, &data);
|
||||
retval = trackpoint_read(ps2dev, loc, &data);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (((data & mask) == mask) != !!value)
|
||||
retval = trackpoint_toggle_bit(ps2dev, loc, mask);
|
||||
|
||||
@ -142,9 +129,9 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
|
||||
return err;
|
||||
|
||||
*field = value;
|
||||
trackpoint_write(&psmouse->ps2dev, attr->command, value);
|
||||
err = trackpoint_write(&psmouse->ps2dev, attr->command, value);
|
||||
|
||||
return count;
|
||||
return err ?: count;
|
||||
}
|
||||
|
||||
#define TRACKPOINT_INT_ATTR(_name, _command, _default) \
|
||||
@ -175,10 +162,11 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
|
||||
|
||||
if (*field != value) {
|
||||
*field = value;
|
||||
trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask);
|
||||
err = trackpoint_toggle_bit(&psmouse->ps2dev,
|
||||
attr->command, attr->mask);
|
||||
}
|
||||
|
||||
return count;
|
||||
return err ?: count;
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,31 +26,79 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
|
||||
MODULE_DESCRIPTION("PS/2 driver library");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
|
||||
unsigned int timeout, unsigned int max_attempts)
|
||||
__releases(&ps2dev->serio->lock) __acquires(&ps2dev->serio->lock)
|
||||
{
|
||||
int attempt = 0;
|
||||
int error;
|
||||
|
||||
lockdep_assert_held(&ps2dev->serio->lock);
|
||||
|
||||
do {
|
||||
ps2dev->nak = 1;
|
||||
ps2dev->flags |= PS2_FLAG_ACK;
|
||||
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
|
||||
error = serio_write(ps2dev->serio, byte);
|
||||
if (error)
|
||||
dev_dbg(&ps2dev->serio->dev,
|
||||
"failed to write %#02x: %d\n", byte, error);
|
||||
else
|
||||
wait_event_timeout(ps2dev->wait,
|
||||
!(ps2dev->flags & PS2_FLAG_ACK),
|
||||
msecs_to_jiffies(timeout));
|
||||
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
} while (ps2dev->nak == PS2_RET_NAK && ++attempt < max_attempts);
|
||||
|
||||
ps2dev->flags &= ~PS2_FLAG_ACK;
|
||||
|
||||
if (!error) {
|
||||
switch (ps2dev->nak) {
|
||||
case 0:
|
||||
break;
|
||||
case PS2_RET_NAK:
|
||||
error = -EAGAIN;
|
||||
break;
|
||||
case PS2_RET_ERR:
|
||||
error = -EPROTO;
|
||||
break;
|
||||
default:
|
||||
error = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (error || attempt > 1)
|
||||
dev_dbg(&ps2dev->serio->dev,
|
||||
"%02x - %d (%x), attempt %d\n",
|
||||
byte, error, ps2dev->nak, attempt);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* ps2_sendbyte() sends a byte to the device and waits for acknowledge.
|
||||
* It doesn't handle retransmission, though it could - because if there
|
||||
* is a need for retransmissions device has to be replaced anyway.
|
||||
* It doesn't handle retransmission, the caller is expected to handle
|
||||
* it when needed.
|
||||
*
|
||||
* ps2_sendbyte() can only be called from a process context.
|
||||
*/
|
||||
|
||||
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
|
||||
int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
|
||||
{
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
ps2dev->nak = 1;
|
||||
ps2dev->flags |= PS2_FLAG_ACK;
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
|
||||
if (serio_write(ps2dev->serio, byte) == 0)
|
||||
wait_event_timeout(ps2dev->wait,
|
||||
!(ps2dev->flags & PS2_FLAG_ACK),
|
||||
msecs_to_jiffies(timeout));
|
||||
int retval;
|
||||
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
ps2dev->flags &= ~PS2_FLAG_ACK;
|
||||
|
||||
retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1);
|
||||
dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak);
|
||||
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
|
||||
return -ps2dev->nak;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(ps2_sendbyte);
|
||||
|
||||
@ -75,7 +123,7 @@ EXPORT_SYMBOL(ps2_end_command);
|
||||
* and discards them.
|
||||
*/
|
||||
|
||||
void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
|
||||
void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
|
||||
{
|
||||
if (maxbytes > sizeof(ps2dev->cmdbuf)) {
|
||||
WARN_ON(1);
|
||||
@ -102,9 +150,9 @@ EXPORT_SYMBOL(ps2_drain);
|
||||
* known keyboard IDs.
|
||||
*/
|
||||
|
||||
int ps2_is_keyboard_id(char id_byte)
|
||||
bool ps2_is_keyboard_id(u8 id_byte)
|
||||
{
|
||||
static const char keyboard_ids[] = {
|
||||
static const u8 keyboard_ids[] = {
|
||||
0xab, /* Regular keyboards */
|
||||
0xac, /* NCD Sun keyboard */
|
||||
0x2b, /* Trust keyboard, translated */
|
||||
@ -123,49 +171,50 @@ EXPORT_SYMBOL(ps2_is_keyboard_id);
|
||||
* completion.
|
||||
*/
|
||||
|
||||
static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
|
||||
static int ps2_adjust_timeout(struct ps2dev *ps2dev,
|
||||
unsigned int command, unsigned int timeout)
|
||||
{
|
||||
switch (command) {
|
||||
case PS2_CMD_RESET_BAT:
|
||||
/*
|
||||
* Device has sent the first response byte after
|
||||
* reset command, reset is thus done, so we can
|
||||
* shorten the timeout.
|
||||
* The next byte will come soon (keyboard) or not
|
||||
* at all (mouse).
|
||||
*/
|
||||
if (timeout > msecs_to_jiffies(100))
|
||||
timeout = msecs_to_jiffies(100);
|
||||
break;
|
||||
case PS2_CMD_RESET_BAT:
|
||||
/*
|
||||
* Device has sent the first response byte after
|
||||
* reset command, reset is thus done, so we can
|
||||
* shorten the timeout.
|
||||
* The next byte will come soon (keyboard) or not
|
||||
* at all (mouse).
|
||||
*/
|
||||
if (timeout > msecs_to_jiffies(100))
|
||||
timeout = msecs_to_jiffies(100);
|
||||
break;
|
||||
|
||||
case PS2_CMD_GETID:
|
||||
/*
|
||||
* Microsoft Natural Elite keyboard responds to
|
||||
* the GET ID command as it were a mouse, with
|
||||
* a single byte. Fail the command so atkbd will
|
||||
* use alternative probe to detect it.
|
||||
*/
|
||||
if (ps2dev->cmdbuf[1] == 0xaa) {
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
ps2dev->flags = 0;
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
timeout = 0;
|
||||
}
|
||||
case PS2_CMD_GETID:
|
||||
/*
|
||||
* Microsoft Natural Elite keyboard responds to
|
||||
* the GET ID command as it were a mouse, with
|
||||
* a single byte. Fail the command so atkbd will
|
||||
* use alternative probe to detect it.
|
||||
*/
|
||||
if (ps2dev->cmdbuf[1] == 0xaa) {
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
ps2dev->flags = 0;
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If device behind the port is not a keyboard there
|
||||
* won't be 2nd byte of ID response.
|
||||
*/
|
||||
if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
ps2dev->flags = ps2dev->cmdcnt = 0;
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
timeout = 0;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* If device behind the port is not a keyboard there
|
||||
* won't be 2nd byte of ID response.
|
||||
*/
|
||||
if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
ps2dev->flags = ps2dev->cmdcnt = 0;
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
timeout = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return timeout;
|
||||
@ -178,50 +227,60 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
|
||||
* ps2_command() can only be called from a process context
|
||||
*/
|
||||
|
||||
int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
|
||||
int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
|
||||
{
|
||||
int timeout;
|
||||
int send = (command >> 12) & 0xf;
|
||||
int receive = (command >> 8) & 0xf;
|
||||
int rc = -1;
|
||||
unsigned int timeout;
|
||||
unsigned int send = (command >> 12) & 0xf;
|
||||
unsigned int receive = (command >> 8) & 0xf;
|
||||
int rc;
|
||||
int i;
|
||||
u8 send_param[16];
|
||||
|
||||
if (receive > sizeof(ps2dev->cmdbuf)) {
|
||||
WARN_ON(1);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (send && !param) {
|
||||
WARN_ON(1);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(send_param, param, send);
|
||||
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
|
||||
ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
|
||||
ps2dev->cmdcnt = receive;
|
||||
if (receive && param)
|
||||
for (i = 0; i < receive; i++)
|
||||
ps2dev->cmdbuf[(receive - 1) - i] = param[i];
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
|
||||
/* Signal that we are sending the command byte */
|
||||
ps2dev->flags |= PS2_FLAG_ACK_CMD;
|
||||
|
||||
/*
|
||||
* Some devices (Synaptics) peform the reset before
|
||||
* ACKing the reset command, and so it can take a long
|
||||
* time before the ACK arrives.
|
||||
*/
|
||||
if (ps2_sendbyte(ps2dev, command & 0xff,
|
||||
command == PS2_CMD_RESET_BAT ? 1000 : 200)) {
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
timeout = command == PS2_CMD_RESET_BAT ? 1000 : 200;
|
||||
|
||||
rc = ps2_do_sendbyte(ps2dev, command & 0xff, timeout, 2);
|
||||
if (rc)
|
||||
goto out_reset_flags;
|
||||
}
|
||||
|
||||
/* Now we are sending command parameters, if any */
|
||||
ps2dev->flags &= ~PS2_FLAG_ACK_CMD;
|
||||
|
||||
for (i = 0; i < send; i++) {
|
||||
if (ps2_sendbyte(ps2dev, param[i], 200)) {
|
||||
serio_pause_rx(ps2dev->serio);
|
||||
rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2);
|
||||
if (rc)
|
||||
goto out_reset_flags;
|
||||
}
|
||||
}
|
||||
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
|
||||
/*
|
||||
* The reset command takes a long time to execute.
|
||||
*/
|
||||
@ -243,8 +302,11 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
|
||||
for (i = 0; i < receive; i++)
|
||||
param[i] = ps2dev->cmdbuf[(receive - 1) - i];
|
||||
|
||||
if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1))
|
||||
if (ps2dev->cmdcnt &&
|
||||
(command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) {
|
||||
rc = -EPROTO;
|
||||
goto out_reset_flags;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
@ -252,11 +314,21 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
|
||||
ps2dev->flags = 0;
|
||||
serio_continue_rx(ps2dev->serio);
|
||||
|
||||
return rc;
|
||||
dev_dbg(&ps2dev->serio->dev,
|
||||
"%02x [%*ph] - %x/%08lx [%*ph]\n",
|
||||
command & 0xff, send, send_param,
|
||||
ps2dev->nak, ps2dev->flags,
|
||||
receive, param ?: send_param);
|
||||
|
||||
/*
|
||||
* ps_command() handles resends itself, so do not leak -EAGAIN
|
||||
* to the callers.
|
||||
*/
|
||||
return rc != -EAGAIN ? rc : -EPROTO;
|
||||
}
|
||||
EXPORT_SYMBOL(__ps2_command);
|
||||
|
||||
int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
|
||||
int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@ -268,6 +340,39 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
|
||||
}
|
||||
EXPORT_SYMBOL(ps2_command);
|
||||
|
||||
/*
|
||||
* ps2_sliced_command() sends an extended PS/2 command to the mouse
|
||||
* using sliced syntax, understood by advanced devices, such as Logitech
|
||||
* or Synaptics touchpads. The command is encoded as:
|
||||
* 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
|
||||
* is the command.
|
||||
*/
|
||||
|
||||
int ps2_sliced_command(struct ps2dev *ps2dev, u8 command)
|
||||
{
|
||||
int i;
|
||||
int retval;
|
||||
|
||||
ps2_begin_command(ps2dev);
|
||||
|
||||
retval = __ps2_command(ps2dev, NULL, PS2_CMD_SETSCALE11);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
for (i = 6; i >= 0; i -= 2) {
|
||||
u8 d = (command >> i) & 3;
|
||||
retval = __ps2_command(ps2dev, &d, PS2_CMD_SETRES);
|
||||
if (retval)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
dev_dbg(&ps2dev->serio->dev, "%02x - %d\n", command, retval);
|
||||
ps2_end_command(ps2dev);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(ps2_sliced_command);
|
||||
|
||||
/*
|
||||
* ps2_init() initializes ps2dev structure
|
||||
*/
|
||||
@ -286,42 +391,53 @@ EXPORT_SYMBOL(ps2_init);
|
||||
* to properly process ACK/NAK of a command from a PS/2 device.
|
||||
*/
|
||||
|
||||
int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
|
||||
bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
|
||||
{
|
||||
switch (data) {
|
||||
case PS2_RET_ACK:
|
||||
case PS2_RET_ACK:
|
||||
ps2dev->nak = 0;
|
||||
break;
|
||||
|
||||
case PS2_RET_NAK:
|
||||
ps2dev->flags |= PS2_FLAG_NAK;
|
||||
ps2dev->nak = PS2_RET_NAK;
|
||||
break;
|
||||
|
||||
case PS2_RET_ERR:
|
||||
if (ps2dev->flags & PS2_FLAG_NAK) {
|
||||
ps2dev->flags &= ~PS2_FLAG_NAK;
|
||||
ps2dev->nak = PS2_RET_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround for mice which don't ACK the Get ID command.
|
||||
* These are valid mouse IDs that we recognize.
|
||||
*/
|
||||
case 0x00:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
if (ps2dev->flags & PS2_FLAG_WAITID) {
|
||||
ps2dev->nak = 0;
|
||||
break;
|
||||
|
||||
case PS2_RET_NAK:
|
||||
ps2dev->flags |= PS2_FLAG_NAK;
|
||||
ps2dev->nak = PS2_RET_NAK;
|
||||
break;
|
||||
|
||||
case PS2_RET_ERR:
|
||||
if (ps2dev->flags & PS2_FLAG_NAK) {
|
||||
ps2dev->flags &= ~PS2_FLAG_NAK;
|
||||
ps2dev->nak = PS2_RET_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
/*
|
||||
* Workaround for mice which don't ACK the Get ID command.
|
||||
* These are valid mouse IDs that we recognize.
|
||||
* Do not signal errors if we get unexpected reply while
|
||||
* waiting for an ACK to the initial (first) command byte:
|
||||
* the device might not be quiesced yet and continue
|
||||
* delivering data.
|
||||
* Note that we reset PS2_FLAG_WAITID flag, so the workaround
|
||||
* for mice not acknowledging the Get ID command only triggers
|
||||
* on the 1st byte; if device spews data we really want to see
|
||||
* a real ACK from it.
|
||||
*/
|
||||
case 0x00:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
if (ps2dev->flags & PS2_FLAG_WAITID) {
|
||||
ps2dev->nak = 0;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
return 0;
|
||||
dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data);
|
||||
ps2dev->flags &= ~PS2_FLAG_WAITID;
|
||||
return ps2dev->flags & PS2_FLAG_ACK_CMD;
|
||||
}
|
||||
|
||||
|
||||
if (!ps2dev->nak) {
|
||||
ps2dev->flags &= ~PS2_FLAG_NAK;
|
||||
if (ps2dev->cmdcnt)
|
||||
@ -334,7 +450,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
|
||||
if (data != PS2_RET_ACK)
|
||||
ps2_handle_response(ps2dev, data);
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ps2_handle_ack);
|
||||
|
||||
@ -344,7 +460,7 @@ EXPORT_SYMBOL(ps2_handle_ack);
|
||||
* waiting for completion of the command.
|
||||
*/
|
||||
|
||||
int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
|
||||
bool ps2_handle_response(struct ps2dev *ps2dev, u8 data)
|
||||
{
|
||||
if (ps2dev->cmdcnt)
|
||||
ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
|
||||
@ -360,7 +476,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
|
||||
wake_up(&ps2dev->wait);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ps2_handle_response);
|
||||
|
||||
|
@ -10,7 +10,13 @@
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#define PS2_CMD_SETSCALE11 0x00e6
|
||||
#define PS2_CMD_SETRES 0x10e8
|
||||
#define PS2_CMD_GETID 0x02f2
|
||||
#define PS2_CMD_RESET_BAT 0x02ff
|
||||
|
||||
@ -20,11 +26,12 @@
|
||||
#define PS2_RET_NAK 0xfe
|
||||
#define PS2_RET_ERR 0xfc
|
||||
|
||||
#define PS2_FLAG_ACK 1 /* Waiting for ACK/NAK */
|
||||
#define PS2_FLAG_CMD 2 /* Waiting for command to finish */
|
||||
#define PS2_FLAG_CMD1 4 /* Waiting for the first byte of command response */
|
||||
#define PS2_FLAG_WAITID 8 /* Command execiting is GET ID */
|
||||
#define PS2_FLAG_NAK 16 /* Last transmission was NAKed */
|
||||
#define PS2_FLAG_ACK BIT(0) /* Waiting for ACK/NAK */
|
||||
#define PS2_FLAG_CMD BIT(1) /* Waiting for a command to finish */
|
||||
#define PS2_FLAG_CMD1 BIT(2) /* Waiting for the first byte of command response */
|
||||
#define PS2_FLAG_WAITID BIT(3) /* Command executing is GET ID */
|
||||
#define PS2_FLAG_NAK BIT(4) /* Last transmission was NAKed */
|
||||
#define PS2_FLAG_ACK_CMD BIT(5) /* Waiting to ACK the command (first) byte */
|
||||
|
||||
struct ps2dev {
|
||||
struct serio *serio;
|
||||
@ -36,21 +43,22 @@ struct ps2dev {
|
||||
wait_queue_head_t wait;
|
||||
|
||||
unsigned long flags;
|
||||
unsigned char cmdbuf[8];
|
||||
unsigned char cmdcnt;
|
||||
unsigned char nak;
|
||||
u8 cmdbuf[8];
|
||||
u8 cmdcnt;
|
||||
u8 nak;
|
||||
};
|
||||
|
||||
void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
|
||||
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
|
||||
void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
|
||||
int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout);
|
||||
void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout);
|
||||
void ps2_begin_command(struct ps2dev *ps2dev);
|
||||
void ps2_end_command(struct ps2dev *ps2dev);
|
||||
int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
|
||||
int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
|
||||
int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
|
||||
int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);
|
||||
int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command);
|
||||
int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command);
|
||||
int ps2_sliced_command(struct ps2dev *ps2dev, u8 command);
|
||||
bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data);
|
||||
bool ps2_handle_response(struct ps2dev *ps2dev, u8 data);
|
||||
void ps2_cmd_aborted(struct ps2dev *ps2dev);
|
||||
int ps2_is_keyboard_id(char id);
|
||||
bool ps2_is_keyboard_id(u8 id);
|
||||
|
||||
#endif /* _LIBPS2_H */
|
||||
|
Reference in New Issue
Block a user