linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Peta Blaha <blahapeta@gmail.com>
To: linux-input@vger.kernel.org, linux-usb@vger.kernel.org
Subject: [PATCH] input/joystick: add driver fortius 1942
Date: Mon, 16 Mar 2009 23:20:09 +0100	[thread overview]
Message-ID: <739e73230903161520j154edf4eq9fb308d4a67b001c@mail.gmail.com> (raw)
In-Reply-To: <739e73230903161446k1c8326dfwa817f14afb3749ee@mail.gmail.com>

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

Driver for Fortius 1942 device.

Signed-off-by: Petr Blaha <blahapeta@gmail.com>

---

Hi,
 i wrote driver for Fortius 1942 by re-ingeneering original driver for
win.This is a bicycle from Tacx company, they have their own virtual
reality sw. There is not linux support from this company.
http://www.tacxvr.com/en/products/tacx-virtual-reality
This driver handle bike as normal joystick, it is connected thru USB,
this driver isn't for initializating, it is too complex for me.
here is more info
http://code.google.com/p/fortius/

I would like to merge my work into kernel, is it ok?

Petr

[-- Attachment #2: fortius_1942 --]
[-- Type: application/octet-stream, Size: 9627 bytes --]

--- ./linux-2.6/drivers/input/joystick/fortius_1942.c.orig	1970-01-01 01:00:00.000000000 +0100
+++ ./linux-2.6/drivers/input/joystick/fortius_1942.c	2009-03-16 18:14:53.000000000 +0100
@@ -0,0 +1,348 @@
+/*This driver is under GPL version 2 or any later.No warranty. 
+Look at http://www.gnu.org/licenses/ */
+
+
+/*
+Info for future developers
+Heart Sensor use bit 12 and 14(beginning 0), maybe 13 also.
+*/
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <linux/time.h>
+
+
+#define DRIVER_VERSION "v0.0.2"
+#define DRIVER_DESC    "USB Tacx Fortius 1942 driver"
+#define DRIVER_LICENSE "GPL"
+#define DRIVER_AUTHOR  "Petr Blaha <blahapeta@gmail.com>"
+
+
+/*Don't put here lesser values*/
+#define BIT_IN_DEVICE_1942	64 //read
+#define	BIT_OUT_DEVICE_1942	12 //write
+
+#define BULK_IN_INTERFACE_1942	82 //read
+#define BULK_OUT_INTERFACE_1942	02 //write
+
+
+#define BRAKE_POS 2
+
+
+/*11 states of brake,in beginning active brake helps, later add difficulty to cycling. 0x00 0x00 is neutral*/
+#define ARRAYINT { {0x4d,0xf3}, {0xa7,0xf9}, {0x00,0x00}, {0x59,0x06}, {0xb3,0x0c}, {0x0c,0x13}, {0x66,0x19}, {0xbf,0x1f}, {0x18,0x26}, {0x72,0x2c}, {0xcb,0x32} }
+
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+	unsigned long difference=0;
+	/*time measure*/
+	struct timeval	time,time_before;
+	/*guessed fastest speed a man can possibly ride-incitating full throttle*/
+	unsigned int fastest_wheel_rotate= 1000;
+	/*actual state of path reached in one cycle*/
+	unsigned int ride = 0, old_ride=0;
+
+struct usb_tfor {
+	char name[128];
+	char phys[64]; 
+	struct usb_device *usbdev;
+	struct input_dev *input; 
+
+	struct urb *irq;
+	unsigned char *data;
+	dma_addr_t idata_dma;
+
+	struct urb *out;
+	unsigned char *data_device;
+	dma_addr_t odata_dma;
+	/*brake position*/
+	unsigned int brake_pos;
+};
+
+static void tfor_disconnect(struct usb_interface *intf)
+{
+	struct usb_tfor *tfor = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (tfor) {
+		/*urb*/
+		usb_kill_urb(tfor->out);
+		usb_kill_urb(tfor->irq);
+		/*device*/
+		input_unregister_device(tfor->input);
+		/*urb*/
+		usb_free_urb(tfor->out);
+		usb_free_urb(tfor->irq);
+		/*buffer free*/
+		usb_buffer_free(interface_to_usbdev(intf), 10, tfor->data_device, tfor->odata_dma);
+		usb_buffer_free(interface_to_usbdev(intf), 10, tfor->data, tfor->idata_dma);
+		/*free memory*/
+		kfree(tfor);
+	}
+}
+
+static int usb_tfor_open(struct input_dev *dev)
+{
+	struct usb_tfor *tfor = input_get_drvdata(dev);
+	tfor->irq->dev = tfor->usbdev;
+	usb_submit_urb(tfor->irq, GFP_KERNEL);
+	tfor->out->dev = tfor->usbdev;
+	usb_submit_urb(tfor->out, GFP_KERNEL);
+
+	return 0;
+}
+
+static void usb_tfor_close(struct input_dev *dev)
+{
+	struct usb_tfor *tfor = input_get_drvdata(dev);
+	usb_kill_urb(tfor->irq);
+	usb_kill_urb(tfor->out);
+}
+
+static struct usb_device_id tfor_ids[] = {
+	{ USB_DEVICE(0x3561, 0x1942), .driver_info = 0 },
+	{ }
+};
+
+static void usb_tfor_out(struct urb *urb)
+{	struct usb_tfor *tfor = urb->context;
+	unsigned int brake_bits[11][2] = ARRAYINT;
+	int retval;
+	tfor->brake_pos =BRAKE_POS;
+	/*URB to device*/
+	/*constant*/
+	tfor->data_device[0] =	0x01; 
+	/*constant*/
+	tfor->data_device[1] =	0x08; 
+	/*constant*/
+	tfor->data_device[2] =	0x01; 
+	/*constant*/
+	tfor->data_device[3] =	0x00; 
+	/*brake_bits*/
+	tfor->data_device[4] =	brake_bits[tfor->brake_pos][0];
+	/*brake_bits*/
+	tfor->data_device[5] =	brake_bits[tfor->brake_pos][1];
+	/*0x01 is turn,when frame sensor meets pedal magnet,
+	 i don't see reason for implementation */
+	tfor->data_device[6] =	0x00;
+	/*constant*/
+	tfor->data_device[7] =	0x00;
+	/*constant*/
+	tfor->data_device[8] =	0x02;
+	/*constant*/
+	tfor->data_device[9] =	0x52;
+	/*constant*/
+	tfor->data_device[10] =	0x10;
+	/*constant*/
+	tfor->data_device[11] =	0x04;
+
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+		break;
+	default:
+		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+	}
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result %d",
+		    __func__, retval);
+}
+
+static void usb_tfor_irq(struct urb *urb)
+{
+	struct usb_tfor *tfor = urb->context;
+	unsigned char *data = tfor->data;
+	struct input_dev *dev = tfor->input;
+	int status;
+	int gasolina;
+	
+	switch (urb->status) {
+		case 0:
+			/* success */
+			break;
+		case -ECONNRESET:
+		case -ENOENT:
+		case -ESHUTDOWN:
+			/* ±this urb is terminated, clean up */
+			dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+			return;
+		default:
+			dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+			goto resubmit;
+	}
+		
+		/*Get actual time*/
+		do_gettimeofday(&time);
+		/*Ride counter in velociped is small,avoid mistake here*/
+		if((data[28]*255+data[29])<ride) ride =0;
+		/*If we get new data, set new values of ride counter and time counter*/
+		if((data[28]*255+data[29])>ride) {
+			old_ride = ride;
+			ride = (data[28]*255+data[29]);
+			difference=((time.tv_usec-time_before.tv_usec)+(time.tv_sec-time_before.tv_sec)*1000000);
+			do_gettimeofday(&time_before); 
+			if(difference==0)
+				dbg("Something is not good \n");
+			}
+	/*Prevent division by 0*/
+	if(difference!=0)
+		/*"speed=path/time",change constant 1000
+		   to naturalize it for your speed*/
+		gasolina=(ride-old_ride)/(difference/1000);
+	else gasolina =0;	
+	input_report_abs(dev, ABS_GAS,gasolina);
+	input_report_key(dev, BTN_RIGHT,   data[13] & 0x01);
+	input_report_key(dev, BTN_BACK  ,  data[13] & 0x02);
+	input_report_key(dev, BTN_FORWARD,      data[13] & 0x04);
+	input_report_key(dev, BTN_LEFT,  data[13] & 0x08);
+	input_report_abs(dev, ABS_WHEEL,(((data[18]+((data[19] & 0x0f)*225))-(689+170))*-1));
+
+	/* event termination */
+	input_sync(dev); 
+
+resubmit:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status)
+		err("can't resubmit intr, %s-%s/input0, status %d",
+			tfor->usbdev->bus->bus_name, tfor->usbdev->devpath, status);
+
+}
+
+static int tfor_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_tfor *tfor;
+	struct input_dev *input_dev;
+	unsigned int err = -ENOMEM;
+	
+
+	tfor = kzalloc(sizeof(struct usb_tfor), GFP_KERNEL);
+
+	input_dev = input_allocate_device();
+	if (!tfor || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+	/*initilization of time counter*/	
+	do_gettimeofday(&time);
+	time_before.tv_usec=time.tv_usec;
+	time_before.tv_sec=time.tv_sec;
+
+	tfor->data = usb_buffer_alloc(dev, BIT_IN_DEVICE_1942, GFP_KERNEL, &tfor->idata_dma);
+	if (!tfor->data) {
+		err= -ENOMEM;
+		goto fail1;
+	}
+
+	tfor->data_device = usb_buffer_alloc(dev, BIT_OUT_DEVICE_1942,GFP_KERNEL, &tfor->odata_dma);
+	if (!tfor->data_device) {
+		err= -ENOMEM;
+		goto fail1;
+	}
+
+	tfor->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!tfor->irq) {
+		err = -ENOMEM;
+		goto fail2;
+	}
+
+	tfor->out = usb_alloc_urb(0, GFP_KERNEL);
+	if (!tfor->irq) {
+		err = -ENOMEM;
+		goto fail3;
+	}
+
+	tfor->usbdev = dev;
+	tfor->input = input_dev;
+
+	usb_make_path(dev, tfor->phys, sizeof(tfor->phys));
+	strlcat(tfor->phys, "/input0", sizeof(tfor->phys));
+
+	input_dev->name = "Tacx Fortius 1942";
+	input_dev->phys = tfor->phys;
+	usb_to_input_id(dev, &input_dev->id); 
+	input_dev->dev.parent = &intf->dev;
+	input_set_drvdata(input_dev, tfor);
+	input_dev->open = usb_tfor_open;
+	input_dev->close = usb_tfor_close;
+	input_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);// | BIT_MASK(EV_MSC) | BIT_MASK(EV_FF_STATUS);
+	/*handlebar*/
+	input_set_abs_params(input_dev,ABS_WHEEL,-170,170,0,20);
+	/*plyn*/
+	input_set_abs_params(input_dev,ABS_GAS,0,40,2,0);
+	/*buttons*/
+	set_bit(BTN_LEFT,    input_dev->keybit);
+    	set_bit(BTN_RIGHT,  input_dev->keybit);
+	set_bit(BTN_FORWARD, input_dev->keybit);
+    	set_bit(BTN_BACK,  input_dev->keybit);
+
+	usb_fill_bulk_urb(tfor->irq, dev, usb_rcvbulkpipe(dev, BULK_IN_INTERFACE_1942),tfor->data,BIT_IN_DEVICE_1942,usb_tfor_irq, tfor);
+	tfor->irq->transfer_dma = tfor->idata_dma;
+	tfor->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/*
+	* urb sends data to machine
+	*/
+
+	usb_fill_bulk_urb(tfor->out, dev,
+				usb_sndbulkpipe(dev, BULK_OUT_INTERFACE_1942),
+				tfor->data_device, BIT_OUT_DEVICE_1942, usb_tfor_out, tfor);
+	tfor->out->transfer_dma = tfor->odata_dma;
+	tfor->out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+	err = input_register_device(tfor->input);
+		if (err)
+			goto fail2;
+
+	usb_set_intfdata(intf, tfor);
+	
+
+	return 0;
+
+ fail3:	usb_buffer_free(dev, BIT_OUT_DEVICE_1942, tfor->data_device, tfor->odata_dma);
+ fail2:	usb_buffer_free(dev, BIT_IN_DEVICE_1942, tfor->data, tfor->idata_dma);
+ fail1: input_free_device(input_dev);
+	kfree(tfor);
+	return err;
+}
+
+static struct usb_driver tfor_driver = {
+	.name =		"tfor",
+	.probe =	tfor_probe,
+	.disconnect =	tfor_disconnect,
+	.id_table =	tfor_ids,
+};
+
+static int __init tfor_init(void)
+{
+	int retval;
+	retval = usb_register(&tfor_driver);
+	if (retval)
+		goto out;
+	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n");
+out:
+	return retval;
+}
+
+static void __exit tfor_exit(void)
+{
+	usb_deregister(&tfor_driver);
+}
+
+module_init(tfor_init);
+module_exit(tfor_exit);

       reply	other threads:[~2009-03-16 22:20 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <739e73230903161446k1c8326dfwa817f14afb3749ee@mail.gmail.com>
2009-03-16 22:20 ` Peta Blaha [this message]
2009-03-16 22:39   ` [PATCH] input/joystick: add driver fortius 1942 Greg KH
2009-03-17  2:21 Peta Blaha
     [not found] ` <739e73230903161921u426f2c65gddbc089d25ba5d50-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-03-17  2:25   ` Greg KH
2009-03-21  5:46   ` Dmitry Torokhov
  -- strict thread matches above, loose matches on Subject: below --
2009-03-19 13:51 Peta Blaha
     [not found] ` <739e73230903190651w4fff7aaen818a42540ffbdc8d-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-03-19 13:39   ` Felipe Balbi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=739e73230903161520j154edf4eq9fb308d4a67b001c@mail.gmail.com \
    --to=blahapeta@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).