aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Taht <d@teklibre.com>2008-12-17 20:13:45 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-06 16:52:36 -0500
commit8da3dc28753ece6b7ddae9d5897a0ad0797e21e6 (patch)
treedf9f694ef05bfad2cc9d05f55fb46693e713b36e /drivers
parent1242c70df56978e8abbf715a02fb1c55313f8471 (diff)
Staging: add frontier tranzport and alphatrack drivers
Adds the tranzport and alphatrack drivers to the staging tree. Cc: David Taht <d@teklibre.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/frontier/Kconfig6
-rw-r--r--drivers/staging/frontier/Makefile2
-rw-r--r--drivers/staging/frontier/README28
-rw-r--r--drivers/staging/frontier/TODO9
-rw-r--r--drivers/staging/frontier/alphatrack.c901
-rw-r--r--drivers/staging/frontier/alphatrack.h117
-rw-r--r--drivers/staging/frontier/alphatrack_sysfs.c279
-rw-r--r--drivers/staging/frontier/frontier_compat.h63
-rw-r--r--drivers/staging/frontier/surface_sysfs.h100
-rw-r--r--drivers/staging/frontier/tranzport.c1017
12 files changed, 2525 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e2f57e9b694c..15f2b1148df3 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -89,5 +89,7 @@ source "drivers/staging/rspiusb/Kconfig"
89 89
90source "drivers/staging/mimio/Kconfig" 90source "drivers/staging/mimio/Kconfig"
91 91
92source "drivers/staging/frontier/Kconfig"
93
92endif # !STAGING_EXCLUDE_BUILD 94endif # !STAGING_EXCLUDE_BUILD
93endif # STAGING 95endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 94efc9df5a85..d33803092b62 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/
27obj-$(CONFIG_RTL8187SE) += rtl8187se/ 27obj-$(CONFIG_RTL8187SE) += rtl8187se/
28obj-$(CONFIG_USB_RSPI) += rspiusb/ 28obj-$(CONFIG_USB_RSPI) += rspiusb/
29obj-$(CONFIG_INPUT_MIMIO) += mimio/ 29obj-$(CONFIG_INPUT_MIMIO) += mimio/
30obj-$(CONFIG_TRANZPORT) += frontier/
diff --git a/drivers/staging/frontier/Kconfig b/drivers/staging/frontier/Kconfig
new file mode 100644
index 000000000000..7121853bd397
--- /dev/null
+++ b/drivers/staging/frontier/Kconfig
@@ -0,0 +1,6 @@
1config TRANZPORT
2 tristate "Frontier Tranzport and Alphatrack support"
3 depends on USB
4 default N
5 ---help---
6 Enable support for the Frontier Tranzport and Alphatrack devices.
diff --git a/drivers/staging/frontier/Makefile b/drivers/staging/frontier/Makefile
new file mode 100644
index 000000000000..2d2ac97492dd
--- /dev/null
+++ b/drivers/staging/frontier/Makefile
@@ -0,0 +1,2 @@
1obj-$(CONFIG_TRANZPORT) += tranzport.o
2obj-$(CONFIG_TRANZPORT) += alphatrack.o
diff --git a/drivers/staging/frontier/README b/drivers/staging/frontier/README
new file mode 100644
index 000000000000..07c9ef9b8fc4
--- /dev/null
+++ b/drivers/staging/frontier/README
@@ -0,0 +1,28 @@
1This directory contains the USB Tranzport and Alphatrack Kernel drivers for Linux.
2
3At present the tranzport does reads/writes of 8 byte cmds to /dev/tranzport0 to control
4the lights and screen and wheel
5
6At present the alphatrack accepts reads/writes of 12 byte cmds to /dev/tranzport0 to control
7the lights and screen and fader.
8
9Both drivers also have some sysfs hooks that are non-functional at the moment.
10
11The API is currently closely tied to the ardour revision and WILL change.
12
13A sysfs interface is PERFECT for simple userspace apps to do fun things with the
14lights and screen. It's fairly lousy for handling input events and very lousy
15for watching the state of the shuttle wheel.
16
17A linux input events interface is great for the input events and shuttle wheel. It's
18theoretically OK on LEDs. A Fader can be mapped to an absolute mouse device.
19But there is no LCD support at all.
20
21In the end this is going to be driven by a midi layer, which handles all those
22cases via a defined API, but - among other things - is slow, doesn't do
23flow control, and is a LOT of extra work. Frankly, I'd like to keep the
24core driver simple because the only realtime work really required is
25the bottom half interrupt handler and the output overlapping.
26
27Exposing some sort of clean aio api to userspace would be perfect. What that
28API looks like? Gah. beats me.
diff --git a/drivers/staging/frontier/TODO b/drivers/staging/frontier/TODO
new file mode 100644
index 000000000000..3620ad2df3ee
--- /dev/null
+++ b/drivers/staging/frontier/TODO
@@ -0,0 +1,9 @@
1TODO:
2 - checkpatch.pl clean
3 - sparse clean
4 - fix userspace interface to be sane
5 - possibly just port to userspace with libusb
6 - review by the USB developer community
7
8Please send any patches for this driver to Greg Kroah-Hartman <greg@kroah.com>
9and David Taht <d@teklibre.com>.
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
new file mode 100644
index 000000000000..efc2345a676b
--- /dev/null
+++ b/drivers/staging/frontier/alphatrack.c
@@ -0,0 +1,901 @@
1/*
2 * Frontier Designs Alphatrack driver
3 *
4 * Copyright (C) 2007 Michael Taht (m@taht.net)
5 *
6 * Based on the usbled driver and ldusb drivers by
7 *
8 * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
9 * Copyright (C) 2005 Michael Hund <mhund@ld-didactic.de>
10 *
11 * The ldusb driver was, in turn, derived from Lego USB Tower driver
12 * Copyright (C) 2003 David Glance <advidgsf@sourceforge.net>
13 * 2001-2004 Juergen Stuber <starblue@users.sourceforge.net>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation, version 2.
18 *
19 */
20
21/**
22 * This driver uses a ring buffer for time critical reading of
23 * interrupt in reports and provides read and write methods for
24 * raw interrupt reports.
25 */
26
27/* Note: this currently uses a dumb ringbuffer for reads and writes.
28 * A more optimal driver would cache and kill off outstanding urbs that are
29 * now invalid, and ignore ones that already were in the queue but valid
30 * as we only have 30 commands for the alphatrack. In particular this is
31 * key for getting lights to flash in time as otherwise many commands
32 * can be buffered up before the light change makes it to the interface.
33*/
34
35#include <linux/kernel.h>
36#include <linux/errno.h>
37#include <linux/init.h>
38#include <linux/slab.h>
39#include <linux/module.h>
40#include <linux/kobject.h>
41#include <linux/mutex.h>
42#include <linux/version.h>
43
44#include <asm/uaccess.h>
45#include <linux/input.h>
46#include <linux/usb.h>
47#include <linux/poll.h>
48
49#include "surface_sysfs.h"
50
51/* make this work on older kernel versions */
52
53#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
54#include "frontier_compat.h"
55#endif /* older kernel versions */
56
57#include "alphatrack.h"
58
59#define VENDOR_ID 0x165b
60#define PRODUCT_ID 0xfad1
61
62#ifdef CONFIG_USB_DYNAMIC_MINORS
63#define USB_ALPHATRACK_MINOR_BASE 0
64#else
65// FIXME 176 - is another driver's minor - apply for that
66// #define USB_ALPHATRACK_MINOR_BASE 177
67#define USB_ALPHATRACK_MINOR_BASE 176
68#endif
69
70/* table of devices that work with this driver */
71static struct usb_device_id usb_alphatrack_table [] = {
72 { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
73 { } /* Terminating entry */
74};
75
76MODULE_DEVICE_TABLE(usb, usb_alphatrack_table);
77MODULE_VERSION("0.40");
78MODULE_AUTHOR("Mike Taht <m@taht.net>");
79MODULE_DESCRIPTION("Alphatrack USB Driver");
80MODULE_LICENSE("GPL");
81MODULE_SUPPORTED_DEVICE("Frontier Designs Alphatrack Control Surface");
82
83/* These aren't done yet */
84
85#define ALPHATRACK_HAVE_SYSFS 0
86#define SUPPRESS_EXTRA_ONLINE_EVENTS 0
87#define BUFFERED_WRITES 0
88#define SUPPRESS_EXTRA_OFFLINE_EVENTS 0
89#define COMPRESS_FADER_EVENTS 0
90
91#define BUFFERED_READS 1
92#define RING_BUFFER_SIZE 512
93#define WRITE_BUFFER_SIZE 34
94#define ALPHATRACK_USB_TIMEOUT 10
95#define OUTPUT_CMD_SIZE 8
96#define INPUT_CMD_SIZE 12
97
98
99static int debug = 0;
100
101/* Use our own dbg macro */
102#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
103
104#if 0
105#define alphatrack_ocmd_info(dev, cmd, format, arg...) do { if (debug) ocmd_info(dev , cmd , format, ## arg); } while (0)
106
107#define alphatrack_icmd_info(dev, cmd, format, arg...) do { if (debug) icmd_info(dev , cmd, format, ## arg); } while (0)
108#else
109#define alphatrack_ocmd_info(dev, cmd, format, arg...)
110
111#define alphatrack_icmd_info(dev, cmd, format, arg...)
112
113#endif
114
115/* Module parameters */
116
117module_param(debug, int, S_IRUGO | S_IWUSR);
118MODULE_PARM_DESC(debug, "Debug enabled or not");
119
120/* All interrupt in transfers are collected in a ring buffer to
121 * avoid racing conditions and get better performance of the driver.
122 */
123
124static int ring_buffer_size = RING_BUFFER_SIZE;
125
126module_param(ring_buffer_size, int, S_IRUGO);
127MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size");
128
129/* The write_buffer can one day contain more than one interrupt out transfer.
130 */
131
132static int write_buffer_size = WRITE_BUFFER_SIZE;
133module_param(write_buffer_size, int, S_IRUGO);
134MODULE_PARM_DESC(write_buffer_size, "Write buffer size");
135
136/*
137 * Increase the interval for debugging purposes.
138 * or set to 1 to use the standard interval from the endpoint descriptors.
139 */
140
141static int min_interrupt_in_interval = ALPHATRACK_USB_TIMEOUT;
142module_param(min_interrupt_in_interval, int, 0);
143MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms");
144
145static int min_interrupt_out_interval = ALPHATRACK_USB_TIMEOUT;
146module_param(min_interrupt_out_interval, int, 0);
147MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms");
148
149
150
151/* Structure to hold all of our device specific stuff */
152
153struct usb_alphatrack {
154 struct semaphore sem; /* locks this structure */
155 struct usb_interface* intf; /* save off the usb interface pointer */
156 int open_count; /* number of times this port has been opened */
157
158 struct alphatrack_icmd (*ring_buffer)[RING_BUFFER_SIZE]; /* just make c happy */
159 struct alphatrack_ocmd (*write_buffer)[WRITE_BUFFER_SIZE]; /* just make c happy */
160 unsigned int ring_head;
161 unsigned int ring_tail;
162
163 wait_queue_head_t read_wait;
164 wait_queue_head_t write_wait;
165
166 unsigned char* interrupt_in_buffer;
167 unsigned char* oldi_buffer;
168 struct usb_endpoint_descriptor* interrupt_in_endpoint;
169 struct urb* interrupt_in_urb;
170 int interrupt_in_interval;
171 size_t interrupt_in_endpoint_size;
172 int interrupt_in_running;
173 int interrupt_in_done;
174
175 char* interrupt_out_buffer;
176 struct usb_endpoint_descriptor* interrupt_out_endpoint;
177 struct urb* interrupt_out_urb;
178 int interrupt_out_interval;
179 size_t interrupt_out_endpoint_size;
180 int interrupt_out_busy;
181
182 atomic_t writes_pending;
183 int event; /* alternate interface to events */
184 int fader; /* 10 bits */
185 int lights; /* 23 bits */
186 unsigned char dump_state; /* 0 if disabled 1 if enabled */
187 unsigned char enable; /* 0 if disabled 1 if enabled */
188 unsigned char offline; /* if the device is out of range or asleep */
189 unsigned char verbose; /* be verbose in error reporting */
190 unsigned char last_cmd[OUTPUT_CMD_SIZE];
191 unsigned char screen[32];
192};
193
194/* prevent races between open() and disconnect() */
195static DEFINE_MUTEX(disconnect_mutex);
196
197/* forward declaration */
198
199static struct usb_driver usb_alphatrack_driver;
200
201static void icmd_info(struct usb_alphatrack *dev, char *cmd, char *str, char *a) {
202/*
203if (dev->verbose) {
204} else {
205}
206*/
207}
208
209static void ocmd_info(struct usb_alphatrack *dev, char *cmd, char *str, char* a) {
210/*
211if (dev->verbose) {
212} else {
213}
214*/
215}
216
217
218/**
219 * usb_alphatrack_abort_transfers
220 * aborts transfers and frees associated data structures
221 */
222static void usb_alphatrack_abort_transfers(struct usb_alphatrack *dev)
223{
224 /* shutdown transfer */
225 if (dev->interrupt_in_running) {
226 dev->interrupt_in_running = 0;
227 if (dev->intf)
228 usb_kill_urb(dev->interrupt_in_urb);
229 }
230 if (dev->interrupt_out_busy)
231 if (dev->intf)
232 usb_kill_urb(dev->interrupt_out_urb);
233}
234
235#if ALPHATRACK_HAVE_SYSFS
236/* lots and lots and lots of sysfs stuff */
237/* Currently borked, probably useless */
238#include "alphatrack_sysfs.c"
239#endif
240
241/**
242 * usb_alphatrack_delete
243 */
244static void usb_alphatrack_delete(struct usb_alphatrack *dev)
245{
246 usb_alphatrack_abort_transfers(dev);
247 usb_free_urb(dev->interrupt_in_urb);
248 usb_free_urb(dev->interrupt_out_urb);
249 kfree(dev->ring_buffer);
250 kfree(dev->interrupt_in_buffer);
251 kfree(dev->interrupt_out_buffer);
252 kfree(dev); // fixme oldi_buffer
253}
254
255/**
256 * usb_alphatrack_interrupt_in_callback
257 */
258
259static void usb_alphatrack_interrupt_in_callback(struct urb *urb)
260{
261 struct usb_alphatrack *dev = urb->context;
262 unsigned int next_ring_head;
263 int retval = -1;
264 int *iptr;
265
266 if (urb->status) {
267 if (urb->status == -ENOENT ||
268 urb->status == -ECONNRESET ||
269 urb->status == -ESHUTDOWN) {
270 goto exit;
271 } else {
272 dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
273 __FUNCTION__, urb->status);
274 goto resubmit; /* maybe we can recover */
275 }
276 }
277
278 if (urb->actual_length != INPUT_CMD_SIZE) {
279 dev_warn(&dev->intf->dev,
280 "Urb length was %d bytes!! Do something intelligent \n", urb->actual_length);
281 } else {
282 alphatrack_ocmd_info(&dev->intf->dev,&(*dev->ring_buffer)[dev->ring_tail].cmd,"%s", "bla");
283 if(memcmp(dev->interrupt_in_buffer,dev->oldi_buffer,INPUT_CMD_SIZE)==0) {
284 goto resubmit;
285 }
286 memcpy(dev->oldi_buffer,dev->interrupt_in_buffer,INPUT_CMD_SIZE);
287
288#if SUPPRESS_EXTRA_OFFLINE_EVENTS
289 if(dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) { goto resubmit; }
290 if(dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 2; goto resubmit; }
291/* Always pass one offline event up the stack */
292 if(dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) { dev->offline = 0; }
293 if(dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 1; }
294#endif
295 dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
296 next_ring_head = (dev->ring_head+1) % ring_buffer_size;
297
298 if (next_ring_head != dev->ring_tail) {
299 memcpy(&((*dev->ring_buffer)[dev->ring_head]),
300 dev->interrupt_in_buffer, urb->actual_length);
301 dev->ring_head = next_ring_head;
302 retval = 0;
303 memset(dev->interrupt_in_buffer, 0, urb->actual_length);
304 } else {
305 dev_warn(&dev->intf->dev,
306 "Ring buffer overflow, %d bytes dropped\n",
307 urb->actual_length);
308 memset(dev->interrupt_in_buffer, 0, urb->actual_length);
309 }
310 }
311
312resubmit:
313 /* resubmit if we're still running */
314 if (dev->interrupt_in_running && dev->intf) {
315 retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
316 if (retval)
317 dev_err(&dev->intf->dev,
318 "usb_submit_urb failed (%d)\n", retval);
319 }
320
321exit:
322 dev->interrupt_in_done = 1;
323 wake_up_interruptible(&dev->read_wait);
324}
325
326/**
327 * usb_alphatrack_interrupt_out_callback
328 */
329static void usb_alphatrack_interrupt_out_callback(struct urb *urb)
330{
331 struct usb_alphatrack *dev = urb->context;
332
333 /* sync/async unlink faults aren't errors */
334 if (urb->status && !(urb->status == -ENOENT ||
335 urb->status == -ECONNRESET ||
336 urb->status == -ESHUTDOWN))
337 dbg_info(&dev->intf->dev,
338 "%s - nonzero write interrupt status received: %d\n",
339 __FUNCTION__, urb->status);
340 atomic_dec(&dev->writes_pending);
341 dev->interrupt_out_busy = 0;
342 wake_up_interruptible(&dev->write_wait);
343}
344
345/**
346 * usb_alphatrack_open
347 */
348static int usb_alphatrack_open(struct inode *inode, struct file *file)
349{
350 struct usb_alphatrack *dev;
351 int subminor;
352 int retval = 0;
353 struct usb_interface *interface;
354
355 nonseekable_open(inode, file);
356 subminor = iminor(inode);
357
358 mutex_lock(&disconnect_mutex);
359
360 interface = usb_find_interface(&usb_alphatrack_driver, subminor);
361
362 if (!interface) {
363 err("%s - error, can't find device for minor %d\n",
364 __FUNCTION__, subminor);
365 retval = -ENODEV;
366 goto unlock_disconnect_exit;
367 }
368
369 dev = usb_get_intfdata(interface);
370
371 if (!dev) {
372 retval = -ENODEV;
373 goto unlock_disconnect_exit;
374 }
375
376 /* lock this device */
377 if (down_interruptible(&dev->sem)) {
378 retval = -ERESTARTSYS;
379 goto unlock_disconnect_exit;
380 }
381
382 /* allow opening only once */
383 if (dev->open_count) {
384 retval = -EBUSY;
385 goto unlock_exit;
386 }
387 dev->open_count = 1;
388
389 /* initialize in direction */
390 dev->ring_head = 0;
391 dev->ring_tail = 0;
392 usb_fill_int_urb(dev->interrupt_in_urb,
393 interface_to_usbdev(interface),
394 usb_rcvintpipe(interface_to_usbdev(interface),
395 dev->interrupt_in_endpoint->bEndpointAddress),
396 dev->interrupt_in_buffer,
397 dev->interrupt_in_endpoint_size,
398 usb_alphatrack_interrupt_in_callback,
399 dev,
400 dev->interrupt_in_interval);
401
402 dev->interrupt_in_running = 1;
403 dev->interrupt_in_done = 0;
404 dev->enable = 1;
405 dev->offline = 0;
406
407 retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
408 if (retval) {
409 dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval);
410 dev->interrupt_in_running = 0;
411 dev->open_count = 0;
412 goto unlock_exit;
413 }
414
415 /* save device in the file's private structure */
416 file->private_data = dev;
417
418
419unlock_exit:
420 up(&dev->sem);
421
422unlock_disconnect_exit:
423 mutex_unlock(&disconnect_mutex);
424
425 return retval;
426}
427
428/**
429 * usb_alphatrack_release
430 */
431static int usb_alphatrack_release(struct inode *inode, struct file *file)
432{
433 struct usb_alphatrack *dev;
434 int retval = 0;
435
436 dev = file->private_data;
437
438 if (dev == NULL) {
439 retval = -ENODEV;
440 goto exit;
441 }
442
443 if (down_interruptible(&dev->sem)) {
444 retval = -ERESTARTSYS;
445 goto exit;
446 }
447
448 if (dev->open_count != 1) {
449 retval = -ENODEV;
450 goto unlock_exit;
451 }
452
453 if (dev->intf == NULL) {
454 /* the device was unplugged before the file was released */
455 up(&dev->sem);
456 /* unlock here as usb_alphatrack_delete frees dev */
457 usb_alphatrack_delete(dev);
458 retval = -ENODEV;
459 goto exit;
460 }
461
462 /* wait until write transfer is finished */
463 if (dev->interrupt_out_busy)
464 wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ);
465 usb_alphatrack_abort_transfers(dev);
466 dev->open_count = 0;
467
468unlock_exit:
469 up(&dev->sem);
470
471exit:
472 return retval;
473}
474
475/**
476 * usb_alphatrack_poll
477 */
478static unsigned int usb_alphatrack_poll(struct file *file, poll_table *wait)
479{
480 struct usb_alphatrack *dev;
481 unsigned int mask = 0;
482
483 dev = file->private_data;
484
485 poll_wait(file, &dev->read_wait, wait);
486 poll_wait(file, &dev->write_wait, wait);
487
488 if (dev->ring_head != dev->ring_tail)
489 mask |= POLLIN | POLLRDNORM;
490 if (!dev->interrupt_out_busy)
491 mask |= POLLOUT | POLLWRNORM;
492
493 return mask;
494}
495
496/**
497 * usb_alphatrack_read
498 */
499static ssize_t usb_alphatrack_read(struct file *file, char __user *buffer, size_t count,
500 loff_t *ppos)
501{
502 struct usb_alphatrack *dev;
503 int retval = 0;
504
505 int c = 0;
506
507 dev = file->private_data;
508
509 /* verify that we actually have some data to read */
510 if (count == 0)
511 goto exit;
512
513 /* lock this object */
514 if (down_interruptible(&dev->sem)) {
515 retval = -ERESTARTSYS;
516 goto exit;
517 }
518
519 /* verify that the device wasn't unplugged */
520 if (dev->intf == NULL) {
521 retval = -ENODEV;
522 err("No device or device unplugged %d\n", retval);
523 goto unlock_exit;
524 }
525
526 while (dev->ring_head == dev->ring_tail) {
527 if (file->f_flags & O_NONBLOCK) {
528 retval = -EAGAIN;
529 goto unlock_exit;
530 }
531 dev->interrupt_in_done = 0 ;
532 retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
533 if (retval < 0) {
534 goto unlock_exit;
535 }
536 }
537
538 alphatrack_ocmd_info(&dev->intf->dev, &(*dev->ring_buffer)[dev->ring_tail].cmd, "%s", ": copying to userspace");
539
540 c = 0;
541 while((c < count) && (dev->ring_tail != dev->ring_head)) {
542 if (copy_to_user(&buffer[c], &(*dev->ring_buffer)[dev->ring_tail], INPUT_CMD_SIZE)) {
543 retval = -EFAULT;
544 goto unlock_exit;
545 }
546 dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
547 c+=INPUT_CMD_SIZE;
548 dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
549 }
550 retval = c;
551
552unlock_exit:
553 /* unlock the device */
554 up(&dev->sem);
555
556exit:
557 return retval;
558}
559
560/**
561 * usb_alphatrack_write
562 */
563static ssize_t usb_alphatrack_write(struct file *file, const char __user *buffer,
564 size_t count, loff_t *ppos)
565{
566 struct usb_alphatrack *dev;
567 size_t bytes_to_write;
568 int retval = 0;
569
570 dev = file->private_data;
571
572 /* verify that we actually have some data to write */
573 if (count == 0)
574 goto exit;
575
576 /* lock this object */
577 if (down_interruptible(&dev->sem)) {
578 retval = -ERESTARTSYS;
579 goto exit;
580 }
581
582 /* verify that the device wasn't unplugged */
583 if (dev->intf == NULL) {
584 retval = -ENODEV;
585 err("No device or device unplugged %d\n", retval);
586 goto unlock_exit;
587 }
588
589 /* wait until previous transfer is finished */
590 if (dev->interrupt_out_busy) {
591 if (file->f_flags & O_NONBLOCK) {
592 retval = -EAGAIN;
593 goto unlock_exit;
594 }
595 retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy);
596 if (retval < 0) {
597 goto unlock_exit;
598 }
599 }
600
601 /* write the data into interrupt_out_buffer from userspace */
602 /* FIXME - if you write more than 12 bytes this breaks */
603 bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
604 if (bytes_to_write < count)
605 dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
606
607 dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
608
609 if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
610 retval = -EFAULT;
611 goto unlock_exit;
612 }
613
614 if (dev->interrupt_out_endpoint == NULL) {
615 err("Endpoint should not be be null! \n");
616 goto unlock_exit;
617 }
618
619 /* send off the urb */
620 usb_fill_int_urb(dev->interrupt_out_urb,
621 interface_to_usbdev(dev->intf),
622 usb_sndintpipe(interface_to_usbdev(dev->intf),
623 dev->interrupt_out_endpoint->bEndpointAddress),
624 dev->interrupt_out_buffer,
625 bytes_to_write,
626 usb_alphatrack_interrupt_out_callback,
627 dev,
628 dev->interrupt_out_interval);
629 dev->interrupt_out_busy = 1;
630 atomic_inc(&dev->writes_pending);
631 wmb();
632
633 retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
634 if (retval) {
635 dev->interrupt_out_busy = 0;
636 err("Couldn't submit interrupt_out_urb %d\n", retval);
637 atomic_dec(&dev->writes_pending);
638 goto unlock_exit;
639 }
640 retval = bytes_to_write;
641
642unlock_exit:
643 /* unlock the device */
644 up(&dev->sem);
645
646exit:
647 return retval;
648}
649
650/* file operations needed when we register this driver */
651static const struct file_operations usb_alphatrack_fops = {
652 .owner = THIS_MODULE,
653 .read = usb_alphatrack_read,
654 .write = usb_alphatrack_write,
655 .open = usb_alphatrack_open,
656 .release = usb_alphatrack_release,
657 .poll = usb_alphatrack_poll,
658};
659
660/*
661 * usb class driver info in order to get a minor number from the usb core,
662 * and to have the device registered with the driver core
663 */
664
665static struct usb_class_driver usb_alphatrack_class = {
666 .name = "alphatrack%d",
667 .fops = &usb_alphatrack_fops,
668 .minor_base = USB_ALPHATRACK_MINOR_BASE,
669};
670
671
672/**
673 * usb_alphatrack_probe
674 *
675 * Called by the usb core when a new device is connected that it thinks
676 * this driver might be interested in.
677 */
678static int usb_alphatrack_probe(struct usb_interface *intf, const struct usb_device_id *id)
679{
680 struct usb_device *udev = interface_to_usbdev(intf);
681 struct usb_alphatrack *dev = NULL;
682 struct usb_host_interface *iface_desc;
683 struct usb_endpoint_descriptor *endpoint;
684 int i;
685 int true_size;
686 int retval = -ENOMEM;
687
688 /* allocate memory for our device state and intialize it */
689
690 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
691 if (dev == NULL) {
692 dev_err(&intf->dev, "Out of memory\n");
693 goto exit;
694 }
695 init_MUTEX(&dev->sem);
696 dev->intf = intf;
697 init_waitqueue_head(&dev->read_wait);
698 init_waitqueue_head(&dev->write_wait);
699
700 iface_desc = intf->cur_altsetting;
701
702 /* set up the endpoint information */
703 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
704 endpoint = &iface_desc->endpoint[i].desc;
705
706 if (usb_endpoint_is_int_in(endpoint))
707 dev->interrupt_in_endpoint = endpoint;
708
709 if (usb_endpoint_is_int_out(endpoint))
710 dev->interrupt_out_endpoint = endpoint;
711 }
712 if (dev->interrupt_in_endpoint == NULL) {
713 dev_err(&intf->dev, "Interrupt in endpoint not found\n");
714 goto error;
715 }
716 if (dev->interrupt_out_endpoint == NULL)
717 dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
718
719 dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
720
721 if (dev->interrupt_in_endpoint_size != 64)
722 dev_warn(&intf->dev, "Interrupt in endpoint size is not 64!\n");
723
724 if(ring_buffer_size == 0) { ring_buffer_size = RING_BUFFER_SIZE; }
725
726 true_size = min(ring_buffer_size,RING_BUFFER_SIZE);
727
728 /* FIXME - there are more usb_alloc routines for dma correctness. Needed? */
729
730// dev->ring_buffer = kmalloc((true_size*sizeof(struct alphatrack_icmd))+12, GFP_KERNEL);
731 dev->ring_buffer = kmalloc((true_size*sizeof(struct alphatrack_icmd)), GFP_KERNEL);
732
733 if (!dev->ring_buffer) {
734 dev_err(&intf->dev, "Couldn't allocate input ring_buffer of size %d\n",true_size);
735 goto error;
736 }
737
738 dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
739
740 if (!dev->interrupt_in_buffer) {
741 dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n");
742 goto error;
743 }
744 dev->oldi_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
745 if (!dev->oldi_buffer) {
746 dev_err(&intf->dev, "Couldn't allocate old buffer\n");
747 goto error;
748 }
749 dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
750 if (!dev->interrupt_in_urb) {
751 dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
752 goto error;
753 }
754
755 dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) :
756 udev->descriptor.bMaxPacketSize0;
757
758 if (dev->interrupt_out_endpoint_size !=64)
759 dev_warn(&intf->dev, "Interrupt out endpoint size is not 64!)\n");
760
761 if(write_buffer_size == 0) { write_buffer_size = WRITE_BUFFER_SIZE; }
762 true_size = min(write_buffer_size,WRITE_BUFFER_SIZE);
763
764 dev->interrupt_out_buffer = kmalloc(true_size*dev->interrupt_out_endpoint_size, GFP_KERNEL);
765
766 if (!dev->interrupt_out_buffer) {
767 dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n");
768 goto error;
769 }
770
771 dev->write_buffer = kmalloc(sizeof(struct alphatrack_ocmd)*true_size, GFP_KERNEL);
772
773 if (!dev->write_buffer) {
774 dev_err(&intf->dev, "Couldn't allocate write_buffer \n");
775 goto error;
776 }
777
778 dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
779 if (!dev->interrupt_out_urb) {
780 dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n");
781 goto error;
782 }
783 dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
784 if (dev->interrupt_out_endpoint)
785 dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
786
787 /* we can register the device now, as it is ready */
788 usb_set_intfdata(intf, dev);
789
790 atomic_set(&dev->writes_pending,0);
791 retval = usb_register_dev(intf, &usb_alphatrack_class);
792 if (retval) {
793 /* something prevented us from registering this driver */
794 dev_err(&intf->dev, "Not able to get a minor for this device.\n");
795 usb_set_intfdata(intf, NULL);
796 goto error;
797 }
798
799 /* let the user know what node this device is now attached to */
800 dev_info(&intf->dev, "Alphatrack Device #%d now attached to major %d minor %d\n",
801 (intf->minor - USB_ALPHATRACK_MINOR_BASE), USB_MAJOR, intf->minor);
802
803#if ALPHATRACK_HAVE_SYSFS
804 if((retval = device_create_file(&intf->dev, &dev_attr_event))) goto error;
805 if((retval = device_create_file(&intf->dev, &dev_attr_dump_state))) goto error;
806 if((retval = device_create_file(&intf->dev, &dev_attr_enable))) goto error;
807 if((retval = device_create_file(&intf->dev, &dev_attr_offline))) goto error;
808
809 /* exercise sysfs */
810
811 set_lights("32767"); // turn on all the lights
812 set_fader0("1023"); // Move fader to max
813 set_screen("INITIALIZING ALPHATRACK...");
814 set_lights("0");
815 set_fader0("0");
816 set_screen(" ");
817
818#endif
819
820exit:
821 return retval;
822
823error:
824 usb_alphatrack_delete(dev);
825
826 return retval;
827}
828
829/**
830 * usb_alphatrack_disconnect
831 *
832 * Called by the usb core when the device is removed from the system.
833 */
834static void usb_alphatrack_disconnect(struct usb_interface *intf)
835{
836 struct usb_alphatrack *dev;
837 int minor;
838
839 mutex_lock(&disconnect_mutex);
840
841 dev = usb_get_intfdata(intf);
842 usb_set_intfdata(intf, NULL);
843
844 down(&dev->sem);
845
846 minor = intf->minor;
847
848 /* give back our minor */
849 usb_deregister_dev(intf, &usb_alphatrack_class);
850
851 /* if the device is not opened, then we clean up right now */
852 if (!dev->open_count) {
853 up(&dev->sem);
854 usb_alphatrack_delete(dev);
855 } else {
856 dev->intf = NULL;
857 up(&dev->sem);
858 }
859
860 atomic_set(&dev->writes_pending,0);
861 mutex_unlock(&disconnect_mutex);
862
863 dev_info(&intf->dev, "Alphatrack Surface #%d now disconnected\n",
864 (minor - USB_ALPHATRACK_MINOR_BASE));
865}
866
867/* usb specific object needed to register this driver with the usb subsystem */
868static struct usb_driver usb_alphatrack_driver = {
869 .name = "alphatrack",
870 .probe = usb_alphatrack_probe,
871 .disconnect = usb_alphatrack_disconnect,
872 .id_table = usb_alphatrack_table,
873};
874
875/**
876 * usb_alphatrack_init
877 */
878static int __init usb_alphatrack_init(void)
879{
880 int retval;
881
882 /* register this driver with the USB subsystem */
883 retval = usb_register(&usb_alphatrack_driver);
884 if (retval)
885 err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval);
886
887 return retval;
888}
889
890/**
891 * usb_alphatrack_exit
892 */
893static void __exit usb_alphatrack_exit(void)
894{
895 /* deregister this driver with the USB subsystem */
896 usb_deregister(&usb_alphatrack_driver);
897}
898
899module_init(usb_alphatrack_init);
900module_exit(usb_alphatrack_exit);
901
diff --git a/drivers/staging/frontier/alphatrack.h b/drivers/staging/frontier/alphatrack.h
new file mode 100644
index 000000000000..3dd7d54f49a8
--- /dev/null
+++ b/drivers/staging/frontier/alphatrack.h
@@ -0,0 +1,117 @@
1#define show_set_bit(a) show_set_mbit(alphatrack,a)
2#define show_set_cmd(a) show_set_mcmd(alphatrack,a)
3#define show_set_int(a) show_set_mint(alphatrack,a)
4#define show_set_char(a) show_set_mchar(alphatrack,a)
5#define show_set_light(a) show_set_ebit(alphatrack,LightID,lights,a)
6#define show_set_button(a) show_set_ebit(alphatrack,ButtonID,button,a)
7
8struct alphatrack_icmd {
9 unsigned char cmd[12];
10};
11
12struct alphatrack_ocmd {
13 unsigned char cmd[8];
14};
15
16enum LightID {
17 LIGHT_EQ = 0,
18 LIGHT_OUT,
19 LIGHT_F2,
20 LIGHT_SEND,
21 LIGHT_IN,
22 LIGHT_F1,
23 LIGHT_PAN,
24 LIGHT_UNDEF1,
25 LIGHT_UNDEF2,
26 LIGHT_SHIFT,
27 LIGHT_TRACKMUTE,
28 LIGHT_TRACKSOLO,
29 LIGHT_TRACKREC,
30 LIGHT_READ,
31 LIGHT_WRITE,
32 LIGHT_ANYSOLO,
33 LIGHT_AUTO,
34 LIGHT_F4,
35 LIGHT_RECORD,
36 LIGHT_WINDOW,
37 LIGHT_PLUGIN,
38 LIGHT_F3,
39 LIGHT_LOOP
40};
41
42static const char *Lightname[] = { "eq",
43"out",
44"f2",
45"send",
46"in",
47"f1",
48"pan",
49"undef1",
50"undef2",
51"shift",
52"mute",
53"tracksolo",
54"trackrec",
55"read",
56"write",
57"anysolo",
58"auto",
59"f4",
60"record",
61"window",
62"plugin",
63"f3",
64"loop",
65NULL };
66
67#define BUTTONMASK_BATTERY 0x00004000
68#define BUTTONMASK_BACKLIGHT 0x00008000
69#define BUTTONMASK_FASTFORWARD 0x04000000
70#define BUTTONMASK_TRACKMUTE 0x00040000
71#define BUTTONMASK_TRACKSOLO 0x00800000
72#define BUTTONMASK_TRACKLEFT 0x80000000
73#define BUTTONMASK_RECORD 0x02000000
74#define BUTTONMASK_SHIFT 0x20000000
75#define BUTTONMASK_PUNCH 0x00800000
76#define BUTTONMASK_TRACKRIGHT 0x00020000
77#define BUTTONMASK_REWIND 0x01000000
78#define BUTTONMASK_STOP 0x10000000
79#define BUTTONMASK_LOOP 0x00010000
80#define BUTTONMASK_TRACKREC 0x00001000
81#define BUTTONMASK_PLAY 0x08000000
82#define BUTTONMASK_TOUCH1 0x00000008
83#define BUTTONMASK_TOUCH2 0x00000010
84#define BUTTONMASK_TOUCH3 0x00000020
85
86#define BUTTONMASK_PRESS1 0x00000009
87#define BUTTONMASK_PRESS2 0x00008010
88#define BUTTONMASK_PRESS3 0x00002020
89
90// last 3 bytes are the slider position
91// 40 is the actual slider moving, the most sig bits, and 3 lsb
92
93#define BUTTONMASK_FLIP 0x40000000
94#define BUTTONMASK_F1 0x00100000
95#define BUTTONMASK_F2 0x00400000
96#define BUTTONMASK_F3 0x00200000
97#define BUTTONMASK_F4 0x00080000
98#define BUTTONMASK_PAN 0x00000200
99#define BUTTONMASK_SEND 0x00000800
100#define BUTTONMASK_EQ 0x00004000
101#define BUTTONMASK_PLUGIN 0x00000400
102#define BUTTONMASK_AUTO 0x00000100
103
104
105// #define BUTTONMASK_FOOTSWITCH FIXME
106
107// Lookup. name. midi out. midi in.
108
109struct buttonmap_t {
110 u32 mask;
111 short midi_in;
112 short midi_out;
113 char *name;
114// void (*function) (buttonmap_t *);
115 void (*function) (void);
116};
117
diff --git a/drivers/staging/frontier/alphatrack_sysfs.c b/drivers/staging/frontier/alphatrack_sysfs.c
new file mode 100644
index 000000000000..21af6a2d70bb
--- /dev/null
+++ b/drivers/staging/frontier/alphatrack_sysfs.c
@@ -0,0 +1,279 @@
1/* This was an attempt - ultimately proved pointless - at making a full fledged sysfs interface to the alphatrack */
2/* won't even compile at present */
3
4char *alphatrack_sys_margs;
5spinlock_t alphatrack_sys_margs_lock;
6
7struct alphatrack_attr {
8 struct attribute attr;
9 ssize_t (*show)(struct device *, char *);
10 ssize_t (*store)(struct device *, const char *, size_t);
11};
12
13#define ALPHATRACK_ATTR(name, mode, show, store) \
14static struct alphatrack_attr alphatrack_attr_##name = __ATTR(name, mode, show, store)
15
16/* now a great deal of callback code generation */
17
18// FOREACH_LIGHT(show_set_light)
19// FOREACH_BUTTON(show_set_button)
20
21show_set_light(LIGHT_RECORD); show_set_light(LIGHT_EQ); show_set_light(LIGHT_OUT);
22show_set_light(LIGHT_F2); show_set_light(LIGHT_SEND); show_set_light(LIGHT_IN);
23show_set_light(LIGHT_F1); show_set_light(LIGHT_PAN); show_set_light(LIGHT_UNDEF1);
24show_set_light(LIGHT_UNDEF2); show_set_light(LIGHT_SHIFT); show_set_light(LIGHT_TRACKMUTE);
25show_set_light(LIGHT_TRACKSOLO); show_set_light(LIGHT_TRACKREC); show_set_light(LIGHT_READ);
26show_set_light(LIGHT_WRITE); show_set_light(LIGHT_ANYSOLO); show_set_light(LIGHT_AUTO);
27show_set_light(LIGHT_F4); show_set_light(LIGHT_RECORD); show_set_light(LIGHT_WINDOW);
28show_set_light(LIGHT_PLUGIN); show_set_light(LIGHT_F3); show_set_light(LIGHT_LOOP);
29
30show_set_opt(enable); show_set_opt(offline); show_set_opt(compress_fader); show_set_opt(dump_state);
31show_set_int(fader); show_set_int(event);
32
33
34static ssize_t show_lights(struct device *dev, struct device_attribute *attr, char *buf)
35{
36 struct usb_interface *intf = to_usb_interface(dev);
37 struct usb_alphatrack *t = usb_get_intfdata(intf);
38 return sprintf(buf, "%d\n", t->lights);
39}
40
41static ssize_t set_lights(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
42{
43 struct usb_interface *intf = to_usb_interface(dev);
44 struct usb_alphatrack *t = usb_get_intfdata(intf);
45 int temp = simple_strtoul(buf, NULL, 10);
46 t->lights = temp;
47 return count;
48}
49
50static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_lights, set_lights);
51
52
53ALPHATRACK_ATTR(LightRecord, 0200, NULL, LightRecord_store);
54
55static struct attribute *alphatrack_attrs[] = {
56 &alphatrack_attr_LightRecord.attr,
57 NULL,
58};
59
60static ssize_t alphatrack_attr_show(struct kobject *kobj, struct attribute *attr,
61 char *buf)
62{
63 struct device *sdp = container_of(kobj, struct device, kobj);
64 struct alphatrack_attr *a = container_of(attr, struct alphatrack_attr, attr);
65 return a->show ? a->show(sdp, buf) : 0;
66}
67
68static ssize_t alphatrack_attr_store(struct kobject *kobj, struct attribute *attr,
69 const char *buf, size_t len)
70{
71 struct device *sdp = container_of(kobj, struct device, kobj);
72 struct alphatrack_attr *a = container_of(attr, struct alphatrack_attr, attr);
73 return a->store ? a->store(sdp, buf, len) : len;
74}
75
76static struct sysfs_ops alphatrack_attr_ops = {
77 .show = alphatrack_attr_show,
78 .store = alphatrack_attr_store,
79};
80
81static struct kobj_type alphatrack_ktype = {
82 .default_attrs = alphatrack_attrs,
83 .sysfs_ops = &alphatrack_attr_ops,
84};
85
86static struct kset alphatrack_kset = {
87 .subsys = &fs_subsys,
88 .kobj = {.name = "alphatrack"},
89 .ktype = &alphatrack_ktype,
90};
91
92
93static struct attribute *lights_attrs[] = {
94 &tune_attr_demote_secs.attr,
95 NULL,
96};
97
98
99static struct attribute_group leds_group = {
100 .name = "leds",
101 .attrs = lights_attrs,
102};
103
104static struct attribute_group faders_group = {
105 .name = "faders",
106 .attrs = faders_attrs,
107};
108
109static struct attribute_group lcds_group = {
110 .name = "lcds",
111 .attrs = lcds_attrs,
112};
113
114static struct attribute_group wheels_group = {
115 .name = "wheels",
116 .attrs = wheels_attrs,
117};
118
119static struct attribute_group touchsurfaces_group = {
120 .name = "touchsurfaces",
121 .attrs = touchsurfaces_attrs,
122};
123
124static struct attribute_group buttons_group = {
125 .name = "buttons",
126 .attrs = buttons_attrs,
127};
128
129
130int alphatrack_sys_fs_add(struct device *sdp)
131{
132 int error;
133
134 sdp->kobj.kset = &alphatrack_kset;
135 sdp->kobj.ktype = &alphatrack_ktype;
136
137// error = kobject_set_name(&sdp->kobj, "%s", sdp->sd_table_name);
138 error = kobject_set_name(&sdp->kobj, "%s", "alphatrack");
139 if (error)
140 goto fail;
141
142 error = kobject_register(&sdp->kobj);
143 if (error)
144 goto fail;
145
146 error = sysfs_create_group(&sdp->kobj, &lcds_group);
147 if (error)
148 goto fail_reg;
149
150 error = sysfs_create_group(&sdp->kobj, &leds_group);
151 if (error)
152 goto fail_leds;
153
154 error = sysfs_create_group(&sdp->kobj, &wheels_group);
155 if (error)
156 goto fail_wheels;
157
158 error = sysfs_create_group(&sdp->kobj, &faders_group);
159 if (error)
160 goto fail_lcds;
161
162 error = sysfs_create_group(&sdp->kobj, &buttons_group);
163 if (error)
164 goto fail_faders;
165
166 error = sysfs_create_group(&sdp->kobj, &touchsurfaces_group);
167 if (error)
168 goto fail_buttons;
169
170 return 0;
171
172
173fail_buttons:
174 sysfs_remove_group(&sdp->kobj, &buttons_group);
175fail_faders:
176 sysfs_remove_group(&sdp->kobj, &faders_group);
177fail_wheels:
178 sysfs_remove_group(&sdp->kobj, &wheels_group);
179fail_lcds:
180 sysfs_remove_group(&sdp->kobj, &lcds_group);
181fail_leds:
182 sysfs_remove_group(&sdp->kobj, &leds_group);
183
184
185
186fail_reg:
187 kobject_unregister(&sdp->kobj);
188fail:
189 fs_err(sdp, "error %d adding sysfs files", error);
190 return error;
191}
192
193// int sysfs_create_link(struct kobject *kobj,
194// struct kobject *target,
195// char *name);
196
197void alphatrack_sys_fs_del(struct device *sdp)
198{
199 sysfs_remove_group(&sdp->kobj, &touchsurfaces_group);
200 sysfs_remove_group(&sdp->kobj, &buttons_group);
201 sysfs_remove_group(&sdp->kobj, &faders_group);
202 sysfs_remove_group(&sdp->kobj, &lcds_group);
203 sysfs_remove_group(&sdp->kobj, &wheels_group);
204 sysfs_remove_group(&sdp->kobj, &leds_group)
205//void sysfs_remove_link(struct kobject *kobj, char *name);
206 kobject_unregister(&sdp->kobj);
207}
208
209int alphatrack_sys_init(void)
210{
211 alphatrack_sys_margs = NULL;
212 spin_lock_init(&alphatrack_sys_margs_lock);
213 return kset_register(&alphatrack_kset);
214}
215
216void alphatrack_sys_uninit(void)
217{
218 kfree(alphatrack_sys_margs);
219 kset_unregister(&alphatrack_kset);
220}
221
222
223//decl_subsys(char *name, struct kobj_type *type,
224// struct kset_hotplug_ops *hotplug_ops);
225
226/* End of all the crazy sysfs stuff */
227
228#define SYSEX_INQUIRE signed char *SYSEX_INQUIRE[] = { 0xf0,0x7e,0x00,0x06,0x01,0x17 };
229
230#define COMMAND(NAME,CONT_NAME) { BUTTONMASK_##NAME, ((0x90 << 8) | CONT_NAME), ((0x90 << 8) | CONT_NAME), #NAME, NAME ## _set }
231#define ROTARY(NAME,CONT_NAME) { FADER_##NAME, ((0xb0 << 8) | CONT_NAME), ((0xb0 << 8) | CONT_NAME), #NAME, NAME ## _set }
232#define SPOSITION(NAME,CONT_NAME) { BUTTON_##NAME ((0xe9 << 8) | CONT_NAME), #NAME, NAME ## _set }
233#define ENDCOMMAND { 0,NULL,0,NULL,NULL}
234
235/* Now that we've generated all our callbacks */
236
237static struct buttonmap_t buttonmap[] =
238 {
239 COMMAND (REWIND,0x5b),
240 COMMAND (FASTFORWARD,0x5c),
241 COMMAND (STOP,0x5d),
242 COMMAND (PLAY,0x5e),
243 COMMAND (RECORD,0x5f),
244 COMMAND (SHIFT,0x46),
245 COMMAND (TRACKLEFT,0x57),
246 COMMAND (TRACKRIGHT,0x58),
247 COMMAND (LOOP,0x56),
248 COMMAND (FLIP,0x32),
249 COMMAND (MUTE,0x10),
250 COMMAND (F1,0x36),
251 COMMAND (F2,0x37),
252 COMMAND (F3,0x38),
253 COMMAND (F4,0x39),
254 COMMAND (SOLO,0x08),
255 COMMAND (ANY,0x73),
256 COMMAND (PAN,0x2a),
257 COMMAND (SEND,0x29),
258 COMMAND (EQ,0x2c),
259 COMMAND (PLUGIN,0x2b),
260 COMMAND (AUTO,0x4a),
261 COMMAND (TRACKREC,0x00),
262 COMMAND (FOOTSWITCH1,0x67),
263 COMMAND (KNOBTOUCH1,0x78),
264 COMMAND (KNOBPUSH1,0x20),
265 ROTARY (KNOBTURN1,0x10),
266 COMMAND (KNOBTOUCH2,0x79),
267 COMMAND (KNOBPUSH2,0x21),
268 ROTARY (KNOBTURN2,0x11),
269 COMMAND (KNOBTOUCH3,0x7a),
270 COMMAND (KNOBPUSH3,0x22),
271 ROTARY (KNOBTURN3,0x12),
272 COMMAND (FADERTOUCH1,0x68),
273 COMMAND (STRIPTOUCH1,0x74),
274 COMMAND (STRIPTOUCH2,0x6b),
275 SPOSITION (STRIPPOS1,0x00),
276 ENDCOMMAND
277 };
278
279
diff --git a/drivers/staging/frontier/frontier_compat.h b/drivers/staging/frontier/frontier_compat.h
new file mode 100644
index 000000000000..00450e637ac8
--- /dev/null
+++ b/drivers/staging/frontier/frontier_compat.h
@@ -0,0 +1,63 @@
1/* USB defines for older kernels */
2
3#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
4
5/**
6 * usb_endpoint_dir_out - check if the endpoint has OUT direction
7 * @epd: endpoint to be checked
8 *
9 * Returns true if the endpoint is of type OUT, otherwise it returns false.
10 */
11
12static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
13{
14 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
15}
16
17static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
18{
19 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
20}
21
22
23/**
24 * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
25 * @epd: endpoint to be checked
26 *
27 * Returns true if the endpoint is of type interrupt, otherwise it returns
28 * false.
29 */
30static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
31{
32 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
33 USB_ENDPOINT_XFER_INT);
34}
35
36
37/**
38 * usb_endpoint_is_int_in - check if the endpoint is interrupt IN
39 * @epd: endpoint to be checked
40 *
41 * Returns true if the endpoint has interrupt transfer type and IN direction,
42 * otherwise it returns false.
43 */
44
45static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
46{
47 return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
48}
49
50/**
51 * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
52 * @epd: endpoint to be checked
53 *
54 * Returns true if the endpoint has interrupt transfer type and OUT direction,
55 * otherwise it returns false.
56 */
57
58static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
59{
60 return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
61}
62
63#endif /* older kernel versions */
diff --git a/drivers/staging/frontier/surface_sysfs.h b/drivers/staging/frontier/surface_sysfs.h
new file mode 100644
index 000000000000..d50a562d658a
--- /dev/null
+++ b/drivers/staging/frontier/surface_sysfs.h
@@ -0,0 +1,100 @@
1/* If you are going to abuse the preprocessor, why not ABUSE the preprocessor?
2 I stuck this header in a separate file so I don't have to look at it */
3
4// FIXME Need locking or atomic ops
5
6#define show_set_mbit(dname,value,bit) \
7static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
8{ \
9 struct usb_interface *intf = to_usb_interface(dev); \
10 struct usb_##dname *t = usb_get_intfdata(intf); \
11 int temp = (1 && (t->value & (1 << bit))); \
12 return sprintf(buf, "%d\n", temp); \
13} \
14static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
15{ \
16 struct usb_interface *intf = to_usb_interface(dev); \
17 struct usb_##dname *t = usb_get_intfdata(intf); \
18 int temp = simple_strtoul(buf, NULL, 10); \
19 if(temp > 0) { long b = 1 << bit; t->value |= b; } \
20 else { long b = ~(1 << bit); t->value &= b ; \
21 return count; \
22} \
23static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
24
25#define show_set_ebit(dname,enumname,value,bit) \
26static ssize_t show_##bit(struct device *dev, struct device_attribute *attr, char *buf) \
27{ \
28 struct usb_interface *intf = to_usb_interface(dev); \
29 struct usb_##dname *t = usb_get_intfdata(intf); \
30 enum enumname l = bit; \
31 int temp = t->value & (1 << l); \
32 return sprintf(buf, "%d\n", temp); \
33} \
34static ssize_t set_##bit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
35{ \
36 struct usb_interface *intf = to_usb_interface(dev); \
37 struct usb_##dname *t = usb_get_intfdata(intf); \
38 int temp = simple_strtoul(buf, NULL, 10); \
39 enum enumname l = bit;\
40 long b = 1 << l; \
41 if(temp > 0) { t->value |= b; } \
42 else { t->value &= ~b ; \
43 return count; \
44} \
45static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
46
47// FIXME FOR CORRECTLY SETTING HEX from a string
48#define show_set_mcmd(dname,value) \
49static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
50{ \
51 struct usb_interface *intf = to_usb_interface(dev); \
52 struct usb_##dname *t = usb_get_intfdata(intf); \
53 int count = 0;\
54 int i; \
55 for (i = 0,i<sizeof(dname); i++) count += snprintf(buf, "%02x",t->dname[i]); \
56 return(count);\
57} \
58static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
59{ \
60 struct usb_interface *intf = to_usb_interface(dev); \
61 struct usb_##dname *t = usb_get_intfdata(intf); \
62 int temp = simple_strtoul(buf, NULL, 10); \
63 t->value = temp; \
64 return count; \
65} \
66static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
67
68#define show_set_mint(dname,value) \
69static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
70{ \
71 struct usb_interface *intf = to_usb_interface(dev); \
72 struct usb_##dname *t = usb_get_intfdata(intf); \
73 return sprintf(buf, "%d\n", t->value); \
74} \
75static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
76{ \
77 struct usb_interface *intf = to_usb_interface(dev); \
78 struct usb_##dname *t = usb_get_intfdata(intf); \
79 int temp = simple_strtoul(buf, NULL, 10); \
80 t->value = temp; \
81 return count; \
82} \
83static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
84
85#define show_set_mchar(dname,value) \
86static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
87{ \
88 struct usb_interface *intf = to_usb_interface(dev); \
89 struct usb_##dname *t = usb_get_intfdata(intf); \
90 return sprintf(buf, "%c\n", t->value); \
91} \
92static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
93{ \
94 struct usb_interface *intf = to_usb_interface(dev); \
95 struct usb_##dname *t = usb_get_intfdata(intf); \
96 int temp = simple_strtoul(buf, NULL, 10); \
97 t->value = temp; \
98 return count; \
99} \
100static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
new file mode 100644
index 000000000000..32d9c5084c88
--- /dev/null
+++ b/drivers/staging/frontier/tranzport.c
@@ -0,0 +1,1017 @@
1/*
2 * Frontier Designs Tranzport driver
3 *
4 * Copyright (C) 2007 Michael Taht (m@taht.net)
5 *
6 * Based on the usbled driver and ldusb drivers by
7 *
8 * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
9 * Copyright (C) 2005 Michael Hund <mhund@ld-didactic.de>
10 *
11 * The ldusb driver was, in turn, derived from Lego USB Tower driver
12 * Copyright (C) 2003 David Glance <advidgsf@sourceforge.net>
13 * 2001-2004 Juergen Stuber <starblue@users.sourceforge.net>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation, version 2.
18 *
19 */
20
21/**
22 * This driver uses a ring buffer for time critical reading of
23 * interrupt in reports and provides read and write methods for
24 * raw interrupt reports.
25 */
26
27/* Note: this currently uses a dumb ringbuffer for reads and writes.
28 * A more optimal driver would cache and kill off outstanding urbs that are
29 * now invalid, and ignore ones that already were in the queue but valid
30 * as we only have 17 commands for the tranzport. In particular this is
31 * key for getting lights to flash in time as otherwise many commands
32 * can be buffered up before the light change makes it to the interface.
33*/
34
35#include <linux/kernel.h>
36#include <linux/errno.h>
37#include <linux/init.h>
38#include <linux/slab.h>
39#include <linux/module.h>
40#include <linux/mutex.h>
41#include <linux/version.h>
42
43#include <asm/uaccess.h>
44#include <linux/input.h>
45#include <linux/usb.h>
46#include <linux/poll.h>
47
48#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
49#include frontier_compat.h
50#endif
51
52/* Define these values to match your devices */
53#define VENDOR_ID 0x165b
54#define PRODUCT_ID 0x8101
55
56#ifdef CONFIG_USB_DYNAMIC_MINORS
57#define USB_TRANZPORT_MINOR_BASE 0
58#else
59// FIXME 176 - is the ldusb driver's minor - apply for a minor soon
60#define USB_TRANZPORT_MINOR_BASE 177
61#endif
62
63/* table of devices that work with this driver */
64static struct usb_device_id usb_tranzport_table [] = {
65 { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
66 { } /* Terminating entry */
67};
68
69MODULE_DEVICE_TABLE(usb, usb_tranzport_table);
70MODULE_VERSION("0.33");
71MODULE_AUTHOR("Mike Taht <m@taht.net>");
72MODULE_DESCRIPTION("Tranzport USB Driver");
73MODULE_LICENSE("GPL");
74MODULE_SUPPORTED_DEVICE("Frontier Designs Tranzport Control Surface");
75
76/* These two aren't done yet */
77
78#define SUPPRESS_EXTRA_ONLINE_EVENTS 0
79#define BUFFERED_WRITES 0
80
81#define SUPPRESS_EXTRA_OFFLINE_EVENTS 1
82#define COMPRESS_WHEEL_EVENTS 1
83#define BUFFERED_READS 1
84#define RING_BUFFER_SIZE 1000
85#define WRITE_BUFFER_SIZE 34
86#define TRANZPORT_USB_TIMEOUT 10
87
88
89static int debug = 0;
90
91/* Use our own dbg macro */
92#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
93
94/* Module parameters */
95
96module_param(debug, int, S_IRUGO | S_IWUSR);
97MODULE_PARM_DESC(debug, "Debug enabled or not");
98
99/* All interrupt in transfers are collected in a ring buffer to
100 * avoid racing conditions and get better performance of the driver.
101 */
102
103static int ring_buffer_size = RING_BUFFER_SIZE;
104
105module_param(ring_buffer_size, int, S_IRUGO);
106MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports");
107
108/* The write_buffer can one day contain more than one interrupt out transfer.
109 */
110static int write_buffer_size = WRITE_BUFFER_SIZE;
111module_param(write_buffer_size, int, S_IRUGO);
112MODULE_PARM_DESC(write_buffer_size, "Write buffer size");
113
114/*
115 * Increase the interval for debugging purposes.
116 * or set to 1 to use the standard interval from the endpoint descriptors.
117 */
118
119static int min_interrupt_in_interval = TRANZPORT_USB_TIMEOUT;
120module_param(min_interrupt_in_interval, int, 0);
121MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms");
122
123static int min_interrupt_out_interval = TRANZPORT_USB_TIMEOUT;
124module_param(min_interrupt_out_interval, int, 0);
125MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms");
126
127struct tranzport_cmd {
128 unsigned char cmd[8];
129};
130
131enum LightID {
132 LightRecord = 0,
133 LightTrackrec,
134 LightTrackmute,
135 LightTracksolo,
136 LightAnysolo,
137 LightLoop,
138 LightPunch
139 };
140
141static const char *Lightname[8] = { "LightRecord",
142 "LightTracrec",
143 "LightTrackmute",
144 "LightTrackSolo",
145 "LightAnySolo",
146 "LightLoop",
147 "LightPunch",
148 NULL };
149
150
151/* Structure to hold all of our device specific stuff */
152
153struct usb_tranzport {
154 struct semaphore sem; /* locks this structure */
155 struct usb_interface* intf; /* save off the usb interface pointer */
156
157 int open_count; /* number of times this port has been opened */
158
159 struct tranzport_cmd (*ring_buffer)[RING_BUFFER_SIZE]; /* just make c happy */
160 unsigned int ring_head;
161 unsigned int ring_tail;
162
163 wait_queue_head_t read_wait;
164 wait_queue_head_t write_wait;
165
166 unsigned char* interrupt_in_buffer;
167 struct usb_endpoint_descriptor* interrupt_in_endpoint;
168 struct urb* interrupt_in_urb;
169 int interrupt_in_interval;
170 size_t interrupt_in_endpoint_size;
171 int interrupt_in_running;
172 int interrupt_in_done;
173
174 char* interrupt_out_buffer;
175 struct usb_endpoint_descriptor* interrupt_out_endpoint;
176 struct urb* interrupt_out_urb;
177 int interrupt_out_interval;
178 size_t interrupt_out_endpoint_size;
179 int interrupt_out_busy;
180
181 /* Sysfs and translation support */
182
183 int event; /* alternate interface to events */
184 int wheel; /* - for negative, 0 for none, + for positive */
185 unsigned char dump_state; /* 0 if disabled 1 if enabled */
186 unsigned char enable; /* 0 if disabled 1 if enabled */
187 unsigned char offline; /* if the device is out of range or asleep */
188 unsigned char compress_wheel; /* flag to compress wheel events */
189 unsigned char light; /* 7 bits used */
190 unsigned char last_cmd[8];
191 unsigned char last_input[8];
192 unsigned char screen[40]; // We'll also have cells
193
194};
195
196/* prevent races between open() and disconnect() */
197static DEFINE_MUTEX(disconnect_mutex);
198
199static struct usb_driver usb_tranzport_driver;
200
201/**
202 * usb_tranzport_abort_transfers
203 * aborts transfers and frees associated data structures
204 */
205static void usb_tranzport_abort_transfers(struct usb_tranzport *dev)
206{
207 /* shutdown transfer */
208 if (dev->interrupt_in_running) {
209 dev->interrupt_in_running = 0;
210 if (dev->intf)
211 usb_kill_urb(dev->interrupt_in_urb);
212 }
213 if (dev->interrupt_out_busy)
214 if (dev->intf)
215 usb_kill_urb(dev->interrupt_out_urb);
216}
217
218// FIXME ~light not good enough or correct - need atomic set_bit
219
220#define show_set_light(value) \
221static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
222{ \
223 struct usb_interface *intf = to_usb_interface(dev); \
224 struct usb_tranzport *t = usb_get_intfdata(intf); \
225 enum LightID light = value; \
226 int temp = (1 && (t->light & (1 << light))); \
227 return sprintf(buf, "%d\n", temp ); \
228} \
229static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
230{ \
231 struct usb_interface *intf = to_usb_interface(dev); \
232 struct usb_tranzport *t = usb_get_intfdata(intf); \
233 int temp = simple_strtoul(buf, NULL, 10); \
234 enum LightID light = (temp << value) & (t->light << value); \
235 t->light = (t->light & ~light) ; \
236 return count; \
237} \
238static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
239
240show_set_light(LightRecord);
241show_set_light(LightTrackrec);
242show_set_light(LightTrackmute);
243show_set_light(LightTracksolo);
244show_set_light(LightAnysolo);
245show_set_light(LightLoop);
246show_set_light(LightPunch);
247
248
249#define show_set_int(value) \
250static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
251{ \
252 struct usb_interface *intf = to_usb_interface(dev); \
253 struct usb_tranzport *t = usb_get_intfdata(intf); \
254 \
255 return sprintf(buf, "%d\n", t->value); \
256} \
257static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
258{ \
259 struct usb_interface *intf = to_usb_interface(dev); \
260 struct usb_tranzport *t = usb_get_intfdata(intf); \
261 int temp = simple_strtoul(buf, NULL, 10); \
262 \
263 t->value = temp; \
264 return count; \
265} \
266static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
267
268show_set_int(enable);
269show_set_int(offline);
270show_set_int(compress_wheel);
271show_set_int(dump_state);
272show_set_int(wheel);
273show_set_int(event);
274
275#define show_set_cmd(value) \
276static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
277{ \
278 struct usb_interface *intf = to_usb_interface(dev); \
279 struct usb_tranzport *t = usb_get_intfdata(intf); \
280 \
281 return sprintf(buf, "%d\n", t->value); \
282} \
283static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
284{ \
285 struct usb_interface *intf = to_usb_interface(dev); \
286 struct usb_tranzport *t = usb_get_intfdata(intf); \
287 int temp = simple_strtoul(buf, NULL, 10); \
288 \
289 t->value = temp; \
290 return count; \
291} \
292static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
293
294
295
296
297/**
298 * usb_tranzport_delete
299 */
300static void usb_tranzport_delete(struct usb_tranzport *dev)
301{
302 usb_tranzport_abort_transfers(dev);
303 /* This is just too twisted to be correct */
304 if(dev->intf != NULL) {
305 device_remove_file(&dev->intf->dev, &dev_attr_LightRecord);
306 device_remove_file(&dev->intf->dev, &dev_attr_LightTrackrec);
307 device_remove_file(&dev->intf->dev, &dev_attr_LightTrackmute);
308 device_remove_file(&dev->intf->dev, &dev_attr_LightTracksolo);
309 device_remove_file(&dev->intf->dev, &dev_attr_LightTrackmute);
310 device_remove_file(&dev->intf->dev, &dev_attr_LightAnysolo);
311 device_remove_file(&dev->intf->dev, &dev_attr_LightLoop);
312 device_remove_file(&dev->intf->dev, &dev_attr_LightPunch);
313 device_remove_file(&dev->intf->dev, &dev_attr_wheel);
314 device_remove_file(&dev->intf->dev, &dev_attr_enable);
315 device_remove_file(&dev->intf->dev, &dev_attr_event);
316 device_remove_file(&dev->intf->dev, &dev_attr_offline);
317 device_remove_file(&dev->intf->dev, &dev_attr_compress_wheel);
318
319 device_remove_file(&dev->intf->dev, &dev_attr_dump_state);
320 }
321
322 /* free data structures */
323 usb_free_urb(dev->interrupt_in_urb);
324 usb_free_urb(dev->interrupt_out_urb);
325 kfree(dev->ring_buffer);
326 kfree(dev->interrupt_in_buffer);
327 kfree(dev->interrupt_out_buffer);
328 kfree(dev);
329}
330
331/**
332 * usb_tranzport_interrupt_in_callback
333 */
334
335static void usb_tranzport_interrupt_in_callback(struct urb *urb)
336{
337 struct usb_tranzport *dev = urb->context;
338 unsigned int next_ring_head;
339 int retval = -1;
340
341 if (urb->status) {
342 if (urb->status == -ENOENT ||
343 urb->status == -ECONNRESET ||
344 urb->status == -ESHUTDOWN) {
345 goto exit;
346 } else {
347 dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
348 __FUNCTION__, urb->status);
349 goto resubmit; /* maybe we can recover */
350 }
351 }
352
353 if (urb->actual_length != 8) {
354 dev_warn(&dev->intf->dev,
355 "Urb length was %d bytes!! Do something intelligent \n", urb->actual_length);
356 } else {
357 dbg_info(&dev->intf->dev, "%s: received: %02x%02x%02x%02x%02x%02x%02x%02x\n",
358 __FUNCTION__, dev->interrupt_in_buffer[0],dev->interrupt_in_buffer[1],dev->interrupt_in_buffer[2],dev->interrupt_in_buffer[3],dev->interrupt_in_buffer[4],dev->interrupt_in_buffer[5],dev->interrupt_in_buffer[6],dev->interrupt_in_buffer[7]);
359#if SUPPRESS_EXTRA_OFFLINE_EVENTS
360 if(dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) { goto resubmit; }
361 if(dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 2; goto resubmit; }
362
363/* Always pass one offline event up the stack */
364 if(dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) { dev->offline = 0; }
365 if(dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 1; }
366
367#endif
368 dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
369
370 next_ring_head = (dev->ring_head+1) % ring_buffer_size;
371
372 if (next_ring_head != dev->ring_tail) {
373 memcpy(&((*dev->ring_buffer)[dev->ring_head]), dev->interrupt_in_buffer, urb->actual_length);
374 dev->ring_head = next_ring_head;
375 retval = 0;
376 memset(dev->interrupt_in_buffer, 0, urb->actual_length);
377 } else {
378 dev_warn(&dev->intf->dev,
379 "Ring buffer overflow, %d bytes dropped\n",
380 urb->actual_length);
381 memset(dev->interrupt_in_buffer, 0, urb->actual_length);
382 }
383 }
384
385resubmit:
386 /* resubmit if we're still running */
387 if (dev->interrupt_in_running && dev->intf) {
388 retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
389 if (retval)
390 dev_err(&dev->intf->dev,
391 "usb_submit_urb failed (%d)\n", retval);
392 }
393
394exit:
395 dev->interrupt_in_done = 1;
396 wake_up_interruptible(&dev->read_wait);
397}
398
399/**
400 * usb_tranzport_interrupt_out_callback
401 */
402static void usb_tranzport_interrupt_out_callback(struct urb *urb)
403{
404 struct usb_tranzport *dev = urb->context;
405
406 /* sync/async unlink faults aren't errors */
407 if (urb->status && !(urb->status == -ENOENT ||
408 urb->status == -ECONNRESET ||
409 urb->status == -ESHUTDOWN))
410 dbg_info(&dev->intf->dev,
411 "%s - nonzero write interrupt status received: %d\n",
412 __FUNCTION__, urb->status);
413
414 dev->interrupt_out_busy = 0;
415 wake_up_interruptible(&dev->write_wait);
416}
417
418/**
419 * usb_tranzport_open
420 */
421static int usb_tranzport_open(struct inode *inode, struct file *file)
422{
423 struct usb_tranzport *dev;
424 int subminor;
425 int retval = 0;
426 struct usb_interface *interface;
427
428 nonseekable_open(inode, file);
429 subminor = iminor(inode);
430
431 mutex_lock(&disconnect_mutex);
432
433 interface = usb_find_interface(&usb_tranzport_driver, subminor);
434
435 if (!interface) {
436 err("%s - error, can't find device for minor %d\n",
437 __FUNCTION__, subminor);
438 retval = -ENODEV;
439 goto unlock_disconnect_exit;
440 }
441
442 dev = usb_get_intfdata(interface);
443
444 if (!dev) {
445 retval = -ENODEV;
446 goto unlock_disconnect_exit;
447 }
448
449 /* lock this device */
450 if (down_interruptible(&dev->sem)) {
451 retval = -ERESTARTSYS;
452 goto unlock_disconnect_exit;
453 }
454
455 /* allow opening only once */
456 if (dev->open_count) {
457 retval = -EBUSY;
458 goto unlock_exit;
459 }
460 dev->open_count = 1;
461
462 /* initialize in direction */
463 dev->ring_head = 0;
464 dev->ring_tail = 0;
465 usb_fill_int_urb(dev->interrupt_in_urb,
466 interface_to_usbdev(interface),
467 usb_rcvintpipe(interface_to_usbdev(interface),
468 dev->interrupt_in_endpoint->bEndpointAddress),
469 dev->interrupt_in_buffer,
470 dev->interrupt_in_endpoint_size,
471 usb_tranzport_interrupt_in_callback,
472 dev,
473 dev->interrupt_in_interval);
474
475 dev->interrupt_in_running = 1;
476 dev->interrupt_in_done = 0;
477 dev->enable = 1;
478 dev->offline = 0;
479 dev->compress_wheel = 1;
480
481 retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
482 if (retval) {
483 dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval);
484 dev->interrupt_in_running = 0;
485 dev->open_count = 0;
486 goto unlock_exit;
487 }
488
489 /* save device in the file's private structure */
490 file->private_data = dev;
491
492
493unlock_exit:
494 up(&dev->sem);
495
496unlock_disconnect_exit:
497 mutex_unlock(&disconnect_mutex);
498
499 return retval;
500}
501
502/**
503 * usb_tranzport_release
504 */
505static int usb_tranzport_release(struct inode *inode, struct file *file)
506{
507 struct usb_tranzport *dev;
508 int retval = 0;
509
510 dev = file->private_data;
511
512 if (dev == NULL) {
513 retval = -ENODEV;
514 goto exit;
515 }
516
517 if (down_interruptible(&dev->sem)) {
518 retval = -ERESTARTSYS;
519 goto exit;
520 }
521
522 if (dev->open_count != 1) {
523 retval = -ENODEV;
524 goto unlock_exit;
525 }
526
527 if (dev->intf == NULL) {
528 /* the device was unplugged before the file was released */
529 up(&dev->sem);
530 /* unlock here as usb_tranzport_delete frees dev */
531 usb_tranzport_delete(dev);
532 retval = -ENODEV;
533 goto exit;
534 }
535
536 /* wait until write transfer is finished */
537 if (dev->interrupt_out_busy)
538 wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ);
539 usb_tranzport_abort_transfers(dev);
540 dev->open_count = 0;
541
542unlock_exit:
543 up(&dev->sem);
544
545exit:
546 return retval;
547}
548
549/**
550 * usb_tranzport_poll
551 */
552static unsigned int usb_tranzport_poll(struct file *file, poll_table *wait)
553{
554 struct usb_tranzport *dev;
555 unsigned int mask = 0;
556
557 dev = file->private_data;
558
559 poll_wait(file, &dev->read_wait, wait);
560 poll_wait(file, &dev->write_wait, wait);
561
562 if (dev->ring_head != dev->ring_tail)
563 mask |= POLLIN | POLLRDNORM;
564 if (!dev->interrupt_out_busy)
565 mask |= POLLOUT | POLLWRNORM;
566
567 return mask;
568}
569
570/**
571 * usb_tranzport_read
572 */
573static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, size_t count,
574 loff_t *ppos)
575{
576 struct usb_tranzport *dev;
577 size_t bytes_to_read;
578 int retval = 0;
579
580#if BUFFERED_READS
581 int c = 0;
582#endif
583
584#if COMPRESS_WHEEL_EVENTS
585 signed char oldwheel;
586 signed char newwheel;
587 int cancompress = 1;
588 int next_tail;
589#endif
590
591/* do I have such a thing as a null event? */
592
593 dev = file->private_data;
594
595 /* verify that we actually have some data to read */
596 if (count == 0)
597 goto exit;
598
599 /* lock this object */
600 if (down_interruptible(&dev->sem)) {
601 retval = -ERESTARTSYS;
602 goto exit;
603 }
604
605 /* verify that the device wasn't unplugged */
606 if (dev->intf == NULL) {
607 retval = -ENODEV;
608 err("No device or device unplugged %d\n", retval);
609 goto unlock_exit;
610 }
611
612 while (dev->ring_head == dev->ring_tail) {
613
614 if (file->f_flags & O_NONBLOCK) {
615 retval = -EAGAIN;
616 goto unlock_exit;
617 }
618 // atomic_cmp_exchange(&dev->interrupt_in_done,0,0);
619 dev->interrupt_in_done = 0 ; /* tiny race - FIXME: make atomic? */
620 retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
621 if (retval < 0) {
622 goto unlock_exit;
623 }
624 }
625
626 dbg_info(&dev->intf->dev, "%s: copying to userspace: %02x%02x%02x%02x%02x%02x%02x%02x\n",
627 __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
628
629#if BUFFERED_READS
630 c = 0;
631 while((c < count) && (dev->ring_tail != dev->ring_head)) {
632
633/* This started off in the lower level service routine, and I moved it here. Then my brain died. Not done yet. */
634#if COMPRESS_WHEEL_EVENTS
635 next_tail = (dev->ring_tail+1) % ring_buffer_size;
636 if(dev->compress_wheel) cancompress = 1;
637 while(dev->ring_head != next_tail && cancompress == 1 ) {
638 newwheel = (*dev->ring_buffer)[next_tail].cmd[6];
639 oldwheel = (*dev->ring_buffer)[dev->ring_tail].cmd[6];
640 // if both are wheel events, and no buttons have changes (FIXME, do I have to check?),
641 // and we are the same sign, we can compress +- 7F
642 // FIXME: saner check for overflow! - max of +- 7F
643 // FIXME the math is wrong for going in reverse, actually, as the midi spec doesn't allow signed chars
644
645 dbg_info(&dev->intf->dev, "%s: trying to compress: %02x%02x%02x%02x%02x %02x %02x %02x\n",
646 __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
647
648
649 if(((*dev->ring_buffer)[dev->ring_tail].cmd[6] != 0 &&
650 (*dev->ring_buffer)[next_tail].cmd[6] != 0 ) &&
651 ((newwheel > 0 && oldwheel > 0) ||
652 (newwheel < 0 && oldwheel < 0)) &&
653 ((*dev->ring_buffer)[dev->ring_tail].cmd[2] == (*dev->ring_buffer)[next_tail].cmd[2]) &&
654 ((*dev->ring_buffer)[dev->ring_tail].cmd[3] == (*dev->ring_buffer)[next_tail].cmd[3]) &&
655 ((*dev->ring_buffer)[dev->ring_tail].cmd[4] == (*dev->ring_buffer)[next_tail].cmd[4]) &&
656 ((*dev->ring_buffer)[dev->ring_tail].cmd[5] == (*dev->ring_buffer)[next_tail].cmd[5]))
657 {
658 dbg_info(&dev->intf->dev, "%s: should compress: %02x%02x%02x%02x%02x%02x%02x%02x\n",
659 __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
660
661 newwheel += oldwheel;
662 if(oldwheel > 0 && !(newwheel > 0)) {
663 newwheel = 0x7f;
664 cancompress = 0;
665 }
666 if(oldwheel < 0 && !(newwheel < 0)) {
667 newwheel = 0x80;
668 cancompress = 0;
669 }
670
671 (*dev->ring_buffer)[next_tail].cmd[6] = newwheel;
672 dev->ring_tail = next_tail;
673 next_tail = (dev->ring_tail+1) % ring_buffer_size;
674 } else {
675 cancompress = 0;
676 }
677 }
678#endif /* COMPRESS_WHEEL_EVENTS */
679
680 if (copy_to_user(&buffer[c], &(*dev->ring_buffer)[dev->ring_tail], 8)) {
681 retval = -EFAULT;
682 goto unlock_exit;
683 }
684
685 dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
686 c+=8;
687 dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
688 }
689 retval = c;
690
691#else
692 if (copy_to_user(buffer, &(*dev->ring_buffer)[dev->ring_tail], 8)) {
693 retval = -EFAULT;
694 goto unlock_exit;
695 }
696
697 dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
698 dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
699
700 retval = 8;
701#endif /* BUFFERED_READS */
702
703unlock_exit:
704 /* unlock the device */
705 up(&dev->sem);
706
707exit:
708 return retval;
709}
710
711/**
712 * usb_tranzport_write
713 */
714static ssize_t usb_tranzport_write(struct file *file, const char __user *buffer,
715 size_t count, loff_t *ppos)
716{
717 struct usb_tranzport *dev;
718 size_t bytes_to_write;
719 int retval = 0;
720
721 dev = file->private_data;
722
723 /* verify that we actually have some data to write */
724 if (count == 0)
725 goto exit;
726
727 /* lock this object */
728 if (down_interruptible(&dev->sem)) {
729 retval = -ERESTARTSYS;
730 goto exit;
731 }
732
733 /* verify that the device wasn't unplugged */
734 if (dev->intf == NULL) {
735 retval = -ENODEV;
736 err("No device or device unplugged %d\n", retval);
737 goto unlock_exit;
738 }
739
740 /* wait until previous transfer is finished */
741 if (dev->interrupt_out_busy) {
742 if (file->f_flags & O_NONBLOCK) {
743 retval = -EAGAIN;
744 goto unlock_exit;
745 }
746 retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy);
747 if (retval < 0) {
748 goto unlock_exit;
749 }
750 }
751
752 /* write the data into interrupt_out_buffer from userspace */
753 bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
754 if (bytes_to_write < count)
755 dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
756
757 dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
758
759 if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
760 retval = -EFAULT;
761 goto unlock_exit;
762 }
763
764 if (dev->interrupt_out_endpoint == NULL) {
765 err("Endpoint should not be be null! \n");
766 goto unlock_exit;
767 }
768
769 /* send off the urb */
770 usb_fill_int_urb(dev->interrupt_out_urb,
771 interface_to_usbdev(dev->intf),
772 usb_sndintpipe(interface_to_usbdev(dev->intf),
773 dev->interrupt_out_endpoint->bEndpointAddress),
774 dev->interrupt_out_buffer,
775 bytes_to_write,
776 usb_tranzport_interrupt_out_callback,
777 dev,
778 dev->interrupt_out_interval);
779
780 dev->interrupt_out_busy = 1;
781 wmb();
782
783 retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
784 if (retval) {
785 dev->interrupt_out_busy = 0;
786 err("Couldn't submit interrupt_out_urb %d\n", retval);
787 goto unlock_exit;
788 }
789 retval = bytes_to_write;
790
791unlock_exit:
792 /* unlock the device */
793 up(&dev->sem);
794
795exit:
796 return retval;
797}
798
799/* file operations needed when we register this driver */
800static const struct file_operations usb_tranzport_fops = {
801 .owner = THIS_MODULE,
802 .read = usb_tranzport_read,
803 .write = usb_tranzport_write,
804 .open = usb_tranzport_open,
805 .release = usb_tranzport_release,
806 .poll = usb_tranzport_poll,
807};
808
809/*
810 * usb class driver info in order to get a minor number from the usb core,
811 * and to have the device registered with the driver core
812 */
813static struct usb_class_driver usb_tranzport_class = {
814 .name = "tranzport%d",
815 .fops = &usb_tranzport_fops,
816 .minor_base = USB_TRANZPORT_MINOR_BASE,
817};
818
819
820/**
821 * usb_tranzport_probe
822 *
823 * Called by the usb core when a new device is connected that it thinks
824 * this driver might be interested in.
825 */
826static int usb_tranzport_probe(struct usb_interface *intf, const struct usb_device_id *id)
827{
828 struct usb_device *udev = interface_to_usbdev(intf);
829 struct usb_tranzport *dev = NULL;
830 struct usb_host_interface *iface_desc;
831 struct usb_endpoint_descriptor *endpoint;
832 int i;
833 int true_size;
834 int retval = -ENOMEM;
835
836 /* allocate memory for our device state and intialize it */
837
838 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
839 if (dev == NULL) {
840 dev_err(&intf->dev, "Out of memory\n");
841 goto exit;
842 }
843 init_MUTEX(&dev->sem);
844 dev->intf = intf;
845 init_waitqueue_head(&dev->read_wait);
846 init_waitqueue_head(&dev->write_wait);
847
848 iface_desc = intf->cur_altsetting;
849
850 /* set up the endpoint information */
851 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
852 endpoint = &iface_desc->endpoint[i].desc;
853
854 if (usb_endpoint_is_int_in(endpoint))
855 dev->interrupt_in_endpoint = endpoint;
856
857 if (usb_endpoint_is_int_out(endpoint))
858 dev->interrupt_out_endpoint = endpoint;
859 }
860 if (dev->interrupt_in_endpoint == NULL) {
861 dev_err(&intf->dev, "Interrupt in endpoint not found\n");
862 goto error;
863 }
864 if (dev->interrupt_out_endpoint == NULL)
865 dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
866
867
868 dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
869
870 if (dev->interrupt_in_endpoint_size != 8)
871 dev_warn(&intf->dev, "Interrupt in endpoint size is not 8!\n");
872
873 if(ring_buffer_size == 0) { ring_buffer_size = RING_BUFFER_SIZE; }
874 true_size = min(ring_buffer_size,RING_BUFFER_SIZE);
875 /* FIXME - there are more usb_alloc routines for dma correctness. Needed? */
876
877 dev->ring_buffer = kmalloc((true_size*sizeof(struct tranzport_cmd))+8, GFP_KERNEL);
878
879 if (!dev->ring_buffer) {
880 dev_err(&intf->dev, "Couldn't allocate ring_buffer of size %d\n",true_size);
881 goto error;
882 }
883 dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
884 if (!dev->interrupt_in_buffer) {
885 dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n");
886 goto error;
887 }
888 dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
889 if (!dev->interrupt_in_urb) {
890 dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
891 goto error;
892 }
893 dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) :
894 udev->descriptor.bMaxPacketSize0;
895
896 if (dev->interrupt_out_endpoint_size !=8)
897 dev_warn(&intf->dev, "Interrupt out endpoint size is not 8!)\n");
898
899 dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL);
900 if (!dev->interrupt_out_buffer) {
901 dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n");
902 goto error;
903 }
904 dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
905 if (!dev->interrupt_out_urb) {
906 dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n");
907 goto error;
908 }
909 dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
910 if (dev->interrupt_out_endpoint)
911 dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
912
913 /* we can register the device now, as it is ready */
914 usb_set_intfdata(intf, dev);
915
916 retval = usb_register_dev(intf, &usb_tranzport_class);
917 if (retval) {
918 /* something prevented us from registering this driver */
919 dev_err(&intf->dev, "Not able to get a minor for this device.\n");
920 usb_set_intfdata(intf, NULL);
921 goto error;
922 }
923
924 if((retval = device_create_file(&intf->dev, &dev_attr_LightRecord))) goto error;
925 if((retval = device_create_file(&intf->dev, &dev_attr_LightTrackrec))) goto error;
926 if((retval = device_create_file(&intf->dev, &dev_attr_LightTrackmute))) goto error;
927 if((retval = device_create_file(&intf->dev, &dev_attr_LightTracksolo))) goto error;
928 if((retval = device_create_file(&intf->dev, &dev_attr_LightAnysolo))) goto error;
929 if((retval = device_create_file(&intf->dev, &dev_attr_LightLoop))) goto error;
930 if((retval = device_create_file(&intf->dev, &dev_attr_LightPunch))) goto error;
931 if((retval = device_create_file(&intf->dev, &dev_attr_wheel))) goto error;
932 if((retval = device_create_file(&intf->dev, &dev_attr_event))) goto error;
933 if((retval = device_create_file(&intf->dev, &dev_attr_dump_state))) goto error;
934 if((retval = device_create_file(&intf->dev, &dev_attr_compress_wheel))) goto error;
935 if((retval = device_create_file(&intf->dev, &dev_attr_enable))) goto error;
936 if((retval = device_create_file(&intf->dev, &dev_attr_offline))) goto error;
937
938 /* let the user know what node this device is now attached to */
939 dev_info(&intf->dev, "Tranzport Device #%d now attached to major %d minor %d\n",
940 (intf->minor - USB_TRANZPORT_MINOR_BASE), USB_MAJOR, intf->minor);
941
942exit:
943 return retval;
944
945error:
946 usb_tranzport_delete(dev);
947
948 return retval;
949}
950
951/**
952 * usb_tranzport_disconnect
953 *
954 * Called by the usb core when the device is removed from the system.
955 */
956static void usb_tranzport_disconnect(struct usb_interface *intf)
957{
958 struct usb_tranzport *dev;
959 int minor;
960 mutex_lock(&disconnect_mutex);
961 dev = usb_get_intfdata(intf);
962 usb_set_intfdata(intf, NULL);
963 down(&dev->sem);
964 minor = intf->minor;
965 /* give back our minor */
966 usb_deregister_dev(intf, &usb_tranzport_class);
967
968 /* if the device is not opened, then we clean up right now */
969 if (!dev->open_count) {
970 up(&dev->sem);
971 usb_tranzport_delete(dev);
972 } else {
973 dev->intf = NULL;
974 up(&dev->sem);
975 }
976
977 mutex_unlock(&disconnect_mutex);
978
979 dev_info(&intf->dev, "Tranzport Surface #%d now disconnected\n",
980 (minor - USB_TRANZPORT_MINOR_BASE));
981}
982
983/* usb specific object needed to register this driver with the usb subsystem */
984static struct usb_driver usb_tranzport_driver = {
985 .name = "tranzport",
986 .probe = usb_tranzport_probe,
987 .disconnect = usb_tranzport_disconnect,
988 .id_table = usb_tranzport_table,
989};
990
991/**
992 * usb_tranzport_init
993 */
994static int __init usb_tranzport_init(void)
995{
996 int retval;
997
998 /* register this driver with the USB subsystem */
999 retval = usb_register(&usb_tranzport_driver);
1000 if (retval)
1001 err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval);
1002
1003 return retval;
1004}
1005
1006/**
1007 * usb_tranzport_exit
1008 */
1009static void __exit usb_tranzport_exit(void)
1010{
1011 /* deregister this driver with the USB subsystem */
1012 usb_deregister(&usb_tranzport_driver);
1013}
1014
1015module_init(usb_tranzport_init);
1016module_exit(usb_tranzport_exit);
1017