All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: wacom serial tablet support
       [not found] <878v6axv7t.fsf@sliver.cipht.net>
@ 2013-02-27  5:23 ` Dmitry Torokhov
  2013-03-01  2:02   ` Ping Cheng
  0 siblings, 1 reply; 3+ messages in thread
From: Dmitry Torokhov @ 2013-02-27  5:23 UTC (permalink / raw)
  To: Julian Squires; +Cc: Chris Bagwell, Ping Cheng, Jason Gerecke, Linux Input

Hi Julian,

On Tue, Feb 26, 2013 at 10:07:20PM -0500, Julian Squires wrote:
> 
> Hi,
> 
> Closing in on two years ago I wrote a kernel driver for Wacom protocol
> IV serial tablet support.  It's been used successfully by at least a
> dozen users over that time, and I would like to take steps to get it
> into the mainline kernel.  After the magic scissors is my first attempt
> at a patch for your approval.  Please let me know what I can do to
> improve this and get it merged.
> 
> Thanks.

The driver looks quite reasonable, however that would be the 4th Wacom
driver in the tree... I wonder if it is time to split out transport
parts from core wacom functionality so that it can be shared by USB, I2C
and serio devices.

Thanks.

> 
> -- >8 --
> 
> Subject: [PATCH] Add Wacom serial tablet (protocol IV) support
> 
> Signed-off-by: Julian Squires <julian@cipht.net>
> ---
>  drivers/input/tablet/Kconfig    |   12 +
>  drivers/input/tablet/Makefile   |    1 +
>  drivers/input/tablet/wacom_iv.c |  494 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serio.h      |    1 +
>  4 files changed, 508 insertions(+)
>  create mode 100644 drivers/input/tablet/wacom_iv.c
> 
> diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
> index bed7cbf..8ea7ef5 100644
> --- a/drivers/input/tablet/Kconfig
> +++ b/drivers/input/tablet/Kconfig
> @@ -89,4 +89,16 @@ config TABLET_USB_WACOM
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called wacom.
>  
> +config TABLET_SERIAL_WACOM_IV
> +	tristate "Wacom protocol IV tablet support (serial)"
> +	depends on SERIO
> +	help
> +	  Say Y here if you have a serial Wacom Digitizer II,
> +	  PenPartner, or Graphire tablet.  Make sure to say Y to
> +	  "Mouse support" (CONFIG_INPUT_MOUSEDEV) and/or "Event
> +	  interface support" (CONFIG_INPUT_EVDEV) as well.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called wacom_iv.
> +
>  endif
> diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
> index 3f6c252..b10e29f 100644
> --- a/drivers/input/tablet/Makefile
> +++ b/drivers/input/tablet/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_TABLET_USB_GTCO)	+= gtco.o
>  obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
>  obj-$(CONFIG_TABLET_USB_KBTAB)	+= kbtab.o
>  obj-$(CONFIG_TABLET_USB_WACOM)	+= wacom.o
> +obj-$(CONFIG_TABLET_SERIAL_WACOM_IV) += wacom_iv.o
> diff --git a/drivers/input/tablet/wacom_iv.c b/drivers/input/tablet/wacom_iv.c
> new file mode 100644
> index 0000000..897ce83
> --- /dev/null
> +++ b/drivers/input/tablet/wacom_iv.c
> @@ -0,0 +1,494 @@
> +/*
> + * Wacom protocol 4 serial tablet driver
> + *
> + * Many thanks to Bill Seremetis, without whom PenPartner support
> + * would not have been possible.
> + *
> + * Thanks to Patrick Mahoney.
> + *
> + * Sections I have been unable to test personally due to lack of
> + * available hardware are marked UNTESTED.  Much of what is marked
> + * UNTESTED comes from reading the wcmSerial code in linuxwacom 0.9.0.
> + * If you have a tablet that corresponds to an UNTESTED section,
> + * please email me your results.
> + *
> + * To do:
> + *  - support pad buttons;
> + *  - support (protocol 4-style) tilt;
> + *  - support suppress;
> + *  - support Graphire relative wheel.
> + *
> + * This driver was developed with reference to much code written by others,
> + * particularly:
> + *  - elo, gunze drivers by Vojtech Pavlik <vojtech@ucw.cz>;
> + *  - wacom_w8001 driver by Jaya Kumar <jayakumar.lkml@gmail.com>;
> + *  - the USB wacom input driver, credited to many people
> + *    (see drivers/input/tablet/wacom.h);
> + *  - new and old versions of linuxwacom / xf86-input-wacom credited to
> + *    Frederic Lepied, France. <Lepied@XFree86.org> and
> + *    Ping Cheng, Wacom. <pingc@wacom.com>;
> + *  - and xf86wacom.c (a presumably ancient version of the linuxwacom code), by
> + *    Frederic Lepied and Raph Levien <raph@gtk.org>.
> + */
> +
> +#include <linux/string.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/input.h>
> +#include <linux/serio.h>
> +#include <linux/slab.h>
> +#include <linux/completion.h>
> +
> +#define DRIVER_AUTHOR	"Julian Squires <julian@cipht.net>"
> +#define DEVICE_NAME	"Wacom protocol 4 serial tablet"
> +#define DRIVER_DESC	DEVICE_NAME " driver"
> +
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> +
> +#define REQUEST_MODEL_AND_ROM_VERSION	"~#"
> +#define REQUEST_MAX_COORDINATES		"~C\r"
> +#define REQUEST_CONFIGURATION_STRING	"~R\r"
> +#define REQUEST_RESET_TO_PROTOCOL_IV	"\r#"
> +/* Note: sending "\r$\r" causes at least the Digitizer II to send
> + * packets in ASCII instead of binary.  "\r#" seems to undo that. */
> +
> +#define COMMAND_START_SENDING_PACKETS		"ST\r"
> +#define COMMAND_STOP_SENDING_PACKETS		"SP\r"
> +#define COMMAND_MULTI_MODE_INPUT		"MU1\r"
> +#define COMMAND_ORIGIN_IN_UPPER_LEFT		"OC1\r"
> +#define COMMAND_ENABLE_ALL_MACRO_BUTTONS	"~M0\r"
> +#define COMMAND_DISABLE_GROUP_1_MACRO_BUTTONS	"~M1\r"
> +#define COMMAND_TRANSMIT_AT_MAX_RATE		"IT0\r"
> +#define COMMAND_DISABLE_INCREMENTAL_MODE	"IN0\r"
> +#define COMMAND_ENABLE_CONTINUOUS_MODE		"SR\r"
> +#define COMMAND_ENABLE_PRESSURE_MODE		"PH1\r"
> +#define COMMAND_Z_FILTER			"ZF1\r"
> +
> +/* Note that this is a protocol 4 packet without tilt information. */
> +#define PACKET_LENGTH 7
> +
> +/* device IDs from wacom_wac.h */
> +#define STYLUS_DEVICE_ID	0x02
> +#define TOUCH_DEVICE_ID         0x03
> +#define CURSOR_DEVICE_ID        0x06
> +#define ERASER_DEVICE_ID        0x0A
> +#define PAD_DEVICE_ID           0x0F
> +
> +#define PAD_SERIAL 0xF0
> +
> +enum { STYLUS = 1, ERASER, PAD, CURSOR, TOUCH };
> +struct { int device_id; int input_id; } tools[] = {
> +	{ 0, 0 },
> +	{ STYLUS_DEVICE_ID, BTN_TOOL_PEN },
> +	{ ERASER_DEVICE_ID, BTN_TOOL_RUBBER },
> +	{ PAD_DEVICE_ID, 0 },
> +	{ CURSOR_DEVICE_ID, BTN_TOOL_MOUSE },
> +	{ TOUCH_DEVICE_ID, BTN_TOOL_FINGER }
> +};
> +
> +struct wacom {
> +	struct input_dev *dev;
> +	struct completion cmd_done;
> +	int extra_z_bits, tool;
> +	int idx;
> +	unsigned char data[32];
> +	char phys[32];
> +};
> +
> +
> +enum {
> +	MODEL_CINTIQ		= 0x504C, /* PL */
> +	MODEL_CINTIQ2		= 0x4454, /* DT */
> +	MODEL_DIGITIZER_II	= 0x5544, /* UD */
> +	MODEL_GRAPHIRE		= 0x4554, /* ET */
> +	MODEL_INTUOS		= 0x4744, /* GD */
> +	MODEL_INTUOS2		= 0x5844, /* XD */
> +	MODEL_PENPARTNER	= 0x4354, /* CT */
> +	MODEL_UNKNOWN		= 0
> +};
> +
> +static void handle_model_response(struct wacom *wacom)
> +{
> +	int major_v, minor_v, max_z;
> +	char *p;
> +
> +	major_v = minor_v = 0;
> +	p = strrchr(wacom->data, 'V');
> +	if (p)
> +		sscanf(p+1, "%u.%u", &major_v, &minor_v);
> +
> +	switch (wacom->data[2] << 8 | wacom->data[3]) {
> +	case MODEL_INTUOS:	/* UNTESTED */
> +	case MODEL_INTUOS2:
> +		dev_info(&wacom->dev->dev,
> +			 "Intuos tablets are not supported by this driver.\n");
> +		p = "Intuos";
> +		wacom->dev->id.version = MODEL_INTUOS;
> +		break;
> +	case MODEL_CINTIQ:	/* UNTESTED */
> +	case MODEL_CINTIQ2:
> +		p = "Cintiq";
> +		wacom->dev->id.version = MODEL_CINTIQ;
> +		switch (wacom->data[5]<<8 | wacom->data[6]) {
> +		case 0x3731: /* PL-710 */
> +			/* wcmSerial sets res to 2540x2540 in this case. */
> +			/* fall through */
> +		case 0x3535: /* PL-550 */
> +		case 0x3830: /* PL-800 */
> +			wacom->extra_z_bits = 2;
> +		}
> +		break;
> +	case MODEL_PENPARTNER:
> +		p = "Penpartner";
> +		wacom->dev->id.version = MODEL_PENPARTNER;
> +		/* wcmSerial sets res 1000x1000 in this case. */
> +		break;
> +	case MODEL_GRAPHIRE:
> +		p = "Graphire";
> +		wacom->dev->id.version = MODEL_GRAPHIRE;
> +		/* Apparently Graphire models do not answer coordinate
> +		   requests; see also wacom_setup(). */
> +		input_set_abs_params(wacom->dev, ABS_X, 0, 5103, 0, 0);
> +		input_set_abs_params(wacom->dev, ABS_Y, 0, 3711, 0, 0);
> +		input_abs_set_res(wacom->dev, ABS_X, 1016);
> +		input_abs_set_res(wacom->dev, ABS_Y, 1016);
> +		wacom->extra_z_bits = 2;
> +		break;
> +	case MODEL_DIGITIZER_II:
> +		p = "Digitizer II";
> +		wacom->dev->id.version = MODEL_DIGITIZER_II;
> +		if (major_v == 1 && minor_v <= 2)
> +			wacom->extra_z_bits = 0; /* UNTESTED */
> +		break;
> +	default:		/* UNTESTED */
> +		dev_dbg(&wacom->dev->dev,
> +			"Didn't understand Wacom model string: %s\n",
> +			wacom->data);
> +		p = "Unknown Protocol IV";
> +		wacom->dev->id.version = MODEL_UNKNOWN;
> +		break;
> +	}
> +	max_z = (1<<(7+wacom->extra_z_bits))-1;
> +	dev_info(&wacom->dev->dev, "Wacom tablet: %s, version %u.%u\n", p,
> +		 major_v, minor_v);
> +	dev_dbg(&wacom->dev->dev, "Max pressure: %d.\n", max_z);
> +	input_set_abs_params(wacom->dev, ABS_PRESSURE, 0, max_z, 0, 0);
> +}
> +
> +
> +static void handle_configuration_response(struct wacom *wacom)
> +{
> +	int x, y, skip;
> +
> +	dev_dbg(&wacom->dev->dev, "Configuration string: %s\n", wacom->data);
> +	sscanf(wacom->data, "~R%x,%u,%u,%u,%u", &skip, &skip, &skip, &x, &y);
> +	input_abs_set_res(wacom->dev, ABS_X, x);
> +	input_abs_set_res(wacom->dev, ABS_Y, y);
> +}
> +
> +static void handle_coordinates_response(struct wacom *wacom)
> +{
> +	int x, y;
> +
> +	dev_dbg(&wacom->dev->dev, "Coordinates string: %s\n", wacom->data);
> +	sscanf(wacom->data, "~C%u,%u", &x, &y);
> +	input_set_abs_params(wacom->dev, ABS_X, 0, x, 0, 0);
> +	input_set_abs_params(wacom->dev, ABS_Y, 0, y, 0, 0);
> +}
> +
> +static void handle_response(struct wacom *wacom)
> +{
> +	if (wacom->data[0] != '~' || wacom->idx < 2) {
> +		dev_dbg(&wacom->dev->dev,
> +			"got a garbled response of length %d.\n",
> +			wacom->idx);
> +		wacom->idx = 0;
> +		return;
> +	}
> +
> +	wacom->data[wacom->idx-1] = 0;
> +	wacom->idx = 0;
> +
> +	switch (wacom->data[1]) {
> +	case '#':
> +		handle_model_response(wacom);
> +		break;
> +	case 'R':
> +		handle_configuration_response(wacom);
> +		break;
> +	case 'C':
> +		handle_coordinates_response(wacom);
> +		break;
> +	default:
> +		dev_dbg(&wacom->dev->dev, "got an unexpected response: %s\n",
> +			wacom->data);
> +		break;
> +	}
> +
> +	complete(&wacom->cmd_done);
> +}
> +
> +static void handle_packet(struct wacom *wacom)
> +{
> +	int in_proximity_p, stylus_p, button, x, y, z;
> +	int tool;
> +
> +	in_proximity_p = wacom->data[0] & 0x40;
> +	stylus_p = wacom->data[0] & 0x20;
> +	button = (wacom->data[3] & 0x78) >> 3;
> +	x = (wacom->data[0] & 3) << 14 | wacom->data[1]<<7 | wacom->data[2];
> +	y = (wacom->data[3] & 3) << 14 | wacom->data[4]<<7 | wacom->data[5];
> +	z = wacom->data[6] & 0x7f;
> +	if (wacom->extra_z_bits >= 1)
> +		z = z << 1 | (wacom->data[3] & 0x4) >> 2;
> +	if (wacom->extra_z_bits > 1)
> +		z = z << 1 | (wacom->data[0] & 0x4);
> +	z = z ^ (0x40 << wacom->extra_z_bits);
> +
> +	/* NOTE: According to old wcmSerial code, button&8 is the
> +	 * eraser on Graphire tablets.  I have removed this until
> +	 * someone can verify it. */
> +	tool = stylus_p ? ((button & 4) ? ERASER : STYLUS) : CURSOR;
> +
> +	if (tool != wacom->tool && wacom->tool != 0) {
> +		input_report_key(wacom->dev, tools[wacom->tool].input_id, 0);
> +		input_sync(wacom->dev);
> +	}
> +	wacom->tool = tool;
> +
> +	input_report_key(wacom->dev, tools[tool].input_id, in_proximity_p);
> +	input_report_key(wacom->dev, MSC_SERIAL, 1);
> +	input_report_key(wacom->dev, ABS_MISC,
> +			 in_proximity_p ? tools[tool].device_id : 0);
> +	input_report_abs(wacom->dev, ABS_X, x);
> +	input_report_abs(wacom->dev, ABS_Y, y);
> +	input_report_abs(wacom->dev, ABS_PRESSURE, z);
> +	input_report_key(wacom->dev, BTN_TOUCH, button & 1);
> +	input_report_key(wacom->dev, BTN_STYLUS, button & 2);
> +	input_sync(wacom->dev);
> +}
> +
> +
> +static irqreturn_t wacom_interrupt(struct serio *serio, unsigned char data,
> +				   unsigned int flags)
> +{
> +	struct wacom *wacom = serio_get_drvdata(serio);
> +
> +	if (data & 0x80)
> +		wacom->idx = 0;
> +	if (wacom->idx >= sizeof(wacom->data)) {
> +		dev_dbg(&wacom->dev->dev,
> +			"throwing away %d bytes of garbage\n",
> +			wacom->idx);
> +		wacom->idx = 0;
> +	}
> +
> +	wacom->data[wacom->idx++] = data;
> +
> +	/* We're either expecting a carriage return-terminated ASCII
> +	 * response string, or a seven-byte packet with the MSB set on
> +	 * the first byte.
> +	 *
> +	 * Note however that some tablets (the PenPartner, for
> +	 * example) don't send a carriage return at the end of a
> +	 * command.  We handle these by waiting for timeout. */
> +	if (wacom->idx == PACKET_LENGTH && (wacom->data[0] & 0x80)) {
> +		handle_packet(wacom);
> +		wacom->idx = 0;
> +	} else if (data == '\r' && !(wacom->data[0] & 0x80)) {
> +		handle_response(wacom);
> +	}
> +	return IRQ_HANDLED;
> +}
> +
> +static void wacom_disconnect(struct serio *serio)
> +{
> +	struct wacom *wacom = serio_get_drvdata(serio);
> +
> +	serio_close(serio);
> +	serio_set_drvdata(serio, NULL);
> +	input_unregister_device(wacom->dev);
> +	kfree(wacom);
> +}
> +
> +static int wacom_send(struct serio *serio, const char *command)
> +{
> +	int err = 0;
> +	for (; !err && *command; command++)
> +		err = serio_write(serio, *command);
> +	return err;
> +}
> +
> +static int send_setup_string(struct wacom *wacom, struct serio *serio)
> +{
> +	const char *s;
> +	switch (wacom->dev->id.version) {
> +	case MODEL_CINTIQ:	/* UNTESTED */
> +		s = COMMAND_ORIGIN_IN_UPPER_LEFT
> +			COMMAND_TRANSMIT_AT_MAX_RATE
> +			COMMAND_ENABLE_CONTINUOUS_MODE
> +			COMMAND_START_SENDING_PACKETS;
> +		break;
> +	case MODEL_PENPARTNER:
> +		s = COMMAND_ENABLE_PRESSURE_MODE
> +			COMMAND_START_SENDING_PACKETS;
> +		break;
> +	default:
> +		s = COMMAND_MULTI_MODE_INPUT
> +			COMMAND_ORIGIN_IN_UPPER_LEFT
> +			COMMAND_ENABLE_ALL_MACRO_BUTTONS
> +			COMMAND_DISABLE_GROUP_1_MACRO_BUTTONS
> +			COMMAND_TRANSMIT_AT_MAX_RATE
> +			COMMAND_DISABLE_INCREMENTAL_MODE
> +			COMMAND_ENABLE_CONTINUOUS_MODE
> +			COMMAND_Z_FILTER
> +			COMMAND_START_SENDING_PACKETS;
> +		break;
> +	}
> +	return wacom_send(serio, s);
> +}
> +
> +static int wacom_setup(struct wacom *wacom, struct serio *serio)
> +{
> +	int err;
> +	unsigned long u;
> +
> +	/* Note that setting the link speed is the job of inputattach.
> +	 * We assume that reset negotiation has already happened,
> +	 * here. */
> +	init_completion(&wacom->cmd_done);
> +	err = wacom_send(serio, REQUEST_MODEL_AND_ROM_VERSION);
> +	if (err)
> +		return err;
> +	u = wait_for_completion_timeout(&wacom->cmd_done, HZ);
> +	if (u == 0) {
> +		if (wacom->idx == 0) {
> +			dev_info(&wacom->dev->dev,
> +				 "Timed out waiting for tablet to respond with model and version.\n");
> +			return -EIO;
> +		}
> +		handle_response(wacom);
> +	}
> +
> +	init_completion(&wacom->cmd_done);
> +	err = wacom_send(serio, REQUEST_CONFIGURATION_STRING);
> +	if (err)
> +		return err;
> +	u = wait_for_completion_timeout(&wacom->cmd_done, HZ);
> +	if (u == 0) {
> +		if (wacom->idx == 0)
> +			dev_info(&wacom->dev->dev,
> +				 "Timed out waiting for tablet to respond with configuration string.  Continuing anyway.\n");
> +		else
> +			handle_response(wacom);
> +	}
> +
> +	init_completion(&wacom->cmd_done);
> +	err = wacom_send(serio, REQUEST_MAX_COORDINATES);
> +	if (err)
> +		return err;
> +	u = wait_for_completion_timeout(&wacom->cmd_done, HZ);
> +	if (u == 0) {
> +		if (wacom->idx == 0)
> +			dev_info(&wacom->dev->dev,
> +				 "Timed out waiting for tablet to respond with coordinates string.  Continuing anyway.\n");
> +		else
> +			handle_response(wacom);
> +	}
> +
> +	return send_setup_string(wacom, serio);
> +}
> +
> +static int wacom_connect(struct serio *serio, struct serio_driver *drv)
> +{
> +	struct wacom *wacom;
> +	struct input_dev *input_dev;
> +	int err = -ENOMEM;
> +
> +	wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
> +	input_dev = input_allocate_device();
> +	if (!wacom || !input_dev)
> +		goto fail0;
> +
> +	wacom->dev = input_dev;
> +	wacom->extra_z_bits = 1;
> +	wacom->tool = wacom->idx = 0;
> +	snprintf(wacom->phys, sizeof(wacom->phys), "%s/input0", serio->phys);
> +
> +	input_dev->name = DEVICE_NAME;
> +	input_dev->phys = wacom->phys;
> +	input_dev->id.bustype = BUS_RS232;
> +	input_dev->id.vendor  = SERIO_WACOM_IV;
> +	input_dev->id.product = serio->id.extra;
> +	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_TOOL_PEN, input_dev->keybit);
> +	__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
> +	__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
> +	__set_bit(BTN_TOUCH, input_dev->keybit);
> +	__set_bit(BTN_STYLUS, input_dev->keybit);
> +
> +	serio_set_drvdata(serio, wacom);
> +
> +	err = serio_open(serio, drv);
> +	if (err)
> +		goto fail1;
> +
> +	err = wacom_setup(wacom, serio);
> +	if (err)
> +		goto fail2;
> +
> +	err = input_register_device(wacom->dev);
> +	if (err)
> +		goto fail2;
> +
> +	return 0;
> +
> + fail2:	serio_close(serio);
> + fail1:	serio_set_drvdata(serio, NULL);
> + fail0:	input_free_device(input_dev);
> +	kfree(wacom);
> +	return err;
> +}
> +
> +static struct serio_device_id wacom_serio_ids[] = {
> +	{
> +		.type	= SERIO_RS232,
> +		.proto	= SERIO_WACOM_IV,
> +		.id	= SERIO_ANY,
> +		.extra	= SERIO_ANY,
> +	},
> +	{ 0 }
> +};
> +
> +MODULE_DEVICE_TABLE(serio, wacom_serio_ids);
> +
> +static struct serio_driver wacom_drv = {
> +	.driver		= {
> +		.name	= "wacom_iv",
> +	},
> +	.description	= DRIVER_DESC,
> +	.id_table	= wacom_serio_ids,
> +	.interrupt	= wacom_interrupt,
> +	.connect	= wacom_connect,
> +	.disconnect	= wacom_disconnect,
> +};
> +
> +static int __init wacom_init(void)
> +{
> +	return serio_register_driver(&wacom_drv);
> +}
> +
> +static void __exit wacom_exit(void)
> +{
> +	serio_unregister_driver(&wacom_drv);
> +}
> +
> +module_init(wacom_init);
> +module_exit(wacom_exit);
> diff --git a/include/uapi/linux/serio.h b/include/uapi/linux/serio.h
> index 9f53fa7..becdd78 100644
> --- a/include/uapi/linux/serio.h
> +++ b/include/uapi/linux/serio.h
> @@ -76,5 +76,6 @@
>  #define SERIO_HAMPSHIRE	0x3b
>  #define SERIO_PS2MULT	0x3c
>  #define SERIO_TSC40	0x3d
> +#define SERIO_WACOM_IV	0x3e
>  
>  #endif /* _UAPI_SERIO_H */
> -- 
> 1.7.10.4

