Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90b9b0d5 authored by Dmitry Torokhov's avatar Dmitry Torokhov
Browse files

Merge branch 'iforce' into next

Bring in improvements to driver for I-Force devices.
parents 002cdb95 11518370
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -13,15 +13,15 @@ config JOYSTICK_IFORCE
	  module will be called iforce.

config JOYSTICK_IFORCE_USB
	bool "I-Force USB joysticks and wheels"
	depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB
	tristate "I-Force USB joysticks and wheels"
	depends on JOYSTICK_IFORCE && USB
	help
	  Say Y here if you have an I-Force joystick or steering wheel
	  connected to your USB port.

config JOYSTICK_IFORCE_232
	bool "I-Force Serial joysticks and wheels"
	depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO
	tristate "I-Force Serial joysticks and wheels"
	depends on JOYSTICK_IFORCE && SERIO
	help
	  Say Y here if you have an I-Force joystick or steering wheel
	  connected to your serial (COM) port.
+3 −4
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@
#

obj-$(CONFIG_JOYSTICK_IFORCE)		+= iforce.o

iforce-y := iforce-ff.o iforce-main.o iforce-packets.o
iforce-$(CONFIG_JOYSTICK_IFORCE_232)	+= iforce-serio.o
iforce-$(CONFIG_JOYSTICK_IFORCE_USB)	+= iforce-usb.o
obj-$(CONFIG_JOYSTICK_IFORCE_232)	+= iforce-serio.o
obj-$(CONFIG_JOYSTICK_IFORCE_USB)	+= iforce-usb.o
+57 −121
Original line number Diff line number Diff line
@@ -21,10 +21,11 @@
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <asm/unaligned.h>
#include "iforce.h"

MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
MODULE_DESCRIPTION("Core I-Force joysticks and wheels driver");
MODULE_LICENSE("GPL");

static signed short btn_joystick[] =
@@ -67,6 +68,7 @@ static struct iforce_device iforce_device[] = {
	{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce }, //?
	{ 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
	{ 0x061c, 0xc084, "ACT LABS Force RS",				btn_wheel, abs_wheel, ff_iforce },
	{ 0x06a3, 0xff04, "Saitek R440 Force Wheel",			btn_wheel, abs_wheel, ff_iforce }, //?
	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce }, //?
	{ 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback",	btn_joystick, abs_joystick_rudder, ff_iforce },
	{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce }, //?
@@ -132,7 +134,6 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect,
 * Upload the effect
 */
	switch (effect->type) {

	case FF_PERIODIC:
		ret = iforce_upload_periodic(iforce, effect, old);
		break;
@@ -185,15 +186,7 @@ static int iforce_open(struct input_dev *dev)
{
	struct iforce *iforce = input_get_drvdata(dev);

	switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
		case IFORCE_USB:
			iforce->irq->dev = iforce->usbdev;
			if (usb_submit_urb(iforce->irq, GFP_KERNEL))
				return -EIO;
			break;
#endif
	}
	iforce->xport_ops->start_io(iforce);

	if (test_bit(EV_FF, dev->evbit)) {
		/* Enable force feedback */
@@ -226,27 +219,17 @@ static void iforce_close(struct input_dev *dev)
			!test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags));
	}

	switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
	case IFORCE_USB:
		usb_kill_urb(iforce->irq);
		usb_kill_urb(iforce->out);
		usb_kill_urb(iforce->ctrl);
		break;
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_232
	case IFORCE_232:
		//TODO: Wait for the last packets to be sent
		break;
#endif
	}
	iforce->xport_ops->stop_io(iforce);
}

int iforce_init_device(struct iforce *iforce)
int iforce_init_device(struct device *parent, u16 bustype,
		       struct iforce *iforce)
{
	struct input_dev *input_dev;
	struct ff_device *ff;
	unsigned char c[] = "CEOV";
	u8 c[] = "CEOV";
	u8 buf[IFORCE_MAX_LENGTH];
	size_t len;
	int i, error;
	int ff_effects = 0;

@@ -264,20 +247,8 @@ int iforce_init_device(struct iforce *iforce)
 * Input device fields.
 */

	switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
	case IFORCE_USB:
		input_dev->id.bustype = BUS_USB;
		input_dev->dev.parent = &iforce->usbdev->dev;
		break;
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_232
	case IFORCE_232:
		input_dev->id.bustype = BUS_RS232;
		input_dev->dev.parent = &iforce->serio->dev;
		break;
#endif
	}
	input_dev->id.bustype = bustype;
	input_dev->dev.parent = parent;

	input_set_drvdata(input_dev, iforce);

