Message ID | 1457789541-29605-1-git-send-email-chris@diamand.org (mailing list archive) |
---|---|
State | Accepted |
Headers | show |
Are there any more concerns Dmitry? best, -Richard On 03/12/2016 05:32 AM, Chris Diamand wrote: > From: Richard Pospesel <pospeselr@gmail.com> > > The Windows driver's settings dialog contains a visualization of the > regions for the hardware edge scrolling capability, which uses a > temporarily-enabled limited-resolution absolute mode. > > This patch enables this during normal operation, and combines the > absolute packets with the existing relative packets to provide > accurate absolute position and touch reporting. > > It also adds documentation for all known gesture packets and > initialization commands. > > Reviewed-by: Chris Diamand <chris@diamand.org> > Signed-off-by: Richard Pospesel <pospeselr@gmail.com> > --- > Hi Dmitry, Richard (and others), > > I've tested Richard's latest patch, and can confirm that it works for me. This > is a resend of that patch, but generated with git-format-patch so hopefully it > should apply cleanly now. It's a verbatim copy, except I've moved one blank > line which I missed last time. > > Cheers! > Chris > > drivers/input/mouse/byd.c | 565 ++++++++++++++++++++++++------------- > drivers/input/mouse/psmouse-base.c | 2 +- > 2 files changed, 369 insertions(+), 198 deletions(-) > > diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c > index 9425e0f..fdc243c 100644 > --- a/drivers/input/mouse/byd.c > +++ b/drivers/input/mouse/byd.c > @@ -12,10 +12,12 @@ > #include <linux/input.h> > #include <linux/libps2.h> > #include <linux/serio.h> > +#include <linux/slab.h> > > #include "psmouse.h" > #include "byd.h" > > +/* PS2 Bits */ > #define PS2_Y_OVERFLOW BIT_MASK(7) > #define PS2_X_OVERFLOW BIT_MASK(6) > #define PS2_Y_SIGN BIT_MASK(5) > @@ -26,69 +28,249 @@ > #define PS2_LEFT BIT_MASK(0) > > /* > - * The touchpad reports gestures in the last byte of each packet. It can take > - * any of the following values: > + * BYD pad constants > */ > > -/* One-finger scrolling in one of the edge scroll zones. */ > -#define BYD_SCROLLUP 0xCA > -#define BYD_SCROLLDOWN 0x36 > -#define BYD_SCROLLLEFT 0xCB > -#define BYD_SCROLLRIGHT 0x35 > -/* Two-finger scrolling. */ > -#define BYD_2DOWN 0x2B > -#define BYD_2UP 0xD5 > -#define BYD_2LEFT 0xD6 > -#define BYD_2RIGHT 0x2A > -/* Pinching in or out. */ > -#define BYD_ZOOMOUT 0xD8 > -#define BYD_ZOOMIN 0x28 > -/* Three-finger swipe. */ > -#define BYD_3UP 0xD3 > -#define BYD_3DOWN 0x2D > -#define BYD_3LEFT 0xD4 > -#define BYD_3RIGHT 0x2C > -/* Four-finger swipe. */ > -#define BYD_4UP 0xCD > -#define BYD_4DOWN 0x33 > +/* > + * True device resolution is unknown, however experiments show the > + * resolution is about 111 units/mm. > + * Absolute coordinate packets are in the range 0-255 for both X and Y > + * we pick ABS_X/ABS_Y dimensions which are multiples of 256 and in > + * the right ballpark given the touchpad's physical dimensions and estimate > + * resolution per spec sheet, device active area dimensions are > + * 101.6 x 60.1 mm. > + */ > +#define BYD_PAD_WIDTH 11264 > +#define BYD_PAD_HEIGHT 6656 > +#define BYD_PAD_RESOLUTION 111 > > -int byd_detect(struct psmouse *psmouse, bool set_properties) > +/* > + * Given the above dimensions, relative packets velocity is in multiples of > + * 1 unit / 11 milliseconds. We use this dt to estimate distance traveled > + */ > +#define BYD_DT 11 > +/* Time in jiffies used to timeout various touch events (64 ms) */ > +#define BYD_TOUCH_TIMEOUT msecs_to_jiffies(64) > + > +/* BYD commands reverse engineered from windows driver */ > + > +/* > + * Swipe gesture from off-pad to on-pad > + * 0 : disable > + * 1 : enable > + */ > +#define BYD_CMD_SET_OFFSCREEN_SWIPE 0x10cc > +/* > + * Tap and drag delay time > + * 0 : disable > + * 1 - 8 : least to most delay > + */ > +#define BYD_CMD_SET_TAP_DRAG_DELAY_TIME 0x10cf > +/* > + * Physical buttons function mapping > + * 0 : enable > + * 4 : normal > + * 5 : left button custom command > + * 6 : right button custom command > + * 8 : disable > + */ > +#define BYD_CMD_SET_PHYSICAL_BUTTONS 0x10d0 > +/* > + * Absolute mode (1 byte X/Y resolution) > + * 0 : disable > + * 2 : enable > + */ > +#define BYD_CMD_SET_ABSOLUTE_MODE 0x10d1 > +/* > + * Two finger scrolling > + * 1 : vertical > + * 2 : horizontal > + * 3 : vertical + horizontal > + * 4 : disable > + */ > +#define BYD_CMD_SET_TWO_FINGER_SCROLL 0x10d2 > +/* > + * Handedness > + * 1 : right handed > + * 2 : left handed > + */ > +#define BYD_CMD_SET_HANDEDNESS 0x10d3 > +/* > + * Tap to click > + * 1 : enable > + * 2 : disable > + */ > +#define BYD_CMD_SET_TAP 0x10d4 > +/* > + * Tap and drag > + * 1 : tap and hold to drag > + * 2 : tap and hold to drag + lock > + * 3 : disable > + */ > +#define BYD_CMD_SET_TAP_DRAG 0x10d5 > +/* > + * Touch sensitivity > + * 1 - 7 : least to most sensitive > + */ > +#define BYD_CMD_SET_TOUCH_SENSITIVITY 0x10d6 > +/* > + * One finger scrolling > + * 1 : vertical > + * 2 : horizontal > + * 3 : vertical + horizontal > + * 4 : disable > + */ > +#define BYD_CMD_SET_ONE_FINGER_SCROLL 0x10d7 > +/* > + * One finger scrolling function > + * 1 : free scrolling > + * 2 : edge motion > + * 3 : free scrolling + edge motion > + * 4 : disable > + */ > +#define BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC 0x10d8 > +/* > + * Sliding speed > + * 1 - 5 : slowest to fastest > + */ > +#define BYD_CMD_SET_SLIDING_SPEED 0x10da > +/* > + * Edge motion > + * 1 : disable > + * 2 : enable when dragging > + * 3 : enable when dragging and pointing > + */ > +#define BYD_CMD_SET_EDGE_MOTION 0x10db > +/* > + * Left edge region size > + * 0 - 7 : smallest to largest width > + */ > +#define BYD_CMD_SET_LEFT_EDGE_REGION 0x10dc > +/* > + * Top edge region size > + * 0 - 9 : smallest to largest height > + */ > +#define BYD_CMD_SET_TOP_EDGE_REGION 0x10dd > +/* > + * Disregard palm press as clicks > + * 1 - 6 : smallest to largest > + */ > +#define BYD_CMD_SET_PALM_CHECK 0x10de > +/* > + * Right edge region size > + * 0 - 7 : smallest to largest width > + */ > +#define BYD_CMD_SET_RIGHT_EDGE_REGION 0x10df > +/* > + * Bottom edge region size > + * 0 - 9 : smallest to largest height > + */ > +#define BYD_CMD_SET_BOTTOM_EDGE_REGION 0x10e1 > +/* > + * Multitouch gestures > + * 1 : enable > + * 2 : disable > + */ > +#define BYD_CMD_SET_MULTITOUCH 0x10e3 > +/* > + * Edge motion speed > + * 0 : control with finger pressure > + * 1 - 9 : slowest to fastest > + */ > +#define BYD_CMD_SET_EDGE_MOTION_SPEED 0x10e4 > +/* > + * Two finger scolling function > + * 0 : free scrolling > + * 1 : free scrolling (with momentum) > + * 2 : edge motion > + * 3 : free scrolling (with momentum) + edge motion > + * 4 : disable > + */ > +#define BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC 0x10e5 > + > +/* > + * The touchpad generates a mixture of absolute and relative packets, indicated > + * by the the last byte of each packet being set to one of the following: > + */ > +#define BYD_PACKET_ABSOLUTE 0xf8 > +#define BYD_PACKET_RELATIVE 0x00 > +/* Multitouch gesture packets */ > +#define BYD_PACKET_PINCH_IN 0xd8 > +#define BYD_PACKET_PINCH_OUT 0x28 > +#define BYD_PACKET_ROTATE_CLOCKWISE 0x29 > +#define BYD_PACKET_ROTATE_ANTICLOCKWISE 0xd7 > +#define BYD_PACKET_TWO_FINGER_SCROLL_RIGHT 0x2a > +#define BYD_PACKET_TWO_FINGER_SCROLL_DOWN 0x2b > +#define BYD_PACKET_TWO_FINGER_SCROLL_UP 0xd5 > +#define BYD_PACKET_TWO_FINGER_SCROLL_LEFT 0xd6 > +#define BYD_PACKET_THREE_FINGER_SWIPE_RIGHT 0x2c > +#define BYD_PACKET_THREE_FINGER_SWIPE_DOWN 0x2d > +#define BYD_PACKET_THREE_FINGER_SWIPE_UP 0xd3 > +#define BYD_PACKET_THREE_FINGER_SWIPE_LEFT 0xd4 > +#define BYD_PACKET_FOUR_FINGER_DOWN 0x33 > +#define BYD_PACKET_FOUR_FINGER_UP 0xcd > +#define BYD_PACKET_REGION_SCROLL_RIGHT 0x35 > +#define BYD_PACKET_REGION_SCROLL_DOWN 0x36 > +#define BYD_PACKET_REGION_SCROLL_UP 0xca > +#define BYD_PACKET_REGION_SCROLL_LEFT 0xcb > +#define BYD_PACKET_RIGHT_CORNER_CLICK 0xd2 > +#define BYD_PACKET_LEFT_CORNER_CLICK 0x2e > +#define BYD_PACKET_LEFT_AND_RIGHT_CORNER_CLICK 0x2f > +#define BYD_PACKET_ONTO_PAD_SWIPE_RIGHT 0x37 > +#define BYD_PACKET_ONTO_PAD_SWIPE_DOWN 0x30 > +#define BYD_PACKET_ONTO_PAD_SWIPE_UP 0xd0 > +#define BYD_PACKET_ONTO_PAD_SWIPE_LEFT 0xc9 > + > +struct byd_data { > + struct timer_list timer; > + s32 abs_x; > + s32 abs_y; > + typeof(jiffies) last_touch_time; > + bool btn_left; > + bool btn_right; > + bool touch; > +}; > + > +static void byd_report_input(struct psmouse *psmouse) > { > - struct ps2dev *ps2dev = &psmouse->ps2dev; > - unsigned char param[4]; > + struct byd_data *priv = psmouse->private; > + struct input_dev *dev = psmouse->dev; > > - param[0] = 0x03; > - param[1] = 0x00; > - param[2] = 0x00; > - param[3] = 0x00; > + input_report_key(dev, BTN_TOUCH, priv->touch); > + input_report_key(dev, BTN_TOOL_FINGER, priv->touch); > > - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) > - return -1; > - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) > - return -1; > - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) > - return -1; > - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) > - return -1; > - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) > - return -1; > + input_report_abs(dev, ABS_X, priv->abs_x); > + input_report_abs(dev, ABS_Y, priv->abs_y); > + input_report_key(dev, BTN_LEFT, priv->btn_left); > + input_report_key(dev, BTN_RIGHT, priv->btn_right); > > - if (param[1] != 0x03 || param[2] != 0x64) > - return -ENODEV; > + input_sync(dev); > +} > > - psmouse_dbg(psmouse, "BYD touchpad detected\n"); > +static void byd_clear_touch(unsigned long data) > +{ > + struct psmouse *psmouse = (struct psmouse *)data; > + struct byd_data *priv = psmouse->private; > > - if (set_properties) { > - psmouse->vendor = "BYD"; > - psmouse->name = "TouchPad"; > - } > + serio_pause_rx(psmouse->ps2dev.serio); > + priv->touch = false; > > - return 0; > + byd_report_input(psmouse); > + > + serio_continue_rx(psmouse->ps2dev.serio); > + > + /* > + * Move cursor back to center of pad when we lose touch - this > + * specifically improves user experience when moving cursor with one > + * finger, and pressing a button with another. > + */ > + priv->abs_x = BYD_PAD_WIDTH / 2; > + priv->abs_y = BYD_PAD_HEIGHT / 2; > } > > static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) > { > - struct input_dev *dev = psmouse->dev; > + struct byd_data *priv = psmouse->private; > u8 *pkt = psmouse->packet; > > if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) { > @@ -102,53 +284,34 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) > > /* Otherwise, a full packet has been received */ > switch (pkt[3]) { > - case 0: { > + case BYD_PACKET_ABSOLUTE: > + /* Only use absolute packets for the start of movement. */ > + if (!priv->touch) { > + /* needed to detect tap */ > + typeof(jiffies) tap_time = > + priv->last_touch_time + BYD_TOUCH_TIMEOUT; > + priv->touch = time_after(jiffies, tap_time); > + > + /* init abs position */ > + priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256); > + priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / 256); > + } > + break; > + case BYD_PACKET_RELATIVE: { > /* Standard packet */ > /* Sign-extend if a sign bit is set. */ > - unsigned int signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; > - unsigned int signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; > - int dx = signx | (int) pkt[1]; > - int dy = signy | (int) pkt[2]; > + u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; > + u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; > + s32 dx = signx | (int) pkt[1]; > + s32 dy = signy | (int) pkt[2]; > > - input_report_rel(psmouse->dev, REL_X, dx); > - input_report_rel(psmouse->dev, REL_Y, -dy); > + /* Update position based on velocity */ > + priv->abs_x += dx * BYD_DT; > + priv->abs_y -= dy * BYD_DT; > > - input_report_key(psmouse->dev, BTN_LEFT, pkt[0] & PS2_LEFT); > - input_report_key(psmouse->dev, BTN_RIGHT, pkt[0] & PS2_RIGHT); > - input_report_key(psmouse->dev, BTN_MIDDLE, pkt[0] & PS2_MIDDLE); > + priv->touch = true; > break; > } > - > - case BYD_SCROLLDOWN: > - case BYD_2DOWN: > - input_report_rel(dev, REL_WHEEL, -1); > - break; > - > - case BYD_SCROLLUP: > - case BYD_2UP: > - input_report_rel(dev, REL_WHEEL, 1); > - break; > - > - case BYD_SCROLLLEFT: > - case BYD_2LEFT: > - input_report_rel(dev, REL_HWHEEL, -1); > - break; > - > - case BYD_SCROLLRIGHT: > - case BYD_2RIGHT: > - input_report_rel(dev, REL_HWHEEL, 1); > - break; > - > - case BYD_ZOOMOUT: > - case BYD_ZOOMIN: > - case BYD_3UP: > - case BYD_3DOWN: > - case BYD_3LEFT: > - case BYD_3RIGHT: > - case BYD_4UP: > - case BYD_4DOWN: > - break; > - > default: > psmouse_warn(psmouse, > "Unrecognized Z: pkt = %02x %02x %02x %02x\n", > @@ -157,134 +320,76 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) > return PSMOUSE_BAD_DATA; > } > > - input_sync(dev); > + priv->btn_left = pkt[0] & PS2_LEFT; > + priv->btn_right = pkt[0] & PS2_RIGHT; > > - return PSMOUSE_FULL_PACKET; > -} > + byd_report_input(psmouse); > > -/* Send a sequence of bytes, where each is ACKed before the next is sent. */ > -static int byd_send_sequence(struct psmouse *psmouse, const u8 *seq, size_t len) > -{ > - unsigned int i; > - > - for (i = 0; i < len; ++i) { > - if (ps2_command(&psmouse->ps2dev, NULL, seq[i])) > - return -1; > + /* Reset time since last touch. */ > + if (priv->touch) { > + priv->last_touch_time = jiffies; > + mod_timer(&priv->timer, jiffies + BYD_TOUCH_TIMEOUT); > } > - return 0; > -} > - > -/* Keep scrolling after fingers are removed. */ > -#define SCROLL_INERTIAL 0x01 > -#define SCROLL_NO_INERTIAL 0x02 > - > -/* Clicking can be done by tapping or pressing. */ > -#define CLICK_BOTH 0x01 > -/* Clicking can only be done by pressing. */ > -#define CLICK_PRESS_ONLY 0x02 > > -static int byd_enable(struct psmouse *psmouse) > -{ > - const u8 seq1[] = { 0xE2, 0x00, 0xE0, 0x02, 0xE0 }; > - const u8 seq2[] = { > - 0xD3, 0x01, > - 0xD0, 0x00, > - 0xD0, 0x04, > - /* Whether clicking is done by tapping or pressing. */ > - 0xD4, CLICK_PRESS_ONLY, > - 0xD5, 0x01, > - 0xD7, 0x03, > - /* Vertical and horizontal one-finger scroll zone inertia. */ > - 0xD8, SCROLL_INERTIAL, > - 0xDA, 0x05, > - 0xDB, 0x02, > - 0xE4, 0x05, > - 0xD6, 0x01, > - 0xDE, 0x04, > - 0xE3, 0x01, > - 0xCF, 0x00, > - 0xD2, 0x03, > - /* Vertical and horizontal two-finger scrolling inertia. */ > - 0xE5, SCROLL_INERTIAL, > - 0xD9, 0x02, > - 0xD9, 0x07, > - 0xDC, 0x03, > - 0xDD, 0x03, > - 0xDF, 0x03, > - 0xE1, 0x03, > - 0xD1, 0x00, > - 0xCE, 0x00, > - 0xCC, 0x00, > - 0xE0, 0x00, > - 0xE2, 0x01 > - }; > - u8 param[4]; > - > - if (byd_send_sequence(psmouse, seq1, ARRAY_SIZE(seq1))) > - return -1; > - > - /* Send a 0x01 command, which should return 4 bytes. */ > - if (ps2_command(&psmouse->ps2dev, param, 0x0401)) > - return -1; > - > - if (byd_send_sequence(psmouse, seq2, ARRAY_SIZE(seq2))) > - return -1; > - > - return 0; > + return PSMOUSE_FULL_PACKET; > } > > -/* > - * Send the set of PS/2 commands required to make it identify as an > - * intellimouse with 4-byte instead of 3-byte packets. > - */ > -static int byd_send_intellimouse_sequence(struct psmouse *psmouse) > +static int byd_reset_touchpad(struct psmouse *psmouse) > { > struct ps2dev *ps2dev = &psmouse->ps2dev; > u8 param[4]; > - int i; > + size_t i; > + > const struct { > u16 command; > u8 arg; > } seq[] = { > - { PSMOUSE_CMD_RESET_BAT, 0 }, > - { PSMOUSE_CMD_RESET_BAT, 0 }, > - { PSMOUSE_CMD_GETID, 0 }, > - { PSMOUSE_CMD_SETSCALE11, 0 }, > - { PSMOUSE_CMD_SETSCALE11, 0 }, > - { PSMOUSE_CMD_SETSCALE11, 0 }, > - { PSMOUSE_CMD_GETINFO, 0 }, > - { PSMOUSE_CMD_SETRES, 0x03 }, > + /* > + * Intellimouse initialization sequence, to get 4-byte instead > + * of 3-byte packets. > + */ > { PSMOUSE_CMD_SETRATE, 0xC8 }, > { PSMOUSE_CMD_SETRATE, 0x64 }, > { PSMOUSE_CMD_SETRATE, 0x50 }, > { PSMOUSE_CMD_GETID, 0 }, > - { PSMOUSE_CMD_SETRATE, 0xC8 }, > - { PSMOUSE_CMD_SETRATE, 0xC8 }, > - { PSMOUSE_CMD_SETRATE, 0x50 }, > - { PSMOUSE_CMD_GETID, 0 }, > - { PSMOUSE_CMD_SETRATE, 0x64 }, > - { PSMOUSE_CMD_SETRES, 0x03 }, > - { PSMOUSE_CMD_ENABLE, 0 } > + { PSMOUSE_CMD_ENABLE, 0 }, > + /* > + * BYD-specific initialization, which enables absolute mode and > + * (if desired), the touchpad's built-in gesture detection. > + */ > + { 0x10E2, 0x00 }, > + { 0x10E0, 0x02 }, > + /* The touchpad should reply with 4 seemingly-random bytes */ > + { 0x14E0, 0x01 }, > + /* Pairs of parameters and values. */ > + { BYD_CMD_SET_HANDEDNESS, 0x01 }, > + { BYD_CMD_SET_PHYSICAL_BUTTONS, 0x04 }, > + { BYD_CMD_SET_TAP, 0x02 }, > + { BYD_CMD_SET_ONE_FINGER_SCROLL, 0x04 }, > + { BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC, 0x04 }, > + { BYD_CMD_SET_EDGE_MOTION, 0x01 }, > + { BYD_CMD_SET_PALM_CHECK, 0x00 }, > + { BYD_CMD_SET_MULTITOUCH, 0x02 }, > + { BYD_CMD_SET_TWO_FINGER_SCROLL, 0x04 }, > + { BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC, 0x04 }, > + { BYD_CMD_SET_LEFT_EDGE_REGION, 0x00 }, > + { BYD_CMD_SET_TOP_EDGE_REGION, 0x00 }, > + { BYD_CMD_SET_RIGHT_EDGE_REGION, 0x00 }, > + { BYD_CMD_SET_BOTTOM_EDGE_REGION, 0x00 }, > + { BYD_CMD_SET_ABSOLUTE_MODE, 0x02 }, > + /* Finalize initialization. */ > + { 0x10E0, 0x00 }, > + { 0x10E2, 0x01 }, > }; > > - memset(param, 0, sizeof(param)); > for (i = 0; i < ARRAY_SIZE(seq); ++i) { > + memset(param, 0, sizeof(param)); > param[0] = seq[i].arg; > if (ps2_command(ps2dev, param, seq[i].command)) > - return -1; > + return -EIO; > } > > - return 0; > -} > - > -static int byd_reset_touchpad(struct psmouse *psmouse) > -{ > - if (byd_send_intellimouse_sequence(psmouse)) > - return -EIO; > - > - if (byd_enable(psmouse)) > - return -EIO; > - > + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); > return 0; > } > > @@ -314,9 +419,50 @@ static int byd_reconnect(struct psmouse *psmouse) > return 0; > } > > +static void byd_disconnect(struct psmouse *psmouse) > +{ > + struct byd_data *priv = psmouse->private; > + > + if (priv) { > + del_timer(&priv->timer); > + kfree(psmouse->private); > + psmouse->private = NULL; > + } > +} > + > +int byd_detect(struct psmouse *psmouse, bool set_properties) > +{ > + struct ps2dev *ps2dev = &psmouse->ps2dev; > + u8 param[4] = {0x03, 0x00, 0x00, 0x00}; > + > + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) > + return -1; > + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) > + return -1; > + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) > + return -1; > + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) > + return -1; > + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) > + return -1; > + > + if (param[1] != 0x03 || param[2] != 0x64) > + return -ENODEV; > + > + psmouse_dbg(psmouse, "BYD touchpad detected\n"); > + > + if (set_properties) { > + psmouse->vendor = "BYD"; > + psmouse->name = "TouchPad"; > + } > + > + return 0; > +} > + > int byd_init(struct psmouse *psmouse) > { > struct input_dev *dev = psmouse->dev; > + struct byd_data *priv; > > if (psmouse_reset(psmouse)) > return -EIO; > @@ -324,14 +470,39 @@ int byd_init(struct psmouse *psmouse) > if (byd_reset_touchpad(psmouse)) > return -EIO; > > + priv = kzalloc(sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + memset(priv, 0, sizeof(*priv)); > + setup_timer(&priv->timer, byd_clear_touch, (unsigned long) psmouse); > + > + psmouse->private = priv; > + psmouse->disconnect = byd_disconnect; > psmouse->reconnect = byd_reconnect; > psmouse->protocol_handler = byd_process_byte; > psmouse->pktsize = 4; > psmouse->resync_time = 0; > > - __set_bit(BTN_MIDDLE, dev->keybit); > - __set_bit(REL_WHEEL, dev->relbit); > - __set_bit(REL_HWHEEL, dev->relbit); > + __set_bit(INPUT_PROP_POINTER, dev->propbit); > + /* Touchpad */ > + __set_bit(BTN_TOUCH, dev->keybit); > + __set_bit(BTN_TOOL_FINGER, dev->keybit); > + /* Buttons */ > + __set_bit(BTN_LEFT, dev->keybit); > + __set_bit(BTN_RIGHT, dev->keybit); > + __clear_bit(BTN_MIDDLE, dev->keybit); > + > + /* Absolute position */ > + __set_bit(EV_ABS, dev->evbit); > + input_set_abs_params(dev, ABS_X, 0, BYD_PAD_WIDTH, 0, 0); > + input_set_abs_params(dev, ABS_Y, 0, BYD_PAD_HEIGHT, 0, 0); > + input_abs_set_res(dev, ABS_X, BYD_PAD_RESOLUTION); > + input_abs_set_res(dev, ABS_Y, BYD_PAD_RESOLUTION); > + /* No relative support */ > + __clear_bit(EV_REL, dev->evbit); > + __clear_bit(REL_X, dev->relbit); > + __clear_bit(REL_Y, dev->relbit); > > return 0; > } > diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c > index 39d1bec..5784e20 100644 > --- a/drivers/input/mouse/psmouse-base.c > +++ b/drivers/input/mouse/psmouse-base.c > @@ -846,7 +846,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { > #ifdef CONFIG_MOUSE_PS2_BYD > { > .type = PSMOUSE_BYD, > - .name = "BydPS/2", > + .name = "BYDPS/2", > .alias = "byd", > .detect = byd_detect, > .init = byd_init, > -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Mar 25, 2016 at 3:43 PM, Richard Pospesel <pospeselr@gmail.com> wrote: > Pinging you on this. Sorry for not responding earlier. It is included in my 2nd pull request for 4.6-rc1. > > -Richard > > On Thu, Mar 17, 2016 at 8:51 AM, Richard Pospesel <pospeselr@gmail.com> > wrote: >> >> Are there any more concerns Dmitry? >> >> best, >> -Richard >> >> >> On 03/12/2016 05:32 AM, Chris Diamand wrote: >>> >>> From: Richard Pospesel <pospeselr@gmail.com> >>> >>> The Windows driver's settings dialog contains a visualization of the >>> regions for the hardware edge scrolling capability, which uses a >>> temporarily-enabled limited-resolution absolute mode. >>> >>> This patch enables this during normal operation, and combines the >>> absolute packets with the existing relative packets to provide >>> accurate absolute position and touch reporting. >>> >>> It also adds documentation for all known gesture packets and >>> initialization commands. >>> >>> Reviewed-by: Chris Diamand <chris@diamand.org> >>> Signed-off-by: Richard Pospesel <pospeselr@gmail.com> >>> --- >>> Hi Dmitry, Richard (and others), >>> >>> I've tested Richard's latest patch, and can confirm that it works for me. >>> This >>> is a resend of that patch, but generated with git-format-patch so >>> hopefully it >>> should apply cleanly now. It's a verbatim copy, except I've moved one >>> blank >>> line which I missed last time. >>> >>> Cheers! >>> Chris >>> >>> drivers/input/mouse/byd.c | 565 >>> ++++++++++++++++++++++++------------- >>> drivers/input/mouse/psmouse-base.c | 2 +- >>> 2 files changed, 369 insertions(+), 198 deletions(-) >>> >>> diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c >>> index 9425e0f..fdc243c 100644 >>> --- a/drivers/input/mouse/byd.c >>> +++ b/drivers/input/mouse/byd.c >>> @@ -12,10 +12,12 @@ >>> #include <linux/input.h> >>> #include <linux/libps2.h> >>> #include <linux/serio.h> >>> +#include <linux/slab.h> >>> >>> #include "psmouse.h" >>> #include "byd.h" >>> >>> +/* PS2 Bits */ >>> #define PS2_Y_OVERFLOW BIT_MASK(7) >>> #define PS2_X_OVERFLOW BIT_MASK(6) >>> #define PS2_Y_SIGN BIT_MASK(5) >>> @@ -26,69 +28,249 @@ >>> #define PS2_LEFT BIT_MASK(0) >>> >>> /* >>> - * The touchpad reports gestures in the last byte of each packet. It can >>> take >>> - * any of the following values: >>> + * BYD pad constants >>> */ >>> >>> -/* One-finger scrolling in one of the edge scroll zones. */ >>> -#define BYD_SCROLLUP 0xCA >>> -#define BYD_SCROLLDOWN 0x36 >>> -#define BYD_SCROLLLEFT 0xCB >>> -#define BYD_SCROLLRIGHT 0x35 >>> -/* Two-finger scrolling. */ >>> -#define BYD_2DOWN 0x2B >>> -#define BYD_2UP 0xD5 >>> -#define BYD_2LEFT 0xD6 >>> -#define BYD_2RIGHT 0x2A >>> -/* Pinching in or out. */ >>> -#define BYD_ZOOMOUT 0xD8 >>> -#define BYD_ZOOMIN 0x28 >>> -/* Three-finger swipe. */ >>> -#define BYD_3UP 0xD3 >>> -#define BYD_3DOWN 0x2D >>> -#define BYD_3LEFT 0xD4 >>> -#define BYD_3RIGHT 0x2C >>> -/* Four-finger swipe. */ >>> -#define BYD_4UP 0xCD >>> -#define BYD_4DOWN 0x33 >>> +/* >>> + * True device resolution is unknown, however experiments show the >>> + * resolution is about 111 units/mm. >>> + * Absolute coordinate packets are in the range 0-255 for both X and Y >>> + * we pick ABS_X/ABS_Y dimensions which are multiples of 256 and in >>> + * the right ballpark given the touchpad's physical dimensions and >>> estimate >>> + * resolution per spec sheet, device active area dimensions are >>> + * 101.6 x 60.1 mm. >>> + */ >>> +#define BYD_PAD_WIDTH 11264 >>> +#define BYD_PAD_HEIGHT 6656 >>> +#define BYD_PAD_RESOLUTION 111 >>> >>> -int byd_detect(struct psmouse *psmouse, bool set_properties) >>> +/* >>> + * Given the above dimensions, relative packets velocity is in multiples >>> of >>> + * 1 unit / 11 milliseconds. We use this dt to estimate distance >>> traveled >>> + */ >>> +#define BYD_DT 11 >>> +/* Time in jiffies used to timeout various touch events (64 ms) */ >>> +#define BYD_TOUCH_TIMEOUT msecs_to_jiffies(64) >>> + >>> +/* BYD commands reverse engineered from windows driver */ >>> + >>> +/* >>> + * Swipe gesture from off-pad to on-pad >>> + * 0 : disable >>> + * 1 : enable >>> + */ >>> +#define BYD_CMD_SET_OFFSCREEN_SWIPE 0x10cc >>> +/* >>> + * Tap and drag delay time >>> + * 0 : disable >>> + * 1 - 8 : least to most delay >>> + */ >>> +#define BYD_CMD_SET_TAP_DRAG_DELAY_TIME 0x10cf >>> +/* >>> + * Physical buttons function mapping >>> + * 0 : enable >>> + * 4 : normal >>> + * 5 : left button custom command >>> + * 6 : right button custom command >>> + * 8 : disable >>> + */ >>> +#define BYD_CMD_SET_PHYSICAL_BUTTONS 0x10d0 >>> +/* >>> + * Absolute mode (1 byte X/Y resolution) >>> + * 0 : disable >>> + * 2 : enable >>> + */ >>> +#define BYD_CMD_SET_ABSOLUTE_MODE 0x10d1 >>> +/* >>> + * Two finger scrolling >>> + * 1 : vertical >>> + * 2 : horizontal >>> + * 3 : vertical + horizontal >>> + * 4 : disable >>> + */ >>> +#define BYD_CMD_SET_TWO_FINGER_SCROLL 0x10d2 >>> +/* >>> + * Handedness >>> + * 1 : right handed >>> + * 2 : left handed >>> + */ >>> +#define BYD_CMD_SET_HANDEDNESS 0x10d3 >>> +/* >>> + * Tap to click >>> + * 1 : enable >>> + * 2 : disable >>> + */ >>> +#define BYD_CMD_SET_TAP 0x10d4 >>> +/* >>> + * Tap and drag >>> + * 1 : tap and hold to drag >>> + * 2 : tap and hold to drag + lock >>> + * 3 : disable >>> + */ >>> +#define BYD_CMD_SET_TAP_DRAG 0x10d5 >>> +/* >>> + * Touch sensitivity >>> + * 1 - 7 : least to most sensitive >>> + */ >>> +#define BYD_CMD_SET_TOUCH_SENSITIVITY 0x10d6 >>> +/* >>> + * One finger scrolling >>> + * 1 : vertical >>> + * 2 : horizontal >>> + * 3 : vertical + horizontal >>> + * 4 : disable >>> + */ >>> +#define BYD_CMD_SET_ONE_FINGER_SCROLL 0x10d7 >>> +/* >>> + * One finger scrolling function >>> + * 1 : free scrolling >>> + * 2 : edge motion >>> + * 3 : free scrolling + edge motion >>> + * 4 : disable >>> + */ >>> +#define BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC 0x10d8 >>> +/* >>> + * Sliding speed >>> + * 1 - 5 : slowest to fastest >>> + */ >>> +#define BYD_CMD_SET_SLIDING_SPEED 0x10da >>> +/* >>> + * Edge motion >>> + * 1 : disable >>> + * 2 : enable when dragging >>> + * 3 : enable when dragging and pointing >>> + */ >>> +#define BYD_CMD_SET_EDGE_MOTION 0x10db >>> +/* >>> + * Left edge region size >>> + * 0 - 7 : smallest to largest width >>> + */ >>> +#define BYD_CMD_SET_LEFT_EDGE_REGION 0x10dc >>> +/* >>> + * Top edge region size >>> + * 0 - 9 : smallest to largest height >>> + */ >>> +#define BYD_CMD_SET_TOP_EDGE_REGION 0x10dd >>> +/* >>> + * Disregard palm press as clicks >>> + * 1 - 6 : smallest to largest >>> + */ >>> +#define BYD_CMD_SET_PALM_CHECK 0x10de >>> +/* >>> + * Right edge region size >>> + * 0 - 7 : smallest to largest width >>> + */ >>> +#define BYD_CMD_SET_RIGHT_EDGE_REGION 0x10df >>> +/* >>> + * Bottom edge region size >>> + * 0 - 9 : smallest to largest height >>> + */ >>> +#define BYD_CMD_SET_BOTTOM_EDGE_REGION 0x10e1 >>> +/* >>> + * Multitouch gestures >>> + * 1 : enable >>> + * 2 : disable >>> + */ >>> +#define BYD_CMD_SET_MULTITOUCH 0x10e3 >>> +/* >>> + * Edge motion speed >>> + * 0 : control with finger pressure >>> + * 1 - 9 : slowest to fastest >>> + */ >>> +#define BYD_CMD_SET_EDGE_MOTION_SPEED 0x10e4 >>> +/* >>> + * Two finger scolling function >>> + * 0 : free scrolling >>> + * 1 : free scrolling (with momentum) >>> + * 2 : edge motion >>> + * 3 : free scrolling (with momentum) + edge motion >>> + * 4 : disable >>> + */ >>> +#define BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC 0x10e5 >>> + >>> +/* >>> + * The touchpad generates a mixture of absolute and relative packets, >>> indicated >>> + * by the the last byte of each packet being set to one of the >>> following: >>> + */ >>> +#define BYD_PACKET_ABSOLUTE 0xf8 >>> +#define BYD_PACKET_RELATIVE 0x00 >>> +/* Multitouch gesture packets */ >>> +#define BYD_PACKET_PINCH_IN 0xd8 >>> +#define BYD_PACKET_PINCH_OUT 0x28 >>> +#define BYD_PACKET_ROTATE_CLOCKWISE 0x29 >>> +#define BYD_PACKET_ROTATE_ANTICLOCKWISE 0xd7 >>> +#define BYD_PACKET_TWO_FINGER_SCROLL_RIGHT 0x2a >>> +#define BYD_PACKET_TWO_FINGER_SCROLL_DOWN 0x2b >>> +#define BYD_PACKET_TWO_FINGER_SCROLL_UP 0xd5 >>> +#define BYD_PACKET_TWO_FINGER_SCROLL_LEFT 0xd6 >>> +#define BYD_PACKET_THREE_FINGER_SWIPE_RIGHT 0x2c >>> +#define BYD_PACKET_THREE_FINGER_SWIPE_DOWN 0x2d >>> +#define BYD_PACKET_THREE_FINGER_SWIPE_UP 0xd3 >>> +#define BYD_PACKET_THREE_FINGER_SWIPE_LEFT 0xd4 >>> +#define BYD_PACKET_FOUR_FINGER_DOWN 0x33 >>> +#define BYD_PACKET_FOUR_FINGER_UP 0xcd >>> +#define BYD_PACKET_REGION_SCROLL_RIGHT 0x35 >>> +#define BYD_PACKET_REGION_SCROLL_DOWN 0x36 >>> +#define BYD_PACKET_REGION_SCROLL_UP 0xca >>> +#define BYD_PACKET_REGION_SCROLL_LEFT 0xcb >>> +#define BYD_PACKET_RIGHT_CORNER_CLICK 0xd2 >>> +#define BYD_PACKET_LEFT_CORNER_CLICK 0x2e >>> +#define BYD_PACKET_LEFT_AND_RIGHT_CORNER_CLICK 0x2f >>> +#define BYD_PACKET_ONTO_PAD_SWIPE_RIGHT 0x37 >>> +#define BYD_PACKET_ONTO_PAD_SWIPE_DOWN 0x30 >>> +#define BYD_PACKET_ONTO_PAD_SWIPE_UP 0xd0 >>> +#define BYD_PACKET_ONTO_PAD_SWIPE_LEFT 0xc9 >>> + >>> +struct byd_data { >>> + struct timer_list timer; >>> + s32 abs_x; >>> + s32 abs_y; >>> + typeof(jiffies) last_touch_time; >>> + bool btn_left; >>> + bool btn_right; >>> + bool touch; >>> +}; >>> + >>> +static void byd_report_input(struct psmouse *psmouse) >>> { >>> - struct ps2dev *ps2dev = &psmouse->ps2dev; >>> - unsigned char param[4]; >>> + struct byd_data *priv = psmouse->private; >>> + struct input_dev *dev = psmouse->dev; >>> >>> - param[0] = 0x03; >>> - param[1] = 0x00; >>> - param[2] = 0x00; >>> - param[3] = 0x00; >>> + input_report_key(dev, BTN_TOUCH, priv->touch); >>> + input_report_key(dev, BTN_TOOL_FINGER, priv->touch); >>> >>> - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) >>> - return -1; >>> - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) >>> - return -1; >>> - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) >>> - return -1; >>> - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) >>> - return -1; >>> - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) >>> - return -1; >>> + input_report_abs(dev, ABS_X, priv->abs_x); >>> + input_report_abs(dev, ABS_Y, priv->abs_y); >>> + input_report_key(dev, BTN_LEFT, priv->btn_left); >>> + input_report_key(dev, BTN_RIGHT, priv->btn_right); >>> >>> - if (param[1] != 0x03 || param[2] != 0x64) >>> - return -ENODEV; >>> + input_sync(dev); >>> +} >>> >>> - psmouse_dbg(psmouse, "BYD touchpad detected\n"); >>> +static void byd_clear_touch(unsigned long data) >>> +{ >>> + struct psmouse *psmouse = (struct psmouse *)data; >>> + struct byd_data *priv = psmouse->private; >>> >>> - if (set_properties) { >>> - psmouse->vendor = "BYD"; >>> - psmouse->name = "TouchPad"; >>> - } >>> + serio_pause_rx(psmouse->ps2dev.serio); >>> + priv->touch = false; >>> >>> - return 0; >>> + byd_report_input(psmouse); >>> + >>> + serio_continue_rx(psmouse->ps2dev.serio); >>> + >>> + /* >>> + * Move cursor back to center of pad when we lose touch - this >>> + * specifically improves user experience when moving cursor with >>> one >>> + * finger, and pressing a button with another. >>> + */ >>> + priv->abs_x = BYD_PAD_WIDTH / 2; >>> + priv->abs_y = BYD_PAD_HEIGHT / 2; >>> } >>> >>> static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) >>> { >>> - struct input_dev *dev = psmouse->dev; >>> + struct byd_data *priv = psmouse->private; >>> u8 *pkt = psmouse->packet; >>> >>> if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) { >>> @@ -102,53 +284,34 @@ static psmouse_ret_t byd_process_byte(struct >>> psmouse *psmouse) >>> >>> /* Otherwise, a full packet has been received */ >>> switch (pkt[3]) { >>> - case 0: { >>> + case BYD_PACKET_ABSOLUTE: >>> + /* Only use absolute packets for the start of movement. >>> */ >>> + if (!priv->touch) { >>> + /* needed to detect tap */ >>> + typeof(jiffies) tap_time = >>> + priv->last_touch_time + >>> BYD_TOUCH_TIMEOUT; >>> + priv->touch = time_after(jiffies, tap_time); >>> + >>> + /* init abs position */ >>> + priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256); >>> + priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / >>> 256); >>> + } >>> + break; >>> + case BYD_PACKET_RELATIVE: { >>> /* Standard packet */ >>> /* Sign-extend if a sign bit is set. */ >>> - unsigned int signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; >>> - unsigned int signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; >>> - int dx = signx | (int) pkt[1]; >>> - int dy = signy | (int) pkt[2]; >>> + u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; >>> + u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; >>> + s32 dx = signx | (int) pkt[1]; >>> + s32 dy = signy | (int) pkt[2]; >>> >>> - input_report_rel(psmouse->dev, REL_X, dx); >>> - input_report_rel(psmouse->dev, REL_Y, -dy); >>> + /* Update position based on velocity */ >>> + priv->abs_x += dx * BYD_DT; >>> + priv->abs_y -= dy * BYD_DT; >>> >>> - input_report_key(psmouse->dev, BTN_LEFT, pkt[0] & >>> PS2_LEFT); >>> - input_report_key(psmouse->dev, BTN_RIGHT, pkt[0] & >>> PS2_RIGHT); >>> - input_report_key(psmouse->dev, BTN_MIDDLE, pkt[0] & >>> PS2_MIDDLE); >>> + priv->touch = true; >>> break; >>> } >>> - >>> - case BYD_SCROLLDOWN: >>> - case BYD_2DOWN: >>> - input_report_rel(dev, REL_WHEEL, -1); >>> - break; >>> - >>> - case BYD_SCROLLUP: >>> - case BYD_2UP: >>> - input_report_rel(dev, REL_WHEEL, 1); >>> - break; >>> - >>> - case BYD_SCROLLLEFT: >>> - case BYD_2LEFT: >>> - input_report_rel(dev, REL_HWHEEL, -1); >>> - break; >>> - >>> - case BYD_SCROLLRIGHT: >>> - case BYD_2RIGHT: >>> - input_report_rel(dev, REL_HWHEEL, 1); >>> - break; >>> - >>> - case BYD_ZOOMOUT: >>> - case BYD_ZOOMIN: >>> - case BYD_3UP: >>> - case BYD_3DOWN: >>> - case BYD_3LEFT: >>> - case BYD_3RIGHT: >>> - case BYD_4UP: >>> - case BYD_4DOWN: >>> - break; >>> - >>> default: >>> psmouse_warn(psmouse, >>> "Unrecognized Z: pkt = %02x %02x %02x >>> %02x\n", >>> @@ -157,134 +320,76 @@ static psmouse_ret_t byd_process_byte(struct >>> psmouse *psmouse) >>> return PSMOUSE_BAD_DATA; >>> } >>> >>> - input_sync(dev); >>> + priv->btn_left = pkt[0] & PS2_LEFT; >>> + priv->btn_right = pkt[0] & PS2_RIGHT; >>> >>> - return PSMOUSE_FULL_PACKET; >>> -} >>> + byd_report_input(psmouse); >>> >>> -/* Send a sequence of bytes, where each is ACKed before the next is >>> sent. */ >>> -static int byd_send_sequence(struct psmouse *psmouse, const u8 *seq, >>> size_t len) >>> -{ >>> - unsigned int i; >>> - >>> - for (i = 0; i < len; ++i) { >>> - if (ps2_command(&psmouse->ps2dev, NULL, seq[i])) >>> - return -1; >>> + /* Reset time since last touch. */ >>> + if (priv->touch) { >>> + priv->last_touch_time = jiffies; >>> + mod_timer(&priv->timer, jiffies + BYD_TOUCH_TIMEOUT); >>> } >>> - return 0; >>> -} >>> - >>> -/* Keep scrolling after fingers are removed. */ >>> -#define SCROLL_INERTIAL 0x01 >>> -#define SCROLL_NO_INERTIAL 0x02 >>> - >>> -/* Clicking can be done by tapping or pressing. */ >>> -#define CLICK_BOTH 0x01 >>> -/* Clicking can only be done by pressing. */ >>> -#define CLICK_PRESS_ONLY 0x02 >>> >>> -static int byd_enable(struct psmouse *psmouse) >>> -{ >>> - const u8 seq1[] = { 0xE2, 0x00, 0xE0, 0x02, 0xE0 }; >>> - const u8 seq2[] = { >>> - 0xD3, 0x01, >>> - 0xD0, 0x00, >>> - 0xD0, 0x04, >>> - /* Whether clicking is done by tapping or pressing. */ >>> - 0xD4, CLICK_PRESS_ONLY, >>> - 0xD5, 0x01, >>> - 0xD7, 0x03, >>> - /* Vertical and horizontal one-finger scroll zone >>> inertia. */ >>> - 0xD8, SCROLL_INERTIAL, >>> - 0xDA, 0x05, >>> - 0xDB, 0x02, >>> - 0xE4, 0x05, >>> - 0xD6, 0x01, >>> - 0xDE, 0x04, >>> - 0xE3, 0x01, >>> - 0xCF, 0x00, >>> - 0xD2, 0x03, >>> - /* Vertical and horizontal two-finger scrolling inertia. >>> */ >>> - 0xE5, SCROLL_INERTIAL, >>> - 0xD9, 0x02, >>> - 0xD9, 0x07, >>> - 0xDC, 0x03, >>> - 0xDD, 0x03, >>> - 0xDF, 0x03, >>> - 0xE1, 0x03, >>> - 0xD1, 0x00, >>> - 0xCE, 0x00, >>> - 0xCC, 0x00, >>> - 0xE0, 0x00, >>> - 0xE2, 0x01 >>> - }; >>> - u8 param[4]; >>> - >>> - if (byd_send_sequence(psmouse, seq1, ARRAY_SIZE(seq1))) >>> - return -1; >>> - >>> - /* Send a 0x01 command, which should return 4 bytes. */ >>> - if (ps2_command(&psmouse->ps2dev, param, 0x0401)) >>> - return -1; >>> - >>> - if (byd_send_sequence(psmouse, seq2, ARRAY_SIZE(seq2))) >>> - return -1; >>> - >>> - return 0; >>> + return PSMOUSE_FULL_PACKET; >>> } >>> >>> -/* >>> - * Send the set of PS/2 commands required to make it identify as an >>> - * intellimouse with 4-byte instead of 3-byte packets. >>> - */ >>> -static int byd_send_intellimouse_sequence(struct psmouse *psmouse) >>> +static int byd_reset_touchpad(struct psmouse *psmouse) >>> { >>> struct ps2dev *ps2dev = &psmouse->ps2dev; >>> u8 param[4]; >>> - int i; >>> + size_t i; >>> + >>> const struct { >>> u16 command; >>> u8 arg; >>> } seq[] = { >>> - { PSMOUSE_CMD_RESET_BAT, 0 }, >>> - { PSMOUSE_CMD_RESET_BAT, 0 }, >>> - { PSMOUSE_CMD_GETID, 0 }, >>> - { PSMOUSE_CMD_SETSCALE11, 0 }, >>> - { PSMOUSE_CMD_SETSCALE11, 0 }, >>> - { PSMOUSE_CMD_SETSCALE11, 0 }, >>> - { PSMOUSE_CMD_GETINFO, 0 }, >>> - { PSMOUSE_CMD_SETRES, 0x03 }, >>> + /* >>> + * Intellimouse initialization sequence, to get 4-byte >>> instead >>> + * of 3-byte packets. >>> + */ >>> { PSMOUSE_CMD_SETRATE, 0xC8 }, >>> { PSMOUSE_CMD_SETRATE, 0x64 }, >>> { PSMOUSE_CMD_SETRATE, 0x50 }, >>> { PSMOUSE_CMD_GETID, 0 }, >>> - { PSMOUSE_CMD_SETRATE, 0xC8 }, >>> - { PSMOUSE_CMD_SETRATE, 0xC8 }, >>> - { PSMOUSE_CMD_SETRATE, 0x50 }, >>> - { PSMOUSE_CMD_GETID, 0 }, >>> - { PSMOUSE_CMD_SETRATE, 0x64 }, >>> - { PSMOUSE_CMD_SETRES, 0x03 }, >>> - { PSMOUSE_CMD_ENABLE, 0 } >>> + { PSMOUSE_CMD_ENABLE, 0 }, >>> + /* >>> + * BYD-specific initialization, which enables absolute >>> mode and >>> + * (if desired), the touchpad's built-in gesture >>> detection. >>> + */ >>> + { 0x10E2, 0x00 }, >>> + { 0x10E0, 0x02 }, >>> + /* The touchpad should reply with 4 seemingly-random >>> bytes */ >>> + { 0x14E0, 0x01 }, >>> + /* Pairs of parameters and values. */ >>> + { BYD_CMD_SET_HANDEDNESS, 0x01 }, >>> + { BYD_CMD_SET_PHYSICAL_BUTTONS, 0x04 }, >>> + { BYD_CMD_SET_TAP, 0x02 }, >>> + { BYD_CMD_SET_ONE_FINGER_SCROLL, 0x04 }, >>> + { BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC, 0x04 }, >>> + { BYD_CMD_SET_EDGE_MOTION, 0x01 }, >>> + { BYD_CMD_SET_PALM_CHECK, 0x00 }, >>> + { BYD_CMD_SET_MULTITOUCH, 0x02 }, >>> + { BYD_CMD_SET_TWO_FINGER_SCROLL, 0x04 }, >>> + { BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC, 0x04 }, >>> + { BYD_CMD_SET_LEFT_EDGE_REGION, 0x00 }, >>> + { BYD_CMD_SET_TOP_EDGE_REGION, 0x00 }, >>> + { BYD_CMD_SET_RIGHT_EDGE_REGION, 0x00 }, >>> + { BYD_CMD_SET_BOTTOM_EDGE_REGION, 0x00 }, >>> + { BYD_CMD_SET_ABSOLUTE_MODE, 0x02 }, >>> + /* Finalize initialization. */ >>> + { 0x10E0, 0x00 }, >>> + { 0x10E2, 0x01 }, >>> }; >>> >>> - memset(param, 0, sizeof(param)); >>> for (i = 0; i < ARRAY_SIZE(seq); ++i) { >>> + memset(param, 0, sizeof(param)); >>> param[0] = seq[i].arg; >>> if (ps2_command(ps2dev, param, seq[i].command)) >>> - return -1; >>> + return -EIO; >>> } >>> >>> - return 0; >>> -} >>> - >>> -static int byd_reset_touchpad(struct psmouse *psmouse) >>> -{ >>> - if (byd_send_intellimouse_sequence(psmouse)) >>> - return -EIO; >>> - >>> - if (byd_enable(psmouse)) >>> - return -EIO; >>> - >>> + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); >>> return 0; >>> } >>> >>> @@ -314,9 +419,50 @@ static int byd_reconnect(struct psmouse *psmouse) >>> return 0; >>> } >>> >>> +static void byd_disconnect(struct psmouse *psmouse) >>> +{ >>> + struct byd_data *priv = psmouse->private; >>> + >>> + if (priv) { >>> + del_timer(&priv->timer); >>> + kfree(psmouse->private); >>> + psmouse->private = NULL; >>> + } >>> +} >>> + >>> +int byd_detect(struct psmouse *psmouse, bool set_properties) >>> +{ >>> + struct ps2dev *ps2dev = &psmouse->ps2dev; >>> + u8 param[4] = {0x03, 0x00, 0x00, 0x00}; >>> + >>> + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) >>> + return -1; >>> + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) >>> + return -1; >>> + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) >>> + return -1; >>> + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) >>> + return -1; >>> + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) >>> + return -1; >>> + >>> + if (param[1] != 0x03 || param[2] != 0x64) >>> + return -ENODEV; >>> + >>> + psmouse_dbg(psmouse, "BYD touchpad detected\n"); >>> + >>> + if (set_properties) { >>> + psmouse->vendor = "BYD"; >>> + psmouse->name = "TouchPad"; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> int byd_init(struct psmouse *psmouse) >>> { >>> struct input_dev *dev = psmouse->dev; >>> + struct byd_data *priv; >>> >>> if (psmouse_reset(psmouse)) >>> return -EIO; >>> @@ -324,14 +470,39 @@ int byd_init(struct psmouse *psmouse) >>> if (byd_reset_touchpad(psmouse)) >>> return -EIO; >>> >>> + priv = kzalloc(sizeof(*priv), GFP_KERNEL); >>> + if (!priv) >>> + return -ENOMEM; >>> + >>> + memset(priv, 0, sizeof(*priv)); >>> + setup_timer(&priv->timer, byd_clear_touch, (unsigned long) >>> psmouse); >>> + >>> + psmouse->private = priv; >>> + psmouse->disconnect = byd_disconnect; >>> psmouse->reconnect = byd_reconnect; >>> psmouse->protocol_handler = byd_process_byte; >>> psmouse->pktsize = 4; >>> psmouse->resync_time = 0; >>> >>> - __set_bit(BTN_MIDDLE, dev->keybit); >>> - __set_bit(REL_WHEEL, dev->relbit); >>> - __set_bit(REL_HWHEEL, dev->relbit); >>> + __set_bit(INPUT_PROP_POINTER, dev->propbit); >>> + /* Touchpad */ >>> + __set_bit(BTN_TOUCH, dev->keybit); >>> + __set_bit(BTN_TOOL_FINGER, dev->keybit); >>> + /* Buttons */ >>> + __set_bit(BTN_LEFT, dev->keybit); >>> + __set_bit(BTN_RIGHT, dev->keybit); >>> + __clear_bit(BTN_MIDDLE, dev->keybit); >>> + >>> + /* Absolute position */ >>> + __set_bit(EV_ABS, dev->evbit); >>> + input_set_abs_params(dev, ABS_X, 0, BYD_PAD_WIDTH, 0, 0); >>> + input_set_abs_params(dev, ABS_Y, 0, BYD_PAD_HEIGHT, 0, 0); >>> + input_abs_set_res(dev, ABS_X, BYD_PAD_RESOLUTION); >>> + input_abs_set_res(dev, ABS_Y, BYD_PAD_RESOLUTION); >>> + /* No relative support */ >>> + __clear_bit(EV_REL, dev->evbit); >>> + __clear_bit(REL_X, dev->relbit); >>> + __clear_bit(REL_Y, dev->relbit); >>> >>> return 0; >>> } >>> diff --git a/drivers/input/mouse/psmouse-base.c >>> b/drivers/input/mouse/psmouse-base.c >>> index 39d1bec..5784e20 100644 >>> --- a/drivers/input/mouse/psmouse-base.c >>> +++ b/drivers/input/mouse/psmouse-base.c >>> @@ -846,7 +846,7 @@ static const struct psmouse_protocol >>> psmouse_protocols[] = { >>> #ifdef CONFIG_MOUSE_PS2_BYD >>> { >>> .type = PSMOUSE_BYD, >>> - .name = "BydPS/2", >>> + .name = "BYDPS/2", >>> .alias = "byd", >>> .detect = byd_detect, >>> .init = byd_init, >>> >
On Fri, Mar 25, 2016 at 4:39 PM, Dmitry Torokhov <dmitry.torokhov@gmail.com> wrote: > On Fri, Mar 25, 2016 at 3:43 PM, Richard Pospesel <pospeselr@gmail.com> wrote: >> Pinging you on this. > > Sorry for not responding earlier. It is included in my 2nd pull > request for 4.6-rc1. ... and it has been merged into mainline. Thanks.
> ... and it has been merged into mainline.
Thanks both!
Chris
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c index 9425e0f..fdc243c 100644 --- a/drivers/input/mouse/byd.c +++ b/drivers/input/mouse/byd.c @@ -12,10 +12,12 @@ #include <linux/input.h> #include <linux/libps2.h> #include <linux/serio.h> +#include <linux/slab.h> #include "psmouse.h" #include "byd.h" +/* PS2 Bits */ #define PS2_Y_OVERFLOW BIT_MASK(7) #define PS2_X_OVERFLOW BIT_MASK(6) #define PS2_Y_SIGN BIT_MASK(5) @@ -26,69 +28,249 @@ #define PS2_LEFT BIT_MASK(0) /* - * The touchpad reports gestures in the last byte of each packet. It can take - * any of the following values: + * BYD pad constants */ -/* One-finger scrolling in one of the edge scroll zones. */ -#define BYD_SCROLLUP 0xCA -#define BYD_SCROLLDOWN 0x36 -#define BYD_SCROLLLEFT 0xCB -#define BYD_SCROLLRIGHT 0x35 -/* Two-finger scrolling. */ -#define BYD_2DOWN 0x2B -#define BYD_2UP 0xD5 -#define BYD_2LEFT 0xD6 -#define BYD_2RIGHT 0x2A -/* Pinching in or out. */ -#define BYD_ZOOMOUT 0xD8 -#define BYD_ZOOMIN 0x28 -/* Three-finger swipe. */ -#define BYD_3UP 0xD3 -#define BYD_3DOWN 0x2D -#define BYD_3LEFT 0xD4 -#define BYD_3RIGHT 0x2C -/* Four-finger swipe. */ -#define BYD_4UP 0xCD -#define BYD_4DOWN 0x33 +/* + * True device resolution is unknown, however experiments show the + * resolution is about 111 units/mm. + * Absolute coordinate packets are in the range 0-255 for both X and Y + * we pick ABS_X/ABS_Y dimensions which are multiples of 256 and in + * the right ballpark given the touchpad's physical dimensions and estimate + * resolution per spec sheet, device active area dimensions are + * 101.6 x 60.1 mm. + */ +#define BYD_PAD_WIDTH 11264 +#define BYD_PAD_HEIGHT 6656 +#define BYD_PAD_RESOLUTION 111 -int byd_detect(struct psmouse *psmouse, bool set_properties) +/* + * Given the above dimensions, relative packets velocity is in multiples of + * 1 unit / 11 milliseconds. We use this dt to estimate distance traveled + */ +#define BYD_DT 11 +/* Time in jiffies used to timeout various touch events (64 ms) */ +#define BYD_TOUCH_TIMEOUT msecs_to_jiffies(64) + +/* BYD commands reverse engineered from windows driver */ + +/* + * Swipe gesture from off-pad to on-pad + * 0 : disable + * 1 : enable + */ +#define BYD_CMD_SET_OFFSCREEN_SWIPE 0x10cc +/* + * Tap and drag delay time + * 0 : disable + * 1 - 8 : least to most delay + */ +#define BYD_CMD_SET_TAP_DRAG_DELAY_TIME 0x10cf +/* + * Physical buttons function mapping + * 0 : enable + * 4 : normal + * 5 : left button custom command + * 6 : right button custom command + * 8 : disable + */ +#define BYD_CMD_SET_PHYSICAL_BUTTONS 0x10d0 +/* + * Absolute mode (1 byte X/Y resolution) + * 0 : disable + * 2 : enable + */ +#define BYD_CMD_SET_ABSOLUTE_MODE 0x10d1 +/* + * Two finger scrolling + * 1 : vertical + * 2 : horizontal + * 3 : vertical + horizontal + * 4 : disable + */ +#define BYD_CMD_SET_TWO_FINGER_SCROLL 0x10d2 +/* + * Handedness + * 1 : right handed + * 2 : left handed + */ +#define BYD_CMD_SET_HANDEDNESS 0x10d3 +/* + * Tap to click + * 1 : enable + * 2 : disable + */ +#define BYD_CMD_SET_TAP 0x10d4 +/* + * Tap and drag + * 1 : tap and hold to drag + * 2 : tap and hold to drag + lock + * 3 : disable + */ +#define BYD_CMD_SET_TAP_DRAG 0x10d5 +/* + * Touch sensitivity + * 1 - 7 : least to most sensitive + */ +#define BYD_CMD_SET_TOUCH_SENSITIVITY 0x10d6 +/* + * One finger scrolling + * 1 : vertical + * 2 : horizontal + * 3 : vertical + horizontal + * 4 : disable + */ +#define BYD_CMD_SET_ONE_FINGER_SCROLL 0x10d7 +/* + * One finger scrolling function + * 1 : free scrolling + * 2 : edge motion + * 3 : free scrolling + edge motion + * 4 : disable + */ +#define BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC 0x10d8 +/* + * Sliding speed + * 1 - 5 : slowest to fastest + */ +#define BYD_CMD_SET_SLIDING_SPEED 0x10da +/* + * Edge motion + * 1 : disable + * 2 : enable when dragging + * 3 : enable when dragging and pointing + */ +#define BYD_CMD_SET_EDGE_MOTION 0x10db +/* + * Left edge region size + * 0 - 7 : smallest to largest width + */ +#define BYD_CMD_SET_LEFT_EDGE_REGION 0x10dc +/* + * Top edge region size + * 0 - 9 : smallest to largest height + */ +#define BYD_CMD_SET_TOP_EDGE_REGION 0x10dd +/* + * Disregard palm press as clicks + * 1 - 6 : smallest to largest + */ +#define BYD_CMD_SET_PALM_CHECK 0x10de +/* + * Right edge region size + * 0 - 7 : smallest to largest width + */ +#define BYD_CMD_SET_RIGHT_EDGE_REGION 0x10df +/* + * Bottom edge region size + * 0 - 9 : smallest to largest height + */ +#define BYD_CMD_SET_BOTTOM_EDGE_REGION 0x10e1 +/* + * Multitouch gestures + * 1 : enable + * 2 : disable + */ +#define BYD_CMD_SET_MULTITOUCH 0x10e3 +/* + * Edge motion speed + * 0 : control with finger pressure + * 1 - 9 : slowest to fastest + */ +#define BYD_CMD_SET_EDGE_MOTION_SPEED 0x10e4 +/* + * Two finger scolling function + * 0 : free scrolling + * 1 : free scrolling (with momentum) + * 2 : edge motion + * 3 : free scrolling (with momentum) + edge motion + * 4 : disable + */ +#define BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC 0x10e5 + +/* + * The touchpad generates a mixture of absolute and relative packets, indicated + * by the the last byte of each packet being set to one of the following: + */ +#define BYD_PACKET_ABSOLUTE 0xf8 +#define BYD_PACKET_RELATIVE 0x00 +/* Multitouch gesture packets */ +#define BYD_PACKET_PINCH_IN 0xd8 +#define BYD_PACKET_PINCH_OUT 0x28 +#define BYD_PACKET_ROTATE_CLOCKWISE 0x29 +#define BYD_PACKET_ROTATE_ANTICLOCKWISE 0xd7 +#define BYD_PACKET_TWO_FINGER_SCROLL_RIGHT 0x2a +#define BYD_PACKET_TWO_FINGER_SCROLL_DOWN 0x2b +#define BYD_PACKET_TWO_FINGER_SCROLL_UP 0xd5 +#define BYD_PACKET_TWO_FINGER_SCROLL_LEFT 0xd6 +#define BYD_PACKET_THREE_FINGER_SWIPE_RIGHT 0x2c +#define BYD_PACKET_THREE_FINGER_SWIPE_DOWN 0x2d +#define BYD_PACKET_THREE_FINGER_SWIPE_UP 0xd3 +#define BYD_PACKET_THREE_FINGER_SWIPE_LEFT 0xd4 +#define BYD_PACKET_FOUR_FINGER_DOWN 0x33 +#define BYD_PACKET_FOUR_FINGER_UP 0xcd +#define BYD_PACKET_REGION_SCROLL_RIGHT 0x35 +#define BYD_PACKET_REGION_SCROLL_DOWN 0x36 +#define BYD_PACKET_REGION_SCROLL_UP 0xca +#define BYD_PACKET_REGION_SCROLL_LEFT 0xcb +#define BYD_PACKET_RIGHT_CORNER_CLICK 0xd2 +#define BYD_PACKET_LEFT_CORNER_CLICK 0x2e +#define BYD_PACKET_LEFT_AND_RIGHT_CORNER_CLICK 0x2f +#define BYD_PACKET_ONTO_PAD_SWIPE_RIGHT 0x37 +#define BYD_PACKET_ONTO_PAD_SWIPE_DOWN 0x30 +#define BYD_PACKET_ONTO_PAD_SWIPE_UP 0xd0 +#define BYD_PACKET_ONTO_PAD_SWIPE_LEFT 0xc9 + +struct byd_data { + struct timer_list timer; + s32 abs_x; + s32 abs_y; + typeof(jiffies) last_touch_time; + bool btn_left; + bool btn_right; + bool touch; +}; + +static void byd_report_input(struct psmouse *psmouse) { - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; + struct byd_data *priv = psmouse->private; + struct input_dev *dev = psmouse->dev; - param[0] = 0x03; - param[1] = 0x00; - param[2] = 0x00; - param[3] = 0x00; + input_report_key(dev, BTN_TOUCH, priv->touch); + input_report_key(dev, BTN_TOOL_FINGER, priv->touch); - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -1; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -1; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -1; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -1; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -1; + input_report_abs(dev, ABS_X, priv->abs_x); + input_report_abs(dev, ABS_Y, priv->abs_y); + input_report_key(dev, BTN_LEFT, priv->btn_left); + input_report_key(dev, BTN_RIGHT, priv->btn_right); - if (param[1] != 0x03 || param[2] != 0x64) - return -ENODEV; + input_sync(dev); +} - psmouse_dbg(psmouse, "BYD touchpad detected\n"); +static void byd_clear_touch(unsigned long data) +{ + struct psmouse *psmouse = (struct psmouse *)data; + struct byd_data *priv = psmouse->private; - if (set_properties) { - psmouse->vendor = "BYD"; - psmouse->name = "TouchPad"; - } + serio_pause_rx(psmouse->ps2dev.serio); + priv->touch = false; - return 0; + byd_report_input(psmouse); + + serio_continue_rx(psmouse->ps2dev.serio); + + /* + * Move cursor back to center of pad when we lose touch - this + * specifically improves user experience when moving cursor with one + * finger, and pressing a button with another. + */ + priv->abs_x = BYD_PAD_WIDTH / 2; + priv->abs_y = BYD_PAD_HEIGHT / 2; } static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) { - struct input_dev *dev = psmouse->dev; + struct byd_data *priv = psmouse->private; u8 *pkt = psmouse->packet; if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) { @@ -102,53 +284,34 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) /* Otherwise, a full packet has been received */ switch (pkt[3]) { - case 0: { + case BYD_PACKET_ABSOLUTE: + /* Only use absolute packets for the start of movement. */ + if (!priv->touch) { + /* needed to detect tap */ + typeof(jiffies) tap_time = + priv->last_touch_time + BYD_TOUCH_TIMEOUT; + priv->touch = time_after(jiffies, tap_time); + + /* init abs position */ + priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256); + priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / 256); + } + break; + case BYD_PACKET_RELATIVE: { /* Standard packet */ /* Sign-extend if a sign bit is set. */ - unsigned int signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; - unsigned int signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; - int dx = signx | (int) pkt[1]; - int dy = signy | (int) pkt[2]; + u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; + u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; + s32 dx = signx | (int) pkt[1]; + s32 dy = signy | (int) pkt[2]; - input_report_rel(psmouse->dev, REL_X, dx); - input_report_rel(psmouse->dev, REL_Y, -dy); + /* Update position based on velocity */ + priv->abs_x += dx * BYD_DT; + priv->abs_y -= dy * BYD_DT; - input_report_key(psmouse->dev, BTN_LEFT, pkt[0] & PS2_LEFT); - input_report_key(psmouse->dev, BTN_RIGHT, pkt[0] & PS2_RIGHT); - input_report_key(psmouse->dev, BTN_MIDDLE, pkt[0] & PS2_MIDDLE); + priv->touch = true; break; } - - case BYD_SCROLLDOWN: - case BYD_2DOWN: - input_report_rel(dev, REL_WHEEL, -1); - break; - - case BYD_SCROLLUP: - case BYD_2UP: - input_report_rel(dev, REL_WHEEL, 1); - break; - - case BYD_SCROLLLEFT: - case BYD_2LEFT: - input_report_rel(dev, REL_HWHEEL, -1); - break; - - case BYD_SCROLLRIGHT: - case BYD_2RIGHT: - input_report_rel(dev, REL_HWHEEL, 1); - break; - - case BYD_ZOOMOUT: - case BYD_ZOOMIN: - case BYD_3UP: - case BYD_3DOWN: - case BYD_3LEFT: - case BYD_3RIGHT: - case BYD_4UP: - case BYD_4DOWN: - break; - default: psmouse_warn(psmouse, "Unrecognized Z: pkt = %02x %02x %02x %02x\n", @@ -157,134 +320,76 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) return PSMOUSE_BAD_DATA; } - input_sync(dev); + priv->btn_left = pkt[0] & PS2_LEFT; + priv->btn_right = pkt[0] & PS2_RIGHT; - return PSMOUSE_FULL_PACKET; -} + byd_report_input(psmouse); -/* Send a sequence of bytes, where each is ACKed before the next is sent. */ -static int byd_send_sequence(struct psmouse *psmouse, const u8 *seq, size_t len) -{ - unsigned int i; - - for (i = 0; i < len; ++i) { - if (ps2_command(&psmouse->ps2dev, NULL, seq[i])) - return -1; + /* Reset time since last touch. */ + if (priv->touch) { + priv->last_touch_time = jiffies; + mod_timer(&priv->timer, jiffies + BYD_TOUCH_TIMEOUT); } - return 0; -} - -/* Keep scrolling after fingers are removed. */ -#define SCROLL_INERTIAL 0x01 -#define SCROLL_NO_INERTIAL 0x02 - -/* Clicking can be done by tapping or pressing. */ -#define CLICK_BOTH 0x01 -/* Clicking can only be done by pressing. */ -#define CLICK_PRESS_ONLY 0x02 -static int byd_enable(struct psmouse *psmouse) -{ - const u8 seq1[] = { 0xE2, 0x00, 0xE0, 0x02, 0xE0 }; - const u8 seq2[] = { - 0xD3, 0x01, - 0xD0, 0x00, - 0xD0, 0x04, - /* Whether clicking is done by tapping or pressing. */ - 0xD4, CLICK_PRESS_ONLY, - 0xD5, 0x01, - 0xD7, 0x03, - /* Vertical and horizontal one-finger scroll zone inertia. */ - 0xD8, SCROLL_INERTIAL, - 0xDA, 0x05, - 0xDB, 0x02, - 0xE4, 0x05, - 0xD6, 0x01, - 0xDE, 0x04, - 0xE3, 0x01, - 0xCF, 0x00, - 0xD2, 0x03, - /* Vertical and horizontal two-finger scrolling inertia. */ - 0xE5, SCROLL_INERTIAL, - 0xD9, 0x02, - 0xD9, 0x07, - 0xDC, 0x03, - 0xDD, 0x03, - 0xDF, 0x03, - 0xE1, 0x03, - 0xD1, 0x00, - 0xCE, 0x00, - 0xCC, 0x00, - 0xE0, 0x00, - 0xE2, 0x01 - }; - u8 param[4]; - - if (byd_send_sequence(psmouse, seq1, ARRAY_SIZE(seq1))) - return -1; - - /* Send a 0x01 command, which should return 4 bytes. */ - if (ps2_command(&psmouse->ps2dev, param, 0x0401)) - return -1; - - if (byd_send_sequence(psmouse, seq2, ARRAY_SIZE(seq2))) - return -1; - - return 0; + return PSMOUSE_FULL_PACKET; } -/* - * Send the set of PS/2 commands required to make it identify as an - * intellimouse with 4-byte instead of 3-byte packets. - */ -static int byd_send_intellimouse_sequence(struct psmouse *psmouse) +static int byd_reset_touchpad(struct psmouse *psmouse) { struct ps2dev *ps2dev = &psmouse->ps2dev; u8 param[4]; - int i; + size_t i; + const struct { u16 command; u8 arg; } seq[] = { - { PSMOUSE_CMD_RESET_BAT, 0 }, - { PSMOUSE_CMD_RESET_BAT, 0 }, - { PSMOUSE_CMD_GETID, 0 }, - { PSMOUSE_CMD_SETSCALE11, 0 }, - { PSMOUSE_CMD_SETSCALE11, 0 }, - { PSMOUSE_CMD_SETSCALE11, 0 }, - { PSMOUSE_CMD_GETINFO, 0 }, - { PSMOUSE_CMD_SETRES, 0x03 }, + /* + * Intellimouse initialization sequence, to get 4-byte instead + * of 3-byte packets. + */ { PSMOUSE_CMD_SETRATE, 0xC8 }, { PSMOUSE_CMD_SETRATE, 0x64 }, { PSMOUSE_CMD_SETRATE, 0x50 }, { PSMOUSE_CMD_GETID, 0 }, - { PSMOUSE_CMD_SETRATE, 0xC8 }, - { PSMOUSE_CMD_SETRATE, 0xC8 }, - { PSMOUSE_CMD_SETRATE, 0x50 }, - { PSMOUSE_CMD_GETID, 0 }, - { PSMOUSE_CMD_SETRATE, 0x64 }, - { PSMOUSE_CMD_SETRES, 0x03 }, - { PSMOUSE_CMD_ENABLE, 0 } + { PSMOUSE_CMD_ENABLE, 0 }, + /* + * BYD-specific initialization, which enables absolute mode and + * (if desired), the touchpad's built-in gesture detection. + */ + { 0x10E2, 0x00 }, + { 0x10E0, 0x02 }, + /* The touchpad should reply with 4 seemingly-random bytes */ + { 0x14E0, 0x01 }, + /* Pairs of parameters and values. */ + { BYD_CMD_SET_HANDEDNESS, 0x01 }, + { BYD_CMD_SET_PHYSICAL_BUTTONS, 0x04 }, + { BYD_CMD_SET_TAP, 0x02 }, + { BYD_CMD_SET_ONE_FINGER_SCROLL, 0x04 }, + { BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC, 0x04 }, + { BYD_CMD_SET_EDGE_MOTION, 0x01 }, + { BYD_CMD_SET_PALM_CHECK, 0x00 }, + { BYD_CMD_SET_MULTITOUCH, 0x02 }, + { BYD_CMD_SET_TWO_FINGER_SCROLL, 0x04 }, + { BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC, 0x04 }, + { BYD_CMD_SET_LEFT_EDGE_REGION, 0x00 }, + { BYD_CMD_SET_TOP_EDGE_REGION, 0x00 }, + { BYD_CMD_SET_RIGHT_EDGE_REGION, 0x00 }, + { BYD_CMD_SET_BOTTOM_EDGE_REGION, 0x00 }, + { BYD_CMD_SET_ABSOLUTE_MODE, 0x02 }, + /* Finalize initialization. */ + { 0x10E0, 0x00 }, + { 0x10E2, 0x01 }, }; - memset(param, 0, sizeof(param)); for (i = 0; i < ARRAY_SIZE(seq); ++i) { + memset(param, 0, sizeof(param)); param[0] = seq[i].arg; if (ps2_command(ps2dev, param, seq[i].command)) - return -1; + return -EIO; } - return 0; -} - -static int byd_reset_touchpad(struct psmouse *psmouse) -{ - if (byd_send_intellimouse_sequence(psmouse)) - return -EIO; - - if (byd_enable(psmouse)) - return -EIO; - + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); return 0; } @@ -314,9 +419,50 @@ static int byd_reconnect(struct psmouse *psmouse) return 0; } +static void byd_disconnect(struct psmouse *psmouse) +{ + struct byd_data *priv = psmouse->private; + + if (priv) { + del_timer(&priv->timer); + kfree(psmouse->private); + psmouse->private = NULL; + } +} + +int byd_detect(struct psmouse *psmouse, bool set_properties) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + u8 param[4] = {0x03, 0x00, 0x00, 0x00}; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -1; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -1; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -1; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -1; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) + return -1; + + if (param[1] != 0x03 || param[2] != 0x64) + return -ENODEV; + + psmouse_dbg(psmouse, "BYD touchpad detected\n"); + + if (set_properties) { + psmouse->vendor = "BYD"; + psmouse->name = "TouchPad"; + } + + return 0; +} + int byd_init(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; + struct byd_data *priv; if (psmouse_reset(psmouse)) return -EIO; @@ -324,14 +470,39 @@ int byd_init(struct psmouse *psmouse) if (byd_reset_touchpad(psmouse)) return -EIO; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + memset(priv, 0, sizeof(*priv)); + setup_timer(&priv->timer, byd_clear_touch, (unsigned long) psmouse); + + psmouse->private = priv; + psmouse->disconnect = byd_disconnect; psmouse->reconnect = byd_reconnect; psmouse->protocol_handler = byd_process_byte; psmouse->pktsize = 4; psmouse->resync_time = 0; - __set_bit(BTN_MIDDLE, dev->keybit); - __set_bit(REL_WHEEL, dev->relbit); - __set_bit(REL_HWHEEL, dev->relbit); + __set_bit(INPUT_PROP_POINTER, dev->propbit); + /* Touchpad */ + __set_bit(BTN_TOUCH, dev->keybit); + __set_bit(BTN_TOOL_FINGER, dev->keybit); + /* Buttons */ + __set_bit(BTN_LEFT, dev->keybit); + __set_bit(BTN_RIGHT, dev->keybit); + __clear_bit(BTN_MIDDLE, dev->keybit); + + /* Absolute position */ + __set_bit(EV_ABS, dev->evbit); + input_set_abs_params(dev, ABS_X, 0, BYD_PAD_WIDTH, 0, 0); + input_set_abs_params(dev, ABS_Y, 0, BYD_PAD_HEIGHT, 0, 0); + input_abs_set_res(dev, ABS_X, BYD_PAD_RESOLUTION); + input_abs_set_res(dev, ABS_Y, BYD_PAD_RESOLUTION); + /* No relative support */ + __clear_bit(EV_REL, dev->evbit); + __clear_bit(REL_X, dev->relbit); + __clear_bit(REL_Y, dev->relbit); return 0; } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 39d1bec..5784e20 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -846,7 +846,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { #ifdef CONFIG_MOUSE_PS2_BYD { .type = PSMOUSE_BYD, - .name = "BydPS/2", + .name = "BYDPS/2", .alias = "byd", .detect = byd_detect, .init = byd_init,