-- 
Dmitry

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: wacom serial tablet support
  2013-02-27  5:23 ` wacom serial tablet support Dmitry Torokhov
@ 2013-03-01  2:02   ` Ping Cheng
  2013-03-01 14:19     ` Julian Squires
  0 siblings, 1 reply; 3+ messages in thread
From: Ping Cheng @ 2013-03-01  2:02 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Julian Squires, Chris Bagwell, Jason Gerecke, Linux Input

On Tuesday, February 26, 2013, Dmitry Torokhov wrote:
>
> Hi Julian,
>
> On Tue, Feb 26, 2013 at 10:07:20PM -0500, Julian Squires wrote:
> >
> > Hi,
> >
> > Closing in on two years ago I wrote a kernel driver for Wacom protocol
> > IV serial tablet support.  It's been used successfully by at least a
> > dozen users over that time, and I would like to take steps to get it
> > into the mainline kernel.  After the magic scissors is my first attempt
> > at a patch for your approval.  Please let me know what I can do to
> > improve this and get it merged.
> >
> > Thanks.
>
> The driver looks quite reasonable, however that would be the 4th Wacom
> driver in the tree... I wonder if it is time to split out transport
> parts from core wacom functionality so that it can be shared by USB, I2C
> and serio devices.

Dmitry raised a very good point. We were considering to unify Wacom
drivers. With recent HID patches submitted by Benjamin and Henrik, I
feel it makes more sense to consider integrate Wacom into HID
subsystem. However, unless someone in the community has time to work
on it now, it will take sometime for us to priority our workflow.

As for Julian's patch, serial models are more than 10 years old. Last
serial devices (Intuos2 series) were released in 2001. We stopped
producing serial devices in 2004 (Intuos3 released then). Whether we
should add EOL models to upstream is beyond my decision. But, my team
won't have resources to maintain this driver, that is for sure.

If by whatever reason we can not merge this patch upstream, I am
willing to help Julian merge this patch to linuxwacom.sf.net project.
I hate to let good work go to waste. This patch could fit into one of
our legacy support branches, if Julian is interested in working with
linuxwacom project.

Ping

>
>
> Thanks.
>
> >
> > -- >8 --
> >
> > Subject: [PATCH] Add Wacom serial tablet (protocol IV) support
> >
> > Signed-off-by: Julian Squires <julian@cipht.net>
> > ---
> >  drivers/input/tablet/Kconfig    |   12 +
> >  drivers/input/tablet/Makefile   |    1 +
> >  drivers/input/tablet/wacom_iv.c |  494 +++++++++++++++++++++++++++++++++++++++
> >  include/uapi/linux/serio.h      |    1 +
> >  4 files changed, 508 insertions(+)
> >  create mode 100644 drivers/input/tablet/wacom_iv.c
> >
> > diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
> > index bed7cbf..8ea7ef5 100644
> > --- a/drivers/input/tablet/Kconfig
> > +++ b/drivers/input/tablet/Kconfig
> > @@ -89,4 +89,16 @@ config TABLET_USB_WACOM
> >         To compile this driver as a module, choose M here: the
> >         module will be called wacom.
> >
> > +config TABLET_SERIAL_WACOM_IV
> > +     tristate "Wacom protocol IV tablet support (serial)"
> > +     depends on SERIO
> > +     help
> > +       Say Y here if you have a serial Wacom Digitizer II,
> > +       PenPartner, or Graphire tablet.  Make sure to say Y to
> > +       "Mouse support" (CONFIG_INPUT_MOUSEDEV) and/or "Event
> > +       interface support" (CONFIG_INPUT_EVDEV) as well.
> > +
> > +       To compile this driver as a module, choose M here: the
> > +       module will be called wacom_iv.
> > +
> >  endif
> > diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
> > index 3f6c252..b10e29f 100644
> > --- a/drivers/input/tablet/Makefile
> > +++ b/drivers/input/tablet/Makefile
> > @@ -11,3 +11,4 @@ obj-$(CONFIG_TABLET_USB_GTCO)       += gtco.o
> >  obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
> >  obj-$(CONFIG_TABLET_USB_KBTAB)       += kbtab.o
> >  obj-$(CONFIG_TABLET_USB_WACOM)       += wacom.o
> > +obj-$(CONFIG_TABLET_SERIAL_WACOM_IV) += wacom_iv.o
> > diff --git a/drivers/input/tablet/wacom_iv.c b/drivers/input/tablet/wacom_iv.c
> > new file mode 100644
> > index 0000000..897ce83
> > --- /dev/null
> > +++ b/drivers/input/tablet/wacom_iv.c
> > @@ -0,0 +1,494 @@
> > +/*
> > + * Wacom protocol 4 serial tablet driver
> > + *
> > + * Many thanks to Bill Seremetis, without whom PenPartner support
> > + * would not have been possible.
> > + *
> > + * Thanks to Patrick Mahoney.
> > + *
> > + * Sections I have been unable to test personally due to lack of
> > + * available hardware are marked UNTESTED.  Much of what is marked
> > + * UNTESTED comes from reading the wcmSerial code in linuxwacom 0.9.0.
> > + * If you have a tablet that corresponds to an UNTESTED section,
> > + * please email me your results.
> > + *
> > + * To do:
> > + *  - support pad buttons;
> > + *  - support (protocol 4-style) tilt;
> > + *  - support suppress;
> > + *  - support Graphire relative wheel.
> > + *
> > + * This driver was developed with reference to much code written by others,
> > + * particularly:
> > + *  - elo, gunze drivers by Vojtech Pavlik <vojtech@ucw.cz>;
> > + *  - wacom_w8001 driver by Jaya Kumar <jayakumar.lkml@gmail.com>;
> > + *  - the USB wacom input driver, credited to many people
> > + *    (see drivers/input/tablet/wacom.h);
> > + *  - new and old versions of linuxwacom / xf86-input-wacom credited to
> > + *    Frederic Lepied, France. <Lepied@XFree86.org> and
> > + *    Ping Cheng, Wacom. <pingc@wacom.com>;
> > + *  - and xf86wacom.c (a presumably ancient version of the linuxwacom code), by
> > + *    Frederic Lepied and Raph Levien <raph@gtk.org>.
> > + */
> > +
> > +#include <linux/string.h>
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/init.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/input.h>
> > +#include <linux/serio.h>
> > +#include <linux/slab.h>
> > +#include <linux/completion.h>
> > +
> > +#define DRIVER_AUTHOR        "Julian Squires <julian@cipht.net>"
> > +#define DEVICE_NAME  "Wacom protocol 4 serial tablet"
> > +#define DRIVER_DESC  DEVICE_NAME " driver"
> > +
> > +MODULE_AUTHOR(DRIVER_AUTHOR);
> > +MODULE_DESCRIPTION(DRIVER_DESC);
> > +MODULE_LICENSE("GPL");
> > +
> > +#define REQUEST_MODEL_AND_ROM_VERSION        "~#"
> > +#define REQUEST_MAX_COORDINATES              "~C\r"
> > +#define REQUEST_CONFIGURATION_STRING "~R\r"
> > +#define REQUEST_RESET_TO_PROTOCOL_IV "\r#"
> > +/* Note: sending "\r$\r" causes at least the Digitizer II to send
> > + * packets in ASCII instead of binary.  "\r#" seems to undo that. */
> > +
> > +#define COMMAND_START_SENDING_PACKETS                "ST\r"
> > +#define COMMAND_STOP_SENDING_PACKETS         "SP\r"
> > +#define COMMAND_MULTI_MODE_INPUT             "MU1\r"
> > +#define COMMAND_ORIGIN_IN_UPPER_LEFT         "OC1\r"
> > +#define COMMAND_ENABLE_ALL_MACRO_BUTTONS     "~M0\r"
> > +#define COMMAND_DISABLE_GROUP_1_MACRO_BUTTONS        "~M1\r"
> > +#define COMMAND_TRANSMIT_AT_MAX_RATE         "IT0\r"
> > +#define COMMAND_DISABLE_INCREMENTAL_MODE     "IN0\r"
> > +#define COMMAND_ENABLE_CONTINUOUS_MODE               "SR\r"
> > +#define COMMAND_ENABLE_PRESSURE_MODE         "PH1\r"
> > +#define COMMAND_Z_FILTER                     "ZF1\r"
> > +
> > +/* Note that this is a protocol 4 packet without tilt information. */
> > +#define PACKET_LENGTH 7
> > +
> > +/* device IDs from wacom_wac.h */
> > +#define STYLUS_DEVICE_ID     0x02
> > +#define TOUCH_DEVICE_ID         0x03
> > +#define CURSOR_DEVICE_ID        0x06
> > +#define ERASER_DEVICE_ID        0x0A
> > +#define PAD_DEVICE_ID           0x0F
> > +
> > +#define PAD_SERIAL 0xF0
> > +
> > +enum { STYLUS = 1, ERASER, PAD, CURSOR, TOUCH };
> > +struct { int device_id; int input_id; } tools[] = {
> > +     { 0, 0 },
> > +     { STYLUS_DEVICE_ID, BTN_TOOL_PEN },
> > +     { ERASER_DEVICE_ID, BTN_TOOL_RUBBER },
> > +     { PAD_DEVICE_ID, 0 },
> > +     { CURSOR_DEVICE_ID, BTN_TOOL_MOUSE },
> > +     { TOUCH_DEVICE_ID, BTN_TOOL_FINGER }
> > +};
> > +
> > +struct wacom {
> > +     struct input_dev *dev;
> > +     struct completion cmd_done;
> > +     int extra_z_bits, tool;
> > +     int idx;
> > +     unsigned char data[32];
> > +     char phys[32];
> > +};
> > +
> > +
> > +enum {
> > +     MODEL_CINTIQ            = 0x504C, /* PL */
> > +     MODEL_CINTIQ2           = 0x4454, /* DT */
> > +     MODEL_DIGITIZER_II      = 0x5544, /* UD */
> > +     MODEL_GRAPHIRE          = 0x4554, /* ET */
> > +     MODEL_INTUOS            = 0x4744, /* GD */
> > +     MODEL_INTUOS2           = 0x5844, /* XD */
> > +     MODEL_PENPARTNER        = 0x4354, /* CT */
> > +     MODEL_UNKNOWN           = 0
> > +};
> > +
> > +static void handle_model_response(struct wacom *wacom)
> > +{
> > +     int major_v, minor_v, max_z;
> > +     char *p;
> > +
> > +     major_v = minor_v = 0;
> > +     p = strrchr(wacom->data, 'V');
> > +     if (p)
> > +             sscanf(p+1, "%u.%u", &major_v, &minor_v);
> > +
> > +     switch (wacom->data[2] << 8 | wacom->data[3]) {
> > +     case MODEL_INTUOS:      /* UNTESTED */
> > +     case MODEL_INTUOS2:
> > +             dev_info(&wacom->dev->dev,
> > +                      "Intuos tablets are not supported by this driver.\n");
> > +             p = "Intuos";
> > +             wacom->dev->id.version = MODEL_INTUOS;
> > +             break;
> > +     case MODEL_CINTIQ:      /* UNTESTED */
> > +     case MODEL_CINTIQ2:
> > +             p = "Cintiq";
> > +             wacom->dev->id.version = MODEL_CINTIQ;
> > +             switch (wacom->data[5]<<8 | wacom->data[6]) {
> > +             case 0x3731: /* PL-710 */
> > +                     /* wcmSerial sets res to 2540x2540 in this case. */
> > +                     /* fall through */
> > +             case 0x3535: /* PL-550 */
> > +             case 0x3830: /* PL-800 */
> > +                     wacom->extra_z_bits = 2;
> > +             }
> > +             break;
> > +     case MODEL_PENPARTNER:
> > +             p = "Penpartner";
> > +             wacom->dev->id.version = MODEL_PENPARTNER;
> > +             /* wcmSerial sets res 1000x1000 in this case. */
> > +             break;
> > +     case MODEL_GRAPHIRE:
> > +             p = "Graphire";
> > +             wacom->dev->id.version = MODEL_GRAPHIRE;
> > +             /* Apparently Graphire models do not answer coordinate
> > +                requests; see also wacom_setup(). */
> > +             input_set_abs_params(wacom->dev, ABS_X, 0, 5103, 0, 0);
> > +             input_set_abs_params(wacom->dev, ABS_Y, 0, 3711, 0, 0);
> > +             input_abs_set_res(wacom->dev, ABS_X, 1016);
> > +             input_abs_set_res(wacom->dev, ABS_Y, 1016);
> > +             wacom->extra_z_bits = 2;
> > +             break;
> > +     case MODEL_DIGITIZER_II:
> > +             p = "Digitizer II";
> > +             wacom->dev->id.version = MODEL_DIGITIZER_II;
> > +             if (major_v == 1 && minor_v <= 2)
> > +                     wacom->extra_z_bits = 0; /* UNTESTED */
> > +             break;
> > +     default:                /* UNTESTED */
> > +             dev_dbg(&wacom->dev->dev,
> > +                     "Didn't understand Wacom model string: %s\n",
> > +                     wacom->data);
> > +             p = "Unknown Protocol IV";
> > +             wacom->dev->id.version = MODEL_UNKNOWN;
> > +             break;
> > +     }
> > +     max_z = (1<<(7+wacom->extra_z_bits))-1;
> > +     dev_info(&wacom->dev->dev, "Wacom tablet: %s, version %u.%u\n", p,
> > +              major_v, minor_v);
> > +     dev_dbg(&wacom->dev->dev, "Max pressure: %d.\n", max_z);
> > +     input_set_abs_params(wacom->dev, ABS_PRESSURE, 0, max_z, 0, 0);
> > +}
> > +
> > +
> > +static void handle_configuration_response(struct wacom *wacom)
> > +{
> > +     int x, y, skip;
> > +
> > +     dev_dbg(&wacom->dev->dev, "Configuration string: %s\n", wacom->data);
> > +     sscanf(wacom->data, "~R%x,%u,%u,%u,%u", &skip, &skip, &skip, &x, &y);
> > +     input_abs_set_res(wacom->dev, ABS_X, x);
> > +     input_abs_set_res(wacom->dev, ABS_Y, y);
> > +}
> > +
> > +static void handle_coordinates_response(struct wacom *wacom)
> > +{
> > +     int x, y;
> > +
> > +     dev_dbg(&wacom->dev->dev, "Coordinates string: %s\n", wacom->data);
> > +     sscanf(wacom->data, "~C%u,%u", &x, &y);
> > +     input_set_abs_params(wacom->dev, ABS_X, 0, x, 0, 0);
> > +     input_set_abs_params(wacom->dev, ABS_Y, 0, y, 0, 0);
> > +}
> > +
> > +static void handle_response(struct wacom *wacom)
> > +{
> > +     if (wacom->data[0] != '~' || wacom->idx < 2) {
> > +             dev_dbg(&wacom->dev->dev,
> > +                     "got a garbled response of length %d.\n",
> > +                     wacom->idx);
> > +             wacom->idx = 0;
> > +             return;
> > +     }
> > +
> > +     wacom->data[wacom->idx-1] = 0;
> > +     wacom->idx = 0;
> > +
> > +     switch (wacom->data[1]) {
> > +     case '#':
> > +             handle_model_response(wacom);
> > +             break;
> > +     case 'R':
> > +             handle_configuration_response(wacom);
> > +             break;
> > +     case 'C':
> > +             handle_coordinates_response(wacom);
> > +             break;
> > +     default:
> > +             dev_dbg(&wacom->dev->dev, "got an unexpected response: %s\n",
> > +                     wacom->data);
> > +             break;
> > +     }
> > +
> > +     complete(&wacom->cmd_done);
> > +}
> > +
> > +static void handle_packet(struct wacom *wacom)
> > +{
> > +     int in_proximity_p, stylus_p, button, x, y, z;
> > +     int tool;
> > +
> > +     in_proximity_p = wacom->data[0] & 0x40;
> > +     stylus_p = wacom->data[0] & 0x20;
> > +     button = (wacom->data[3] & 0x78) >> 3;
> > +     x = (wacom->data[0] & 3) << 14 | wacom->data[1]<<7 | wacom->data[2];
> > +     y = (wacom->data[3] & 3) << 14 | wacom->data[4]<<7 | wacom->data[5];
> > +     z = wacom->data[6] & 0x7f;
> > +     if (wacom->extra_z_bits >= 1)
> > +             z = z << 1 | (wacom->data[3] & 0x4) >> 2;
> > +     if (wacom->extra_z_bits > 1)
> > +             z = z << 1 | (wacom->data[0] & 0x4);
> > +     z = z ^ (0x40 << wacom->extra_z_bits);
> > +
> > +     /* NOTE: According to old wcmSerial code, button&8 is the
> > --
> > 1.7.10.4
>
> --
> Dmitry

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: wacom serial tablet support
  2013-03-01  2:02   ` Ping Cheng