@@ -302,7 +273,7 @@ int iforce_init_device(struct iforce *iforce)
 */

	for (i = 0; i < 20; i++)
		if (!iforce_get_id_packet(iforce, "O"))
		if (!iforce_get_id_packet(iforce, 'O', buf, &len))
			break;

	if (i == 20) { /* 5 seconds */
@@ -316,23 +287,23 @@ int iforce_init_device(struct iforce *iforce)
 * Get device info.
 */

	if (!iforce_get_id_packet(iforce, "M"))
		input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
	if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3)
		input_dev->id.vendor = get_unaligned_le16(buf + 1);
	else
		dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");

	if (!iforce_get_id_packet(iforce, "P"))
		input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
	if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3)
		input_dev->id.product = get_unaligned_le16(buf + 1);
	else
		dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");

	if (!iforce_get_id_packet(iforce, "B"))
		iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
	if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3)
		iforce->device_memory.end = get_unaligned_le16(buf + 1);
	else
		dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");

	if (!iforce_get_id_packet(iforce, "N"))
		ff_effects = iforce->edata[1];
	if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2)
		ff_effects = buf[1];
	else
		dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");

@@ -348,8 +319,9 @@ int iforce_init_device(struct iforce *iforce)
 */

	for (i = 0; c[i]; i++)
		if (!iforce_get_id_packet(iforce, c + i))
			iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata);
		if (!iforce_get_id_packet(iforce, c[i], buf, &len))
			iforce_dump_packet(iforce, "info",
					   (FF_CMD_QUERY & 0xff00) | len, buf);

/*
 * Disable spring, enable force feedback.
@@ -383,11 +355,9 @@ int iforce_init_device(struct iforce *iforce)
		signed short t = iforce->type->abs[i];

		switch (t) {

		case ABS_X:
		case ABS_Y:
		case ABS_WHEEL:

			input_set_abs_params(input_dev, t, -1920, 1920, 16, 128);
			set_bit(t, input_dev->ffbit);
			break;
@@ -395,12 +365,10 @@ int iforce_init_device(struct iforce *iforce)
		case ABS_THROTTLE:
		case ABS_GAS:
		case ABS_BRAKE:

			input_set_abs_params(input_dev, t, 0, 255, 0, 0);
			break;

		case ABS_RUDDER:

			input_set_abs_params(input_dev, t, -128, 127, 0, 0);
			break;

@@ -408,7 +376,6 @@ int iforce_init_device(struct iforce *iforce)
		case ABS_HAT0Y:
		case ABS_HAT1X:
		case ABS_HAT1Y:

			input_set_abs_params(input_dev, t, -1, 1, 0, 0);
			break;
		}
@@ -443,35 +410,4 @@ int iforce_init_device(struct iforce *iforce)
 fail:	input_free_device(input_dev);
	return error;
}

static int __init iforce_init(void)
{
	int err = 0;

#ifdef CONFIG_JOYSTICK_IFORCE_USB
	err = usb_register(&iforce_usb_driver);
	if (err)
		return err;
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_232
	err = serio_register_driver(&iforce_serio_drv);
#ifdef CONFIG_JOYSTICK_IFORCE_USB
	if (err)
		usb_deregister(&iforce_usb_driver);
#endif
#endif
	return err;
}

static void __exit iforce_exit(void)
{
#ifdef CONFIG_JOYSTICK_IFORCE_USB
	usb_deregister(&iforce_usb_driver);
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_232
	serio_unregister_driver(&iforce_serio_drv);
#endif
}

module_init(iforce_init);
module_exit(iforce_exit);
EXPORT_SYMBOL(iforce_init_device);
+70 −145
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <asm/unaligned.h>
#include "iforce.h"

static struct {
@@ -91,27 +92,12 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
/*
 * If necessary, start the transmission
 */
	switch (iforce->bus) {

#ifdef CONFIG_JOYSTICK_IFORCE_232
		case IFORCE_232:
	if (empty)
			iforce_serial_xmit(iforce);
		break;
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_USB
		case IFORCE_USB:

		if (iforce->usbdev && empty &&
			!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
		iforce->xport_ops->xmit(iforce);

			iforce_usb_xmit(iforce);
		}
		break;
#endif
	}
	return 0;
}
EXPORT_SYMBOL(iforce_send_packet);

