*/
 
 struct w8001 {
-       struct input_dev *dev;
+       struct input_dev *pen_dev;
+       struct input_dev *touch_dev;
        struct serio *serio;
        struct completion cmd_done;
        int id;
        u16 max_touch_y;
        u16 max_pen_x;
        u16 max_pen_y;
-       char name[64];
+       char pen_name[64];
+       char touch_name[64];
+       int open_count;
+       struct mutex mutex;
 };
 
 static void parse_pen_data(u8 *data, struct w8001_coord *coord)
 
 static void parse_multi_touch(struct w8001 *w8001)
 {
-       struct input_dev *dev = w8001->dev;
+       struct input_dev *dev = w8001->touch_dev;
        unsigned char *data = w8001->data;
        unsigned int x, y;
        int i;
 
 static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
 {
-       struct input_dev *dev = w8001->dev;
+       struct input_dev *dev = w8001->pen_dev;
 
        /*
         * We have 1 bit for proximity (rdy) and 3 bits for tip, side,
                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;
 
 static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
 {
-       struct input_dev *dev = w8001->dev;
+       struct input_dev *dev = w8001->touch_dev;
        unsigned int x = coord->x;
        unsigned int y = coord->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);
 
 static int w8001_open(struct input_dev *dev)
 {
        struct w8001 *w8001 = input_get_drvdata(dev);
+       int err;
+
+       err = mutex_lock_interruptible(&w8001->mutex);
+       if (err)
+               return err;
+
+       if (w8001->open_count++ == 0) {
+               err = w8001_command(w8001, W8001_CMD_START, false);
+               if (err)
+                       w8001->open_count--;
+       }
 
-       return w8001_command(w8001, W8001_CMD_START, false);
+       mutex_unlock(&w8001->mutex);
+       return err;
 }
 
 static void w8001_close(struct input_dev *dev)
 {
        struct w8001 *w8001 = input_get_drvdata(dev);
 
-       w8001_command(w8001, W8001_CMD_STOP, false);
+       mutex_lock(&w8001->mutex);
+
+       if (--w8001->open_count == 0)
+               w8001_command(w8001, W8001_CMD_STOP, false);
+
+       mutex_unlock(&w8001->mutex);
 }
 
 static int w8001_detect(struct w8001 *w8001)
 {
-       struct input_dev *dev = w8001->dev;
        int error;
 
        error = w8001_command(w8001, W8001_CMD_STOP, false);
 
        msleep(250);    /* wait 250ms before querying the device */
 
-       __set_bit(EV_KEY, dev->evbit);
-       __set_bit(EV_ABS, dev->evbit);
-       strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
-
-       __set_bit(INPUT_PROP_DIRECT, dev->propbit);
-
        return 0;
 }
 
-static int w8001_setup_pen(struct w8001 *w8001)
+static int w8001_setup_pen(struct w8001 *w8001, char *basename,
+                          size_t basename_sz)
 {
-       struct input_dev *dev = w8001->dev;
+       struct input_dev *dev = w8001->pen_dev;
        struct w8001_coord coord;
        int error;
 
        if (error)
                return error;
 
+       __set_bit(EV_KEY, dev->evbit);
+       __set_bit(EV_ABS, dev->evbit);
        __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);
+       __set_bit(INPUT_PROP_DIRECT, dev->propbit);
 
        parse_pen_data(w8001->response, &coord);
        w8001->max_pen_x = coord.x;
        }
 
        w8001->id = 0x90;
-       strlcat(w8001->name, " Penabled", sizeof(w8001->name));
+       strlcat(basename, " Penabled", basename_sz);
 
        return 0;
 }
 
-static int w8001_setup_touch(struct w8001 *w8001)
+static int w8001_setup_touch(struct w8001 *w8001, char *basename,
+                            size_t basename_sz)
 {
-       struct input_dev *dev = w8001->dev;
+       struct input_dev *dev = w8001->touch_dev;
        struct w8001_touch_query touch;
        int error;
 
+
        /* Touch enabled? */
        error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
        if (error)
        if (!w8001->response[1])
                return -ENXIO;
 
+       __set_bit(EV_KEY, dev->evbit);
+       __set_bit(EV_ABS, dev->evbit);
        __set_bit(BTN_TOUCH, dev->keybit);
-       __set_bit(BTN_TOOL_FINGER, dev->keybit);
+       __set_bit(INPUT_PROP_DIRECT, dev->propbit);
 
        parse_touchquery(w8001->response, &touch);
        w8001->max_touch_x = touch.x;
        case 2:
                w8001->pktlen = W8001_PKTLEN_TOUCH93;
                w8001->id = 0x93;
-               strlcat(w8001->name, " 1FG", sizeof(w8001->name));
+               strlcat(basename, " 1FG", basename_sz);
                break;
 
        case 1:
        case 3:
        case 4:
                w8001->pktlen = W8001_PKTLEN_TOUCH9A;
-               strlcat(w8001->name, " 1FG", sizeof(w8001->name));
+               strlcat(basename, " 1FG", basename_sz);
                w8001->id = 0x9a;
                break;
 
                input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
                                        0, MT_TOOL_MAX, 0, 0);
 
