1 /* Hey EMACS -*- linux-c -*-
2  *
3  * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver.
4  * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org).
5  *
6  * Copyright (C) 2001-2004:
7  *   Romain Lievin <roms@lpg.ticalc.org>
8  *   Julien BLACHE <jb@technologeek.org>
9  * under the terms of the GNU General Public License.
10  *
11  * Based on dabusb.c, printer.c & scanner.c
12  *
13  * Please see the file: linux/Documentation/usb/SilverLink.txt
14  * and the website at:  http://lpg.ticalc.org/prj_usb/
15  * for more info.
16  *
17  * History:
18  *   1.0x, Romain & Julien: initial submit.
19  *   1.03, Greg Kroah: modifications.
20  *   1.04, Julien: clean-up & fixes; Romain: 2.4 backport.
21  *   1.05, Randy Dunlap: bug fix with the timeout parameter (divide-by-zero).
22  *   1.06, Romain: synched with 2.5, version/firmware changed (confusing).
23  *   1.07, Romain: fixed bad use of usb_clear_halt (invalid argument);
24  *          timeout argument checked in ioctl + clean-up.
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  * Version Information
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 /* ----- global variables --------------------------------------------- */
50 
51 static tiglusb_t tiglusb[MAXTIGL];
52 static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
53 
54 static devfs_handle_t devfs_handle;
55 
56 /*---------- misc functions ------------------------------------------- */
57 
58 /*
59  * Re-initialize device
60  */
61 static inline int
clear_device(struct usb_device * dev)62 clear_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  * Clear input & output pipes (endpoints)
74  */
75 static inline int
clear_pipes(struct usb_device * dev)76 clear_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 /* ----- file operations functions--------------------------------------- */
96 
97 static int
tiglusb_open(struct inode * inode,struct file * filp)98 tiglusb_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 
139 static int
tiglusb_release(struct inode * inode,struct file * filp)140 tiglusb_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 
161 static ssize_t
tiglusb_read(struct file * filp,char * buf,size_t count,loff_t * f_pos)162 tiglusb_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) {	/* NAK */
187 		if (!bytes_read)
188 			dbg ("quirk !");
189 		warn ("tiglusb_read, NAK received.");
190 		ret = result;
191 		goto out;
192 	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
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) {	/* We should not get any I/O errors */
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 
213 static ssize_t
tiglusb_write(struct file * filp,const char * buf,size_t count,loff_t * f_pos)214 tiglusb_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) {	/* NAK */
244 		warn ("tiglusb_write, NAK received.");
245 		ret = result;
246 		goto out;
247 	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
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) {	/* We should not get any I/O errors */
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 
268 static int
tiglusb_ioctl(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)269 tiglusb_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 /* ----- kernel module registering ------------------------------------ */
313 
314 static 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 /* --- initialisation code ------------------------------------- */
325 
326 static void *
tiglusb_probe(struct usb_device * dev,unsigned int ifnum,const struct usb_device_id * id)327 tiglusb_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 	 * We don't handle multiple configurations. As of version 0x0103 of
340 	 * the TIGL hardware, there's only 1 configuration.
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 	 * Find a tiglusb struct
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 	/* Display firmware version */
386 	info ("firmware revision %i.%02x",
387 		dev->descriptor.bcdDevice >> 8,
388 		dev->descriptor.bcdDevice & 0xff);
389 
390 	return s;
391 }
392 
393 static void
tiglusb_disconnect(struct usb_device * dev,void * drv_context)394 tiglusb_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 
417 static struct usb_device_id tiglusb_ids[] = {
418 	{USB_DEVICE (0x0451, 0xe001)},
419 	{}
420 };
421 
422 MODULE_DEVICE_TABLE (usb, tiglusb_ids);
423 
424 static 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 /* --- initialisation code ------------------------------------- */
433 
434 #ifndef MODULE
435 /*
436  * You can use 'tiusb=timeout' to set timeout.
437  */
438 static int __init
tiglusb_setup(char * str)439 tiglusb_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 
456 static int __init
tiglusb_init(void)457 tiglusb_init (void)
458 {
459 	unsigned u;
460 	int result;
461 
462 	/* initialize struct */
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 	/* register device */
475 	if (register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
476 		err ("unable to get major %d", TIUSB_MAJOR);
477 		return -EIO;
478 	}
479 
480 	/* Use devfs, tree: /dev/ticables/usb/[0..3] */
481 	devfs_handle = devfs_mk_dir (NULL, "ticables/usb", NULL);
482 
483 	/* register USB module */
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 
495 static void __exit
tiglusb_cleanup(void)496 tiglusb_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);
506 module_init (tiglusb_init);
507 module_exit (tiglusb_cleanup);
508 
509 MODULE_AUTHOR (DRIVER_AUTHOR);
510 MODULE_DESCRIPTION (DRIVER_DESC);
511 MODULE_LICENSE (DRIVER_LICENSE);
512 
513 MODULE_PARM (timeout, "i");
514 MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)");
515 
516 /* --------------------------------------------------------------------- */
517