/* Start or stop an effect */
int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
@@ -145,70 +131,74 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
	return -1;
}

void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data)
{
	struct input_dev *dev = iforce->dev;
	int i;
	static int being_used = 0;

	if (being_used)
		dev_warn(&iforce->dev->dev,
			 "re-entrant call to iforce_process %d\n", being_used);
	being_used++;

#ifdef CONFIG_JOYSTICK_IFORCE_232
	if (HI(iforce->expect_packet) == HI(cmd)) {
		iforce->expect_packet = 0;
		iforce->ecmd = cmd;
		memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
	}
#endif
	wake_up(&iforce->wait);

	if (!iforce->type) {
		being_used--;
		return;
	}

	switch (HI(cmd)) {

		case 0x01:	/* joystick position data */
		case 0x03:	/* wheel position data */
			if (HI(cmd) == 1) {
				input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
				input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
				input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
				if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
					input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
			} else {
				input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
				input_report_abs(dev, ABS_GAS,   255 - data[2]);
				input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
			}

	input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
	input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);

	for (i = 0; iforce->type->btn[i] >= 0; i++)
				input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
		input_report_key(dev, iforce->type->btn[i],
				 data[(i >> 3) + 5] & (1 << (i & 7)));

	/* If there are untouched bits left, interpret them as the second hat */
	if (i <= 8) {
				int btns = data[6];
		u8 btns = data[6];

		if (test_bit(ABS_HAT1X, dev->absbit)) {
					if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1);
					else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1);
					else input_report_abs(dev, ABS_HAT1X, 0);
			if (btns & BIT(3))
				input_report_abs(dev, ABS_HAT1X, -1);
			else if (btns & BIT(1))
				input_report_abs(dev, ABS_HAT1X, 1);
			else
				input_report_abs(dev, ABS_HAT1X, 0);
		}

		if (test_bit(ABS_HAT1Y, dev->absbit)) {
					if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1);
					else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1);
					else input_report_abs(dev, ABS_HAT1Y, 0);
			if (btns & BIT(0))
				input_report_abs(dev, ABS_HAT1Y, -1);
			else if (btns & BIT(2))
				input_report_abs(dev, ABS_HAT1Y, 1);
			else
				input_report_abs(dev, ABS_HAT1Y, 0);
		}
	}
}

void iforce_process_packet(struct iforce *iforce,
			   u8 packet_id, u8 *data, size_t len)
{
	struct input_dev *dev = iforce->dev;
	int i, j;

	switch (packet_id) {

	case 0x01:	/* joystick position data */
		input_report_abs(dev, ABS_X,
				 (__s16) get_unaligned_le16(data));
		input_report_abs(dev, ABS_Y,
				 (__s16) get_unaligned_le16(data + 2));
		input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);

		if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
			input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);

		iforce_report_hats_buttons(iforce, data);

		input_sync(dev);
		break;

	case 0x03:	/* wheel position data */
		input_report_abs(dev, ABS_WHEEL,
				 (__s16) get_unaligned_le16(data));
		input_report_abs(dev, ABS_GAS,   255 - data[2]);
		input_report_abs(dev, ABS_BRAKE, 255 - data[3]);

		iforce_report_hats_buttons(iforce, data);

		input_sync(dev);
		break;

	case 0x02:	/* status report */
@@ -226,76 +216,11 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
			/* Report stop event */
			input_report_ff_status(dev, i, FF_STATUS_STOPPED);
		}
			if (LO(cmd) > 3) {
				int j;
				for (j = 3; j < LO(cmd); j += 2)
					mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
			}
			break;
	}
	being_used--;
}

