1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <linux/module.h>
28#include <linux/socket.h>
29#include <linux/miscdevice.h>
30#include <linux/slab.h>
31#include <linux/init.h>
32#include <asm/uaccess.h>
33#include <linux/delay.h>
34#include <linux/usb.h>
35#include <linux/smp_lock.h>
36#include <linux/devfs_fs_kernel.h>
37
38#include <linux/ticable.h>
39#include "tiglusb.h"
40
41
42
43
44#define DRIVER_VERSION "1.07"
45#define DRIVER_AUTHOR "Romain Lievin <roms@tilp.info> & Julien Blache <jb@jblache.org>"
46#define DRIVER_DESC "TI-GRAPH LINK USB (aka SilverLink) driver"
47#define DRIVER_LICENSE "GPL"
48
49
50
51static tiglusb_t tiglusb[MAXTIGL];
52static int timeout = TIMAXTIME;
53
54static devfs_handle_t devfs_handle;
55
56
57
58
59
60
61static inline int
62clear_device (struct usb_device *dev)
63{
64 if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
65 err ("clear_device failed");
66 return -1;
67 }
68
69 return 0;
70}
71
72
73
74
75static inline int
76clear_pipes (struct usb_device *dev)
77{
78 unsigned int pipe;
79
80 pipe = usb_sndbulkpipe (dev, 2);
81 if (usb_clear_halt (dev, pipe)) {
82 err ("clear_pipe (w), request failed");
83 return -1;
84 }
85
86 pipe = usb_rcvbulkpipe (dev, 1);
87 if (usb_clear_halt (dev, pipe)) {
88 err ("clear_pipe (r), request failed");
89 return -1;
90 }
91
92 return 0;
93}
94
95
96
97static int
98tiglusb_open (struct inode *inode, struct file *filp)
99{
100 int devnum = minor (inode->i_rdev);
101 ptiglusb_t s;
102
103 if (devnum < TIUSB_MINOR || devnum >= (TIUSB_MINOR + MAXTIGL))
104 return -EIO;
105
106 s = &tiglusb[devnum - TIUSB_MINOR];
107
108 if (down_interruptible (&s->mutex)) {
109 return -ERESTARTSYS;
110 }
111
112 while (!s->dev || s->opened) {
113 up (&s->mutex);
114
115 if (filp->f_flags & O_NONBLOCK) {
116 return -EBUSY;
117 }
118
119 schedule_timeout (HZ / 2);
120
121 if (signal_pending (current)) {
122 return -EAGAIN;
123 }
124
125 if (down_interruptible (&s->mutex)) {
126 return -ERESTARTSYS;
127 }
128 }
129
130 s->opened = 1;
131 up (&s->mutex);
132
133 filp->f_pos = 0;
134 filp->private_data = s;
135
136 return 0;
137}
138
139static int
140tiglusb_release (struct inode *inode, struct file *filp)
141{
142 ptiglusb_t s = (ptiglusb_t) filp->private_data;
143
144 if (down_interruptible (&s->mutex)) {
145 return -ERESTARTSYS;
146 }
147
148 s->state = _stopped;
149 up (&s->mutex);
150
151 if (!s->remove_pending)
152 clear_device (s->dev);
153 else
154 wake_up (&s->remove_ok);
155
156 s->opened = 0;
157
158 return 0;
159}
160
161static ssize_t
162tiglusb_read (struct file *filp, char *buf, size_t count, loff_t * f_pos)
163{
164 ptiglusb_t s = (ptiglusb_t) filp->private_data;
165 ssize_t ret = 0;
166 int bytes_to_read = 0;
167 int bytes_read = 0;
168 int result = 0;
169 char buffer[BULK_RCV_MAX];
170 unsigned int pipe;
171
172 if (*f_pos)
173 return -ESPIPE;
174
175 if (s->remove_pending)
176 return -EIO;
177
178 if (!s->dev)
179 return -EIO;
180
181 bytes_to_read = (count >= BULK_RCV_MAX) ? BULK_RCV_MAX : count;
182
183 pipe = usb_rcvbulkpipe (s->dev, 1);
184 result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
185 &bytes_read, HZ * 10 / timeout);
186 if (result == -ETIMEDOUT) {
187 if (!bytes_read)
188 dbg ("quirk !");
189 warn ("tiglusb_read, NAK received.");
190 ret = result;
191 goto out;
192 } else if (result == -EPIPE) {
193 warn ("clear_halt request to remove STALL condition.");
194 if (usb_clear_halt (s->dev, pipe))
195 err ("clear_halt, request failed");
196 clear_device (s->dev);
197 ret = result;
198 goto out;
199 } else if (result < 0) {
200 err ("funky result: %d. Please notify maintainer.", result);
201 ret = -EIO;
202 goto out;
203 }
204
205 if (copy_to_user (buf, buffer, bytes_read)) {
206 ret = -EFAULT;
207 }
208
209 out:
210 return ret ? ret : bytes_read;
211}
212
213static ssize_t
214tiglusb_write (struct file *filp, const char *buf, size_t count, loff_t * f_pos)
215{
216 ptiglusb_t s = (ptiglusb_t) filp->private_data;
217 ssize_t ret = 0;
218 int bytes_to_write = 0;
219 int bytes_written = 0;
220 int result = 0;
221 char buffer[BULK_SND_MAX];
222 unsigned int pipe;
223
224 if (*f_pos)
225 return -ESPIPE;
226
227 if (s->remove_pending)
228 return -EIO;
229
230 if (!s->dev)
231 return -EIO;
232
233 bytes_to_write = (count >= BULK_SND_MAX) ? BULK_SND_MAX : count;
234 if (copy_from_user (buffer, buf, bytes_to_write)) {
235 ret = -EFAULT;
236 goto out;
237 }
238
239 pipe = usb_sndbulkpipe (s->dev, 2);
240 result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
241 &bytes_written, HZ * 10 / timeout);
242
243 if (result == -ETIMEDOUT) {
244 warn ("tiglusb_write, NAK received.");
245 ret = result;
246 goto out;
247 } else if (result == -EPIPE) {
248 warn ("clear_halt request to remove STALL condition.");
249 if (usb_clear_halt (s->dev, pipe))
250 err ("clear_halt, request failed");
251 clear_device (s->dev);
252 ret = result;
253 goto out;
254 } else if (result < 0) {
255 warn ("funky result: %d. Please notify maintainer.", result);
256 ret = -EIO;
257 goto out;
258 }
259
260 if (bytes_written != bytes_to_write) {
261 ret = -EIO;
262 }
263
264 out:
265 return ret ? ret : bytes_written;
266}
267
268static int
269tiglusb_ioctl (struct inode *inode, struct file *filp,
270 unsigned int cmd, unsigned long arg)
271{
272 ptiglusb_t s = (ptiglusb_t) filp->private_data;
273 int ret = 0;
274
275 if (s->remove_pending)
276 return -EIO;
277
278 if (down_interruptible (&s->mutex)) {
279 return -ERESTARTSYS;
280 }
281
282 if (!s->dev) {
283 up (&s->mutex);
284 return -EIO;
285 }
286
287 switch (cmd) {
288 case IOCTL_TIUSB_TIMEOUT:
289 if (arg > 0)
290 timeout = (int)arg;
291 else
292 ret = -EINVAL;
293 break;
294 case IOCTL_TIUSB_RESET_DEVICE:
295 if (clear_device (s->dev))
296 ret = -EIO;
297 break;
298 case IOCTL_TIUSB_RESET_PIPES:
299 if (clear_pipes (s->dev))
300 ret = -EIO;
301 break;
302 default:
303 ret = -ENOTTY;
304 break;
305 }
306
307 up (&s->mutex);
308
309 return ret;
310}
311
312
313
314static struct file_operations tiglusb_fops = {
315 .owner = THIS_MODULE,
316 .llseek = no_llseek,
317 .read = tiglusb_read,
318 .write = tiglusb_write,
319 .ioctl = tiglusb_ioctl,
320 .open = tiglusb_open,
321 .release = tiglusb_release,
322};
323
324
325
326static void *
327tiglusb_probe (struct usb_device *dev, unsigned int ifnum,
328 const struct usb_device_id *id)
329{
330 int minor = -1;
331 int i;
332 ptiglusb_t s;
333 char name[8];
334
335 dbg ("probing vendor id 0x%x, device id 0x%x ifnum:%d",
336 dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
337
338
339
340
341
342
343 if (dev->descriptor.bNumConfigurations != 1)
344 return NULL;
345
346 if ((dev->descriptor.idProduct != 0xe001)
347 && (dev->descriptor.idVendor != 0x451))
348 return NULL;
349
350 if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
351 err ("tiglusb_probe: set_configuration failed");
352 return NULL;
353 }
354
355
356
357
358 for (i = 0; i < MAXTIGL; i++) {
359 ptiglusb_t s = &tiglusb[i];
360 if (!s->dev) {
361 minor = i;
362 break;
363 }
364 }
365
366 if (minor == -1)
367 return NULL;
368
369 s = &tiglusb[minor];
370
371 down (&s->mutex);
372 s->remove_pending = 0;
373 s->dev = dev;
374 up (&s->mutex);
375 dbg ("bound to interface: %d", ifnum);
376
377 sprintf (name, "%d", s->minor);
378 dbg ("registering to devfs : major = %d, minor = %d, node = %s",
379 TIUSB_MAJOR, (TIUSB_MINOR + s->minor), name);
380 s->devfs =
381 devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR,
382 TIUSB_MINOR + s->minor, S_IFCHR | S_IRUGO | S_IWUGO,
383 &tiglusb_fops, NULL);
384
385
386 info ("firmware revision %i.%02x",
387 dev->descriptor.bcdDevice >> 8,
388 dev->descriptor.bcdDevice & 0xff);
389
390 return s;
391}
392
393static void
394tiglusb_disconnect (struct usb_device *dev, void *drv_context)
395{
396 ptiglusb_t s = (ptiglusb_t) drv_context;
397
398 if (!s || !s->dev)
399 info ("bogus disconnect");
400
401 s->remove_pending = 1;
402 wake_up (&s->wait);
403 if (s->state == _started)
404 sleep_on (&s->remove_ok);
405 down (&s->mutex);
406 s->dev = NULL;
407 s->opened = 0;
408
409 devfs_unregister (s->devfs);
410 s->devfs = NULL;
411
412 info ("device %d removed", s->minor);
413
414 up (&s->mutex);
415}
416
417static struct usb_device_id tiglusb_ids[] = {
418 {USB_DEVICE (0x0451, 0xe001)},
419 {}
420};
421
422MODULE_DEVICE_TABLE (usb, tiglusb_ids);
423
424static struct usb_driver tiglusb_driver = {
425 .owner = THIS_MODULE,
426 .name = "tiglusb",
427 .probe = tiglusb_probe,
428 .disconnect = tiglusb_disconnect,
429 .id_table = tiglusb_ids,
430};
431
432
433
434#ifndef MODULE
435
436
437
438static int __init
439tiglusb_setup (char *str)
440{
441 int ints[2];
442
443 str = get_options (str, ARRAY_SIZE (ints), ints);
444
445 if (ints[0] > 0) {
446 if (ints[1] > 0)
447 timeout = ints[1];
448 else
449 info ("tiglusb: wrong timeout value (0), using default value.");
450 }
451
452 return 1;
453}
454#endif
455
456static int __init
457tiglusb_init (void)
458{
459 unsigned u;
460 int result;
461
462
463 for (u = 0; u < MAXTIGL; u++) {
464 ptiglusb_t s = &tiglusb[u];
465 memset (s, 0, sizeof (tiglusb_t));
466 init_MUTEX (&s->mutex);
467 s->dev = NULL;
468 s->minor = u;
469 s->opened = 0;
470 init_waitqueue_head (&s->wait);
471 init_waitqueue_head (&s->remove_ok);
472 }
473
474
475 if (register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
476 err ("unable to get major %d", TIUSB_MAJOR);
477 return -EIO;
478 }
479
480
481 devfs_handle = devfs_mk_dir (NULL, "ticables/usb", NULL);
482
483
484 result = usb_register (&tiglusb_driver);
485 if (result < 0) {
486 unregister_chrdev (TIUSB_MAJOR, "tiglusb");
487 return -1;
488 }
489
490 info (DRIVER_DESC ", version " DRIVER_VERSION);
491
492 return 0;
493}
494
495static void __exit
496tiglusb_cleanup (void)
497{
498 usb_deregister (&tiglusb_driver);
499 devfs_unregister (devfs_handle);
500 unregister_chrdev (TIUSB_MAJOR, "tiglusb");
501}
502
503
504
505__setup ("tiusb=", tiglusb_setup);
506module_init (tiglusb_init);
507module_exit (tiglusb_cleanup);
508
509MODULE_AUTHOR (DRIVER_AUTHOR);
510MODULE_DESCRIPTION (DRIVER_DESC);
511MODULE_LICENSE (DRIVER_LICENSE);
512
513MODULE_PARM (timeout, "i");
514MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)");
515
516
517