Dmitry, Any questions about this patch? I hope it can get in 2.6.39. Thank you. Ping On Fri, Jan 7, 2011 at 10:54 AM, Ping Cheng <pinglinux@xxxxxxxxx> wrote: > Emulate single-touch compatible events for the 2-finger panels > so that they can be used with single-touch legacy clients. > > Assign device ids as Wacom USB vendor ID and product ID. > Name the device to reflect its specific features. > > Scale touch cordinates to pen maximum if supported. > > Signed-off-by: Ping Cheng <pingc@xxxxxxxxx> > > --- > Dmitry, > > I can not find the sourceforge inputattach project you mentioned. > The options to attach Wacom serial devices can be add to the > static struct input_types input_types[] in inputattach.c as the > following: > > { "--wacom",      Â"-wacom",    "Wacom W8001-19200", >    ÂB19200, CS8, >    ÂSERIO_W8001,      Â0x00,  0x00,  0,   ÂNULL }, > { "--wacom-384",        Â"-wacom-384",  "Wacom W8001-38400", >    ÂB38400, CS8, >    ÂSERIO_W8001,      Â0x00,  0x00,  0,   ÂNULL }, > --- > Âdrivers/input/touchscreen/wacom_w8001.c | Â165 ++++++++++++++++++++++++++----- > Â1 files changed, 139 insertions(+), 26 deletions(-) > > diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c > index 8ed53ad..144c4f3 100644 > --- a/drivers/input/touchscreen/wacom_w8001.c > +++ b/drivers/input/touchscreen/wacom_w8001.c > @@ -3,6 +3,7 @@ > Â* > Â* Copyright (c) 2008 Jaya Kumar > Â* Copyright (c) 2010 Red Hat, Inc. > + * Copyright (c) 2010 - 2011 Ping Cheng, Wacom. <pingc@xxxxxxxxx> > Â* > Â* This file is subject to the terms and conditions of the GNU General Public > Â* License. See the file COPYING in the main directory of this archive for > @@ -64,11 +65,11 @@ struct w8001_coord { > > Â/* touch query reply packet */ > Âstruct w8001_touch_query { > +    u16 x; > +    u16 y; >    Âu8 panel_res; >    Âu8 capacity_res; >    Âu8 sensor_id; > -    u16 x; > -    u16 y; > Â}; > > Â/* > @@ -87,9 +88,14 @@ struct w8001 { >    Âchar phys[32]; >    Âint type; >    Âunsigned int pktlen; > +    u16 max_touch_x; > +    u16 max_touch_y; > +    u16 max_pen_x; > +    u16 max_pen_y; > +    char name[64]; > Â}; > > -static void parse_data(u8 *data, struct w8001_coord *coord) > +static void parse_pen_data(u8 *data, struct w8001_coord *coord) > Â{ >    Âmemset(coord, 0, sizeof(*coord)); > > @@ -113,11 +119,19 @@ static void parse_data(u8 *data, struct w8001_coord *coord) >    Âcoord->tilt_y = data[8] & 0x7F; > Â} > > -static void parse_touch(struct w8001 *w8001) > +static void parse_single_touch(u8 *data, struct w8001_coord *coord) > +{ > +    coord->x = (data[1] << 7) | data[2]; > +    coord->y = (data[3] << 7) | data[4]; > +    coord->tsw = data[0] & 0x01; > +} > + > +static void parse_multi_touch(struct w8001 *w8001) > Â{ >    Âstruct input_dev *dev = w8001->dev; >    Âunsigned char *data = w8001->data; >    Âint i; > +    int count = 0; > >    Âfor (i = 0; i < 2; i++) { >        Âbool touch = data[0] & (1 << i); > @@ -125,15 +139,33 @@ static void parse_touch(struct w8001 *w8001) >        Âinput_mt_slot(dev, i); >        Âinput_mt_report_slot_state(dev, MT_TOOL_FINGER, touch); >        Âif (touch) { > -            int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]); > -            int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]); > +            int x = (data[6 * i + 1] << 7) | data[6 * i + 2]; > +            int y = (data[6 * i + 3] << 7) | data[6 * i + 4]; >            Â/* data[5,6] and [11,12] is finger capacity */ > > +            /* scale to pen maximum */ > +            if (w8001->max_pen_x && w8001->max_touch_x) > +                x = x * w8001->max_pen_x / w8001->max_touch_x; > + > +            if (w8001->max_pen_y && w8001->max_touch_y) > +                y = y * w8001->max_pen_y / w8001->max_touch_y; > + >            Âinput_report_abs(dev, ABS_MT_POSITION_X, x); >            Âinput_report_abs(dev, ABS_MT_POSITION_Y, y); > +            count++; >        Â} >    Â} > > +    /* emulate single touch events when stylus is out of proximity. > +    Â* This is to make single touch backward support consistent > +    Â* across all Wacom single touch devices. > +    Â*/ > +    if (w8001->type != BTN_TOOL_PEN && > +              w8001->type != BTN_TOOL_RUBBER) { > +        w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED; > +        input_mt_report_pointer_emulation(dev, true); > +    } > + >    Âinput_sync(dev); > Â} > > @@ -152,6 +184,15 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query) >    Âquery->y = data[5] << 9; >    Âquery->y |= data[6] << 2; >    Âquery->y |= (data[2] >> 3) & 0x3; > + > +    /* Early days' single-finger touch models need the following defaults */ > +    if (!query->x && !query->y) { > +        query->x = 1024; > +        query->y = 1024; > +        if (query->panel_res) > +            query->x = query->y = (1 << query->panel_res); > +        query->panel_res = 10; > +    } > Â} > > Âstatic void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) > @@ -161,16 +202,15 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) >    Â/* >     * We have 1 bit for proximity (rdy) and 3 bits for tip, side, >     * side2/eraser. If rdy && f2 are set, this can be either pen + side2, > -    Â* or eraser. assume > +    Â* or eraser. Assume: >     * - if dev is already in proximity and f2 is toggled â pen + side2 >     * - if dev comes into proximity with f2 set â eraser >     * If f2 disappears after assuming eraser, fake proximity out for >     * eraser and in for pen. >     */ > > -    if (!w8001->type) { > -        w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; > -    } else if (w8001->type == BTN_TOOL_RUBBER) { > +    switch (w8001->type) { > +    case BTN_TOOL_RUBBER: >        Âif (!coord->f2) { >            Âinput_report_abs(dev, ABS_PRESSURE, 0); >            Âinput_report_key(dev, BTN_TOUCH, 0); > @@ -180,8 +220,21 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) >            Âinput_sync(dev); >            Âw8001->type = BTN_TOOL_PEN; >        Â} > -    } else { > +        break; > + > +    case BTN_TOOL_FINGER: > +        input_report_key(dev, BTN_TOUCH, 0); > +        input_report_key(dev, BTN_TOOL_FINGER, 0); > +        input_sync(dev); > +        /* fall through */ > + > +    case KEY_RESERVED: > +        w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; > +        break; > + > +    default: >        Âinput_report_key(dev, BTN_STYLUS2, coord->f2); > +        break; >    Â} > >    Âinput_report_abs(dev, ABS_X, coord->x); > @@ -193,7 +246,30 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) >    Âinput_sync(dev); > >    Âif (!coord->rdy) > -        w8001->type = 0; > +        w8001->type = KEY_RESERVED; > +} > + > +static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord) > +{ > +    struct input_dev *dev = w8001->dev; > +    unsigned int x = coord->x; > +    unsigned int y = coord->y; > + > +    /* scale to pen maximum */ > +    if (w8001->max_pen_x && w8001->max_touch_x) > +        x = x * w8001->max_pen_x / w8001->max_touch_x; > + > +    if (w8001->max_pen_y && w8001->max_touch_y) > +        y = y * w8001->max_pen_y / w8001->max_touch_y; > + > +    input_report_abs(dev, ABS_X, x); > +    input_report_abs(dev, ABS_Y, y); > +    input_report_key(dev, BTN_TOUCH, coord->tsw); > +    input_report_key(dev, BTN_TOOL_FINGER, coord->tsw); > + > +    input_sync(dev); > + > +    w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED; > Â} > > Âstatic irqreturn_t w8001_interrupt(struct serio *serio, > @@ -214,9 +290,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio, > >    Âcase W8001_PKTLEN_TOUCH93 - 1: >    Âcase W8001_PKTLEN_TOUCH9A - 1: > -        /* ignore one-finger touch packet. */ > -        if (w8001->pktlen == w8001->idx) > +        tmp = w8001->data[0] & W8001_TOUCH_BYTE; > +        if (tmp != W8001_TOUCH_BYTE) > +            break; > + > +        if (w8001->pktlen == w8001->idx) { >            Âw8001->idx = 0; > +            if (w8001->type != BTN_TOOL_PEN && > +              w8001->type != BTN_TOOL_RUBBER) { > +                parse_single_touch(w8001->data, &coord); > +                report_single_touch(w8001, &coord); > +            } > +        } >        Âbreak; > >    Â/* Pen coordinates packet */ > @@ -225,18 +310,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio, >        Âif (unlikely(tmp == W8001_TAB_BYTE)) >            Âbreak; > > -        tmp = (w8001->data[0] & W8001_TOUCH_BYTE); > +        tmp = w8001->data[0] & W8001_TOUCH_BYTE; >        Âif (tmp == W8001_TOUCH_BYTE) >            Âbreak; > >        Âw8001->idx = 0; > -        parse_data(w8001->data, &coord); > +        parse_pen_data(w8001->data, &coord); >        Âreport_pen_events(w8001, &coord); >        Âbreak; > >    Â/* control packet */ >    Âcase W8001_PKTLEN_TPCCTL - 1: > -        tmp = (w8001->data[0] & W8001_TOUCH_MASK); > +        tmp = w8001->data[0] & W8001_TOUCH_MASK; >        Âif (tmp == W8001_TOUCH_BYTE) >            Âbreak; > > @@ -249,7 +334,7 @@ static irqreturn_t w8001_interrupt(struct serio *serio, >    Â/* 2 finger touch packet */ >    Âcase W8001_PKTLEN_TOUCH2FG - 1: >        Âw8001->idx = 0; > -        parse_touch(w8001); > +        parse_multi_touch(w8001); >        Âbreak; >    Â} > > @@ -279,6 +364,7 @@ static int w8001_setup(struct w8001 *w8001) > Â{ >    Âstruct input_dev *dev = w8001->dev; >    Âstruct w8001_coord coord; > +    struct w8001_touch_query touch; >    Âint error; > >    Âerror = w8001_command(w8001, W8001_CMD_STOP, false); > @@ -287,14 +373,20 @@ static int w8001_setup(struct w8001 *w8001) > >    Âmsleep(250);  Â/* wait 250ms before querying the device */ > > +    strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name)); > + >    Â/* penabled? */ >    Âerror = w8001_command(w8001, W8001_CMD_QUERY, true); >    Âif (!error) { > +        __set_bit(BTN_TOUCH, dev->keybit); >        Â__set_bit(BTN_TOOL_PEN, dev->keybit); >        Â__set_bit(BTN_TOOL_RUBBER, dev->keybit); >        Â__set_bit(BTN_STYLUS, dev->keybit); >        Â__set_bit(BTN_STYLUS2, dev->keybit); > -        parse_data(w8001->response, &coord); > + > +        parse_pen_data(w8001->response, &coord); > +        w8001->max_pen_x = coord.x; > +        w8001->max_pen_y = coord.y; > >        Âinput_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); >        Âinput_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); > @@ -303,6 +395,8 @@ static int w8001_setup(struct w8001 *w8001) >            Âinput_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); >            Âinput_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); >        Â} > +        w8001->id = 0x90; > +        strlcat(w8001->name, " Penabled", sizeof(w8001->name)); >    Â} > >    Â/* Touch enabled? */ > @@ -313,24 +407,38 @@ static int w8001_setup(struct w8001 *w8001) >     * second byte is empty, which indicates touch is not supported. >     */ >    Âif (!error && w8001->response[1]) { > -        struct w8001_touch_query touch; > +        __set_bit(BTN_TOUCH, dev->keybit); > +        __set_bit(BTN_TOOL_FINGER, dev->keybit); > >        Âparse_touchquery(w8001->response, &touch); > +        w8001->max_touch_x = touch.x; > +        w8001->max_touch_y = touch.y; > + > +        /* scale to pen maximum */ > +        if (w8001->max_pen_x && w8001->max_pen_y) { > +            touch.x = w8001->max_pen_x; > +            touch.y = w8001->max_pen_y; > +        } > >        Âinput_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0); >        Âinput_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0); > -        __set_bit(BTN_TOOL_FINGER, dev->keybit); > >        Âswitch (touch.sensor_id) { >        Âcase 0: >        Âcase 2: >            Âw8001->pktlen = W8001_PKTLEN_TOUCH93; > +            w8001->id = 0x93; > +            strlcat(w8001->name, " 1FG", sizeof(w8001->name)); >            Âbreak; > + >        Âcase 1: >        Âcase 3: >        Âcase 4: >            Âw8001->pktlen = W8001_PKTLEN_TOUCH9A; > +            strlcat(w8001->name, " 1FG", sizeof(w8001->name)); > +            w8001->id = 0x9a; >            Âbreak; > + >        Âcase 5: >            Âw8001->pktlen = W8001_PKTLEN_TOUCH2FG; > > @@ -341,10 +449,17 @@ static int w8001_setup(struct w8001 *w8001) >                        Â0, touch.y, 0, 0); >            Âinput_set_abs_params(dev, ABS_MT_TOOL_TYPE, >                        Â0, MT_TOOL_MAX, 0, 0); > + > +            strlcat(w8001->name, " 2FG", sizeof(w8001->name)); > +            if (w8001->max_pen_x && w8001->max_pen_y) > +                w8001->id = 0xE3; > +            else > +                w8001->id = 0xE2; >            Âbreak; >        Â} >    Â} > > +    strlcat(w8001->name, " Touchscreen", sizeof(w8001->name)); >    Âreturn w8001_command(w8001, W8001_CMD_START, false); > Â} > > @@ -384,21 +499,17 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) >    Â} > >    Âw8001->serio = serio; > -    w8001->id = serio->id.id; >    Âw8001->dev = input_dev; >    Âinit_completion(&w8001->cmd_done); >    Âsnprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); > > -    input_dev->name = "Wacom W8001 Penabled Serial TouchScreen"; >    Âinput_dev->phys = w8001->phys; >    Âinput_dev->id.bustype = BUS_RS232; > -    input_dev->id.vendor = SERIO_W8001; > -    input_dev->id.product = w8001->id; > +    input_dev->id.vendor = 0x056a; >    Âinput_dev->id.version = 0x0100; >    Âinput_dev->dev.parent = &serio->dev; > >    Âinput_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); > -    __set_bit(BTN_TOUCH, input_dev->keybit); > >    Âserio_set_drvdata(serio, w8001); >    Âerr = serio_open(serio, drv); > @@ -409,6 +520,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) >    Âif (err) >        Âgoto fail3; > > +    input_dev->name = w8001->name; > +    input_dev->id.product = w8001->id; >    Âerr = input_register_device(w8001->dev); >    Âif (err) >        Âgoto fail3; > -- > 1.7.3.4 > > ÿô.nÇ·®+%˱é¥wÿº{.nÇ·¥{±þ)éâ^nr¡öë¨è&£ûz¹Þúzf£¢·h§~Ûÿÿïÿê_èæ+v¨þ)ßø