int iforce_get_id_packet(struct iforce *iforce, char *packet)
{
	switch (iforce->bus) {

	case IFORCE_USB: {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
		int status;

		iforce->cr.bRequest = packet[0];
		iforce->ctrl->dev = iforce->usbdev;

		status = usb_submit_urb(iforce->ctrl, GFP_KERNEL);
		if (status) {
			dev_err(&iforce->intf->dev,
				"usb_submit_urb failed %d\n", status);
			return -1;
		}

		wait_event_interruptible_timeout(iforce->wait,
			iforce->ctrl->status != -EINPROGRESS, HZ);

		if (iforce->ctrl->status) {
			dev_dbg(&iforce->intf->dev,
				"iforce->ctrl->status = %d\n",
				iforce->ctrl->status);
			usb_unlink_urb(iforce->ctrl);
			return -1;
		}
#else
		printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n");
#endif
		}
		break;

	case IFORCE_232:
		for (j = 3; j < len; j += 2)
			mark_core_as_ready(iforce, get_unaligned_le16(data + j));

#ifdef CONFIG_JOYSTICK_IFORCE_232
		iforce->expect_packet = FF_CMD_QUERY;
		iforce_send_packet(iforce, FF_CMD_QUERY, packet);

		wait_event_interruptible_timeout(iforce->wait,
			!iforce->expect_packet, HZ);

		if (iforce->expect_packet) {
			iforce->expect_packet = 0;
			return -1;
		}
#else
		dev_err(&iforce->dev->dev,
			"iforce_get_id_packet: iforce->bus = SERIO!\n");
#endif
		break;

	default:
		dev_err(&iforce->dev->dev,
			"iforce_get_id_packet: iforce->bus = %d\n",
			iforce->bus);
		break;
	}

	return -(iforce->edata[0] != packet[0]);
}
EXPORT_SYMBOL(iforce_process_packet);
+124 −37
Original line number Diff line number Diff line
@@ -21,10 +21,26 @@
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/serio.h>
#include "iforce.h"

void iforce_serial_xmit(struct iforce *iforce)
struct iforce_serio {
	struct iforce iforce;

	struct serio *serio;
	int idx, pkt, len, id;
	u8 csum;
	u8 expect_packet;
	u8 cmd_response[IFORCE_MAX_LENGTH];
	u8 cmd_response_len;
	u8 data_in[IFORCE_MAX_LENGTH];
};

static void iforce_serio_xmit(struct iforce *iforce)
{
	struct iforce_serio *iforce_serio = container_of(iforce,
							 struct iforce_serio,
							 iforce);
	unsigned char cs;
	int i;
	unsigned long flags;
@@ -45,19 +61,20 @@ void iforce_serial_xmit(struct iforce *iforce)

	cs = 0x2b;

	serio_write(iforce->serio, 0x2b);
	serio_write(iforce_serio->serio, 0x2b);

	serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
	serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]);
	cs ^= iforce->xmit.buf[iforce->xmit.tail];
	XMIT_INC(iforce->xmit.tail, 1);

	for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
		serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
		serio_write(iforce_serio->serio,
			    iforce->xmit.buf[iforce->xmit.tail]);
		cs ^= iforce->xmit.buf[iforce->xmit.tail];
		XMIT_INC(iforce->xmit.tail, 1);
	}

	serio_write(iforce->serio, cs);
	serio_write(iforce_serio->serio, cs);

	if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
		goto again;
@@ -67,54 +84,118 @@ void iforce_serial_xmit(struct iforce *iforce)
	spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}

static int iforce_serio_get_id(struct iforce *iforce, u8 id,
			       u8 *response_data, size_t *response_len)
{
	struct iforce_serio *iforce_serio = container_of(iforce,
							 struct iforce_serio,
							 iforce);

	iforce_serio->expect_packet = HI(FF_CMD_QUERY);
	iforce_serio->cmd_response_len = 0;

	iforce_send_packet(iforce, FF_CMD_QUERY, &id);

	wait_event_interruptible_timeout(iforce->wait,
					 !iforce_serio->expect_packet, HZ);

	if (iforce_serio->expect_packet) {
		iforce_serio->expect_packet = 0;
		return -ETIMEDOUT;
	}

	if (iforce_serio->cmd_response[0] != id)
		return -EIO;

	memcpy(response_data, iforce_serio->cmd_response,
	       iforce_serio->cmd_response_len);
	*response_len = iforce_serio->cmd_response_len;

	return 0;
}

static int iforce_serio_start_io(struct iforce *iforce)
{
	/* No special handling required */
	return 0;
}

static void iforce_serio_stop_io(struct iforce *iforce)
{
	//TODO: Wait for the last packets to be sent
}

static const struct iforce_xport_ops iforce_serio_xport_ops = {
	.xmit		= iforce_serio_xmit,
	.get_id		= iforce_serio_get_id,
	.start_io	= iforce_serio_start_io,
	.stop_io	= iforce_serio_stop_io,
};