-               strlcat(w8001->name, " 2FG", sizeof(w8001->name));
+               strlcat(basename, " 2FG", basename_sz);
                if (w8001->max_pen_x && w8001->max_pen_y)
                        w8001->id = 0xE3;
                else
                break;
        }
 
-       strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
+       strlcat(basename, " Touchscreen", basename_sz);
 
        return 0;
 }
 
+static void w8001_set_devdata(struct input_dev *dev, struct w8001 *w8001,
+                             struct serio *serio)
+{
+       dev->phys = w8001->phys;
+       dev->id.bustype = BUS_RS232;
+       dev->id.product = w8001->id;
+       dev->id.vendor = 0x056a;
+       dev->id.version = 0x0100;
+       dev->open = w8001_open;
+       dev->close = w8001_close;
+
+       dev->dev.parent = &serio->dev;
+
+       input_set_drvdata(dev, w8001);
+}
+
 /*
  * w8001_disconnect() is the opposite of w8001_connect()
  */
 
        serio_close(serio);
 
-       input_unregister_device(w8001->dev);
+       if (w8001->pen_dev)
+               input_unregister_device(w8001->pen_dev);
+       if (w8001->touch_dev)
+               input_unregister_device(w8001->touch_dev);
        kfree(w8001);
 
        serio_set_drvdata(serio, NULL);
 static int w8001_connect(struct serio *serio, struct serio_driver *drv)
 {
        struct w8001 *w8001;
-       struct input_dev *input_dev;
+       struct input_dev *input_dev_pen;
+       struct input_dev *input_dev_touch;
+       char basename[64];
        int err, err_pen, err_touch;
 
        w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!w8001 || !input_dev) {
+       input_dev_pen = input_allocate_device();
+       input_dev_touch = input_allocate_device();
+       if (!w8001 || !input_dev_pen || !input_dev_touch) {
                err = -ENOMEM;
                goto fail1;
        }
 
        w8001->serio = serio;
-       w8001->dev = input_dev;
+       w8001->pen_dev = input_dev_pen;
+       w8001->touch_dev = input_dev_touch;
+       mutex_init(&w8001->mutex);
        init_completion(&w8001->cmd_done);
        snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
 
        if (err)
                goto fail3;
 
-       err_pen = w8001_setup_pen(w8001);
-       err_touch = w8001_setup_touch(w8001);
+       /* For backwards-compatibility we compose the basename based on
+        * capabilities and then just append the tool type
+        */
+       strlcpy(basename, "Wacom Serial", sizeof(basename));
+
+       err_pen = w8001_setup_pen(w8001, basename, sizeof(basename));
+       err_touch = w8001_setup_touch(w8001, basename, sizeof(basename));
        if (err_pen && err_touch) {
                err = -ENXIO;
                goto fail3;
        }
 
-       input_dev->name = w8001->name;
-       input_dev->phys = w8001->phys;
-       input_dev->id.product = w8001->id;
-       input_dev->id.bustype = BUS_RS232;
-       input_dev->id.vendor = 0x056a;
-       input_dev->id.version = 0x0100;
-       input_dev->dev.parent = &serio->dev;
+       if (!err_pen) {
+               strlcpy(w8001->pen_name, basename, sizeof(w8001->pen_name));
+               strlcat(w8001->pen_name, " Pen", sizeof(w8001->pen_name));
+               input_dev_pen->name = w8001->pen_name;
 
-       input_dev->open = w8001_open;
-       input_dev->close = w8001_close;
+               w8001_set_devdata(input_dev_pen, w8001, serio);
 
-       input_set_drvdata(input_dev, w8001);
+               err = input_register_device(w8001->pen_dev);
+               if (err)
+                       goto fail3;
+       } else {
+               input_free_device(input_dev_pen);
+               input_dev_pen = NULL;
+               w8001->pen_dev = NULL;
+       }
 
-       err = input_register_device(w8001->dev);
-       if (err)
-               goto fail3;
+       if (!err_touch) {
+               strlcpy(w8001->touch_name, basename, sizeof(w8001->touch_name));
+               strlcat(w8001->touch_name, " Finger",
+                       sizeof(w8001->touch_name));
+               input_dev_touch->name = w8001->touch_name;
+
+               w8001_set_devdata(input_dev_touch, w8001, serio);
+
+               err = input_register_device(w8001->touch_dev);
+               if (err)
+                       goto fail4;
+       } else {
+               input_free_device(input_dev_touch);
+               input_dev_touch = NULL;
+               w8001->touch_dev = NULL;
+       }
 
        return 0;
 
+fail4:
+       if (w8001->pen_dev)
+               input_unregister_device(w8001->pen_dev);
 fail3:
        serio_close(serio);
 fail2:
        serio_set_drvdata(serio, NULL);
 fail1:
-       input_free_device(input_dev);
+       input_free_device(input_dev_pen);
+       input_free_device(input_dev_touch);
        kfree(w8001);
        return err;
 }