@ 2013-03-01 14:19     ` Julian Squires
  0 siblings, 0 replies; 3+ messages in thread
From: Julian Squires @ 2013-03-01 14:19 UTC (permalink / raw)
  To: Ping Cheng; +Cc: Dmitry Torokhov, Chris Bagwell, Jason Gerecke, Linux Input

[-- Attachment #1: Type: text/plain, Size: 1397 bytes --]


Ping Cheng <pinglinux@gmail.com> writes:
> On Tuesday, February 26, 2013, Dmitry Torokhov wrote:
>> The driver looks quite reasonable, however that would be the 4th Wacom
>> driver in the tree... I wonder if it is time to split out transport
>> parts from core wacom functionality so that it can be shared by USB, I2C
>> and serio devices.

I agree, although I'm not sure how much common code there would actually
be between these devices.  However:

> As for Julian's patch, serial models are more than 10 years old. Last
> serial devices (Intuos2 series) were released in 2001. We stopped
> producing serial devices in 2004 (Intuos3 released then). Whether we
> should add EOL models to upstream is beyond my decision. But, my team
> won't have resources to maintain this driver, that is for sure.

This is the reason I wrote the driver in the first place -- the existing
Wacom driver developers dropped support for serial tablets, which some
people still use (I regularly get email about my driver from users).  I
am only asking to bring this into the mainline because I get asked about
it regularly -- most signicantly, the device needs a serio ID allocated
for it so that users don't have to play whack-a-mole with the IDs being
allocated in the kernel.

I'll take a look at what could be shared between the drivers this
weekend.

Cheers,

-- 
Julian Squires

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2013-03-01 14:19 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <878v6axv7t.fsf@sliver.cipht.net>
2013-02-27  5:23 ` wacom serial tablet support Dmitry Torokhov
2013-03-01  2:02   ` Ping Cheng
2013-03-01 14:19     ` Julian Squires

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.