static void iforce_serio_write_wakeup(struct serio *serio)
{
	struct iforce *iforce = serio_get_drvdata(serio);

	iforce_serial_xmit(iforce);
	iforce_serio_xmit(iforce);
}

static irqreturn_t iforce_serio_irq(struct serio *serio,
				    unsigned char data, unsigned int flags)
{
	struct iforce *iforce = serio_get_drvdata(serio);
	struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
	struct iforce *iforce = &iforce_serio->iforce;

	if (!iforce->pkt) {
	if (!iforce_serio->pkt) {
		if (data == 0x2b)
			iforce->pkt = 1;
			iforce_serio->pkt = 1;
		goto out;
	}

	if (!iforce->id) {
	if (!iforce_serio->id) {
		if (data > 3 && data != 0xff)
			iforce->pkt = 0;
			iforce_serio->pkt = 0;
		else
			iforce->id = data;
			iforce_serio->id = data;
		goto out;
	}

	if (!iforce->len) {
	if (!iforce_serio->len) {
		if (data > IFORCE_MAX_LENGTH) {
			iforce->pkt = 0;
			iforce->id = 0;
			iforce_serio->pkt = 0;
			iforce_serio->id = 0;
		} else {
			iforce->len = data;
			iforce_serio->len = data;
		}
		goto out;
	}

	if (iforce->idx < iforce->len) {
		iforce->csum += iforce->data[iforce->idx++] = data;
	if (iforce_serio->idx < iforce_serio->len) {
		iforce_serio->data_in[iforce_serio->idx++] = data;
		iforce_serio->csum += data;
		goto out;
	}

	if (iforce->idx == iforce->len) {
		iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
		iforce->pkt = 0;
		iforce->id  = 0;
		iforce->len = 0;
		iforce->idx = 0;
		iforce->csum = 0;
	if (iforce_serio->idx == iforce_serio->len) {
		/* Handle command completion */
		if (iforce_serio->expect_packet == iforce_serio->id) {
			iforce_serio->expect_packet = 0;
			memcpy(iforce_serio->cmd_response,
			       iforce_serio->data_in, IFORCE_MAX_LENGTH);
			iforce_serio->cmd_response_len = iforce_serio->len;

			/* Signal that command is done */
			wake_up(&iforce->wait);
		} else if (likely(iforce->type)) {
			iforce_process_packet(iforce, iforce_serio->id,
					      iforce_serio->data_in,
					      iforce_serio->len);
		}

		iforce_serio->pkt = 0;
		iforce_serio->id  = 0;
		iforce_serio->len = 0;
		iforce_serio->idx = 0;
		iforce_serio->csum = 0;
	}
out:
	return IRQ_HANDLED;
@@ -122,23 +203,23 @@ static irqreturn_t iforce_serio_irq(struct serio *serio,

static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
{
	struct iforce *iforce;
	struct iforce_serio *iforce_serio;
	int err;

	iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL);
	if (!iforce)
	iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL);
	if (!iforce_serio)
		return -ENOMEM;

	iforce->bus = IFORCE_232;
	iforce->serio = serio;
	iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops;

	serio_set_drvdata(serio, iforce);
	iforce_serio->serio = serio;
	serio_set_drvdata(serio, iforce_serio);

	err = serio_open(serio, drv);
	if (err)
		goto fail1;

	err = iforce_init_device(iforce);
	err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce);
	if (err)
		goto fail2;

@@ -146,18 +227,18 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)

 fail2:	serio_close(serio);
 fail1:	serio_set_drvdata(serio, NULL);
	kfree(iforce);
	kfree(iforce_serio);
	return err;
}

static void iforce_serio_disconnect(struct serio *serio)
{
	struct iforce *iforce = serio_get_drvdata(serio);
	struct iforce_serio *iforce_serio = serio_get_drvdata(serio);

	input_unregister_device(iforce->dev);
	input_unregister_device(iforce_serio->iforce.dev);
	serio_close(serio);
	serio_set_drvdata(serio, NULL);
	kfree(iforce);
	kfree(iforce_serio);
}

static const struct serio_device_id iforce_serio_ids[] = {
@@ -183,3 +264,9 @@ struct serio_driver iforce_serio_drv = {
	.connect	= iforce_serio_connect,
	.disconnect	= iforce_serio_disconnect,
};

module_serio_driver(iforce_serio_drv);

MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver");
MODULE_LICENSE("GPL");
Loading