tiglusb.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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-2002:
  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.  *  16/07/2002 : v1.04 -- Julien BLACHE <jb@jblache.org>
  19.  *    + removed useless usblp_cleanup()
  20.  *    + removed {un,}lock_kernel() as suggested on lkml
  21.  *    + inlined clear_pipes() (used once)
  22.  *    + inlined clear_device() (small, used twice)
  23.  *    + removed tiglusb_find_struct() (used once, simple code)
  24.  *    + replaced down() with down_interruptible() wherever possible
  25.  *    + fixed double unregistering wrt devfs, causing devfs
  26.  *      to force an oops when the device is deconnected
  27.  *    + removed unused fields from struct tiglusb_t
  28.  */
  29. #include <linux/module.h>
  30. #include <linux/socket.h>
  31. #include <linux/miscdevice.h>
  32. #include <linux/slab.h>
  33. #include <linux/init.h>
  34. #include <asm/uaccess.h>
  35. #include <linux/delay.h>
  36. #include <linux/usb.h>
  37. #include <linux/smp_lock.h>
  38. #include <linux/devfs_fs_kernel.h>
  39. #include <linux/ticable.h>
  40. #include "tiglusb.h"
  41. /*
  42.  * Version Information
  43.  */
  44. #define DRIVER_VERSION "1.04"
  45. #define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
  46. #define DRIVER_DESC    "TI-GRAPH LINK USB (aka SilverLink) driver"
  47. #define DRIVER_LICENSE "GPL"
  48. /* ----- global variables --------------------------------------------- */
  49. static tiglusb_t tiglusb[MAXTIGL];
  50. static int timeout = TIMAXTIME; /* timeout in tenth of seconds     */
  51. static devfs_handle_t devfs_handle;
  52. /*---------- misc functions ------------------------------------------- */
  53. /*
  54.  * Re-initialize device
  55.  */
  56. static inline int
  57. clear_device (struct usb_device *dev)
  58. {
  59. if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
  60. err ("clear_device failed");
  61. return -1;
  62. }
  63. return 0;
  64. }
  65. /* 
  66.  * Clear input & output pipes (endpoints)
  67.  */
  68. static inline int
  69. clear_pipes (struct usb_device *dev)
  70. {
  71. unsigned int pipe;
  72. pipe = usb_sndbulkpipe (dev, 1);
  73. if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
  74. err ("clear_pipe (r), request failed");
  75. return -1;
  76. }
  77. pipe = usb_sndbulkpipe (dev, 2);
  78. if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
  79. err ("clear_pipe (w), request failed");
  80. return -1;
  81. }
  82. return 0;
  83. }
  84. /* ----- file operations functions--------------------------------------- */
  85. static int
  86. tiglusb_open (struct inode *inode, struct file *filp)
  87. {
  88. int devnum = minor (inode->i_rdev);
  89. ptiglusb_t s;
  90. if (devnum < TIUSB_MINOR || devnum >= (TIUSB_MINOR + MAXTIGL))
  91. return -EIO;
  92. s = &tiglusb[devnum - TIUSB_MINOR];
  93. if (down_interruptible (&s->mutex)) {
  94. return -ERESTARTSYS;
  95. }
  96. while (!s->dev || s->opened) {
  97. up (&s->mutex);
  98. if (filp->f_flags & O_NONBLOCK) {
  99. return -EBUSY;
  100. }
  101. schedule_timeout (HZ / 2);
  102. if (signal_pending (current)) {
  103. return -EAGAIN;
  104. }
  105. if (down_interruptible (&s->mutex)) {
  106. return -ERESTARTSYS;
  107. }
  108. }
  109. s->opened = 1;
  110. up (&s->mutex);
  111. filp->f_pos = 0;
  112. filp->private_data = s;
  113. return 0;
  114. }
  115. static int
  116. tiglusb_release (struct inode *inode, struct file *filp)
  117. {
  118. ptiglusb_t s = (ptiglusb_t) filp->private_data;
  119. if (down_interruptible (&s->mutex)) {
  120. return -ERESTARTSYS;
  121. }
  122. s->state = _stopped;
  123. up (&s->mutex);
  124. if (!s->remove_pending)
  125. clear_device (s->dev);
  126. else
  127. wake_up (&s->remove_ok);
  128. s->opened = 0;
  129. return 0;
  130. }
  131. static ssize_t
  132. tiglusb_read (struct file *filp, char *buf, size_t count, loff_t * f_pos)
  133. {
  134. ptiglusb_t s = (ptiglusb_t) filp->private_data;
  135. ssize_t ret = 0;
  136. int bytes_to_read = 0;
  137. int bytes_read = 0;
  138. int result = 0;
  139. char buffer[BULK_RCV_MAX];
  140. unsigned int pipe;
  141. if (*f_pos)
  142. return -ESPIPE;
  143. if (s->remove_pending)
  144. return -EIO;
  145. if (!s->dev)
  146. return -EIO;
  147. bytes_to_read = (count >= BULK_RCV_MAX) ? BULK_RCV_MAX : count;
  148. pipe = usb_rcvbulkpipe (s->dev, 1);
  149. result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
  150.        &bytes_read, HZ / (timeout / 10));
  151. if (result == -ETIMEDOUT) { /* NAK */
  152. ret = result;
  153. if (!bytes_read) {
  154. dbg ("quirk !");
  155. }
  156. warn ("tiglusb_read, NAK received.");
  157. goto out;
  158. } else if (result == -EPIPE) { /* STALL -- shouldn't happen */
  159. warn ("clear_halt request to remove STALL condition.");
  160. if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
  161. err ("clear_halt, request failed");
  162. clear_device (s->dev);
  163. ret = result;
  164. goto out;
  165. } else if (result < 0) { /* We should not get any I/O errors */
  166. err ("funky result: %d. Please notify maintainer.", result);
  167. ret = -EIO;
  168. goto out;
  169. }
  170. if (copy_to_user (buf, buffer, bytes_read)) {
  171. ret = -EFAULT;
  172. }
  173.       out:
  174. return ret ? ret : bytes_read;
  175. }
  176. static ssize_t
  177. tiglusb_write (struct file *filp, const char *buf, size_t count, loff_t * f_pos)
  178. {
  179. ptiglusb_t s = (ptiglusb_t) filp->private_data;
  180. ssize_t ret = 0;
  181. int bytes_to_write = 0;
  182. int bytes_written = 0;
  183. int result = 0;
  184. char buffer[BULK_SND_MAX];
  185. unsigned int pipe;
  186. if (*f_pos)
  187. return -ESPIPE;
  188. if (s->remove_pending)
  189. return -EIO;
  190. if (!s->dev)
  191. return -EIO;
  192. bytes_to_write = (count >= BULK_SND_MAX) ? BULK_SND_MAX : count;
  193. if (copy_from_user (buffer, buf, bytes_to_write)) {
  194. ret = -EFAULT;
  195. goto out;
  196. }
  197. pipe = usb_sndbulkpipe (s->dev, 2);
  198. result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
  199.        &bytes_written, HZ / (timeout / 10));
  200. if (result == -ETIMEDOUT) { /* NAK */
  201. warn ("tiglusb_write, NAK received.");
  202. ret = result;
  203. goto out;
  204. } else if (result == -EPIPE) { /* STALL -- shouldn't happen */
  205. warn ("clear_halt request to remove STALL condition.");
  206. if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
  207. err ("clear_halt, request failed");
  208. clear_device (s->dev);
  209. ret = result;
  210. goto out;
  211. } else if (result < 0) { /* We should not get any I/O errors */
  212. warn ("funky result: %d. Please notify maintainer.", result);
  213. ret = -EIO;
  214. goto out;
  215. }
  216. if (bytes_written != bytes_to_write) {
  217. ret = -EIO;
  218. }
  219.       out:
  220. return ret ? ret : bytes_written;
  221. }
  222. static int
  223. tiglusb_ioctl (struct inode *inode, struct file *filp,
  224.        unsigned int cmd, unsigned long arg)
  225. {
  226. ptiglusb_t s = (ptiglusb_t) filp->private_data;
  227. int ret = 0;
  228. if (s->remove_pending)
  229. return -EIO;
  230. if (down_interruptible (&s->mutex)) {
  231. return -ERESTARTSYS;
  232. }
  233. if (!s->dev) {
  234. up (&s->mutex);
  235. return -EIO;
  236. }
  237. switch (cmd) {
  238. case IOCTL_TIUSB_TIMEOUT:
  239. timeout = arg; // timeout value in tenth of seconds
  240. break;
  241. case IOCTL_TIUSB_RESET_DEVICE:
  242. dbg ("IOCTL_TIGLUSB_RESET_DEVICE");
  243. if (clear_device (s->dev))
  244. ret = -EIO;
  245. break;
  246. case IOCTL_TIUSB_RESET_PIPES:
  247. dbg ("IOCTL_TIGLUSB_RESET_PIPES");
  248. if (clear_pipes (s->dev))
  249. ret = -EIO;
  250. break;
  251. default:
  252. ret = -ENOTTY;
  253. break;
  254. }
  255. up (&s->mutex);
  256. return ret;
  257. }
  258. /* ----- kernel module registering ------------------------------------ */
  259. static struct file_operations tiglusb_fops = {
  260. .llseek = no_llseek,
  261. .read = tiglusb_read,
  262. .write = tiglusb_write,
  263. .ioctl = tiglusb_ioctl,
  264. .open = tiglusb_open,
  265. .release = tiglusb_release,
  266. };
  267. /* --- initialisation code ------------------------------------- */
  268. static void *
  269. tiglusb_probe (struct usb_device *dev, unsigned int ifnum,
  270.        const struct usb_device_id *id)
  271. {
  272. int minor = -1;
  273. int i;
  274. ptiglusb_t s;
  275. char name[8];
  276. dbg ("probing vendor id 0x%x, device id 0x%x ifnum:%d",
  277.      dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
  278. /*
  279.  * We don't handle multiple configurations. As of version 0x0103 of
  280.  * the TIGL hardware, there's only 1 configuration.
  281.  */
  282. if (dev->descriptor.bNumConfigurations != 1)
  283. return NULL;
  284. if ((dev->descriptor.idProduct != 0xe001)
  285.     && (dev->descriptor.idVendor != 0x451))
  286. return NULL;
  287. if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
  288. err ("tiglusb_probe: set_configuration failed");
  289. return NULL;
  290. }
  291. /*
  292.  * Find a tiglusb struct
  293.  */
  294. for (i = 0; i < MAXTIGL; i++) {
  295. ptiglusb_t s = &tiglusb[i];
  296. if (!s->dev) {
  297. minor = i;
  298. break;
  299. }
  300. }
  301. if (minor == -1)
  302. return NULL;
  303. s = &tiglusb[minor];
  304. down (&s->mutex);
  305. s->remove_pending = 0;
  306. s->dev = dev;
  307. up (&s->mutex);
  308. dbg ("bound to interface: %d", ifnum);
  309. sprintf (name, "%d", s->minor);
  310. dbg ("registering to devfs : major = %d, minor = %d, node = %s",
  311.      TIUSB_MAJOR, (TIUSB_MINOR + s->minor), name);
  312. s->devfs =
  313.     devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR,
  314.     TIUSB_MINOR + s->minor, S_IFCHR | S_IRUGO | S_IWUGO,
  315.     &tiglusb_fops, NULL);
  316. /* Display firmware version */
  317. info ("link cable version %i.%02x",
  318. dev->descriptor.bcdDevice >> 8,
  319. dev->descriptor.bcdDevice & 0xff);
  320. return s;
  321. }
  322. static void
  323. tiglusb_disconnect (struct usb_device *dev, void *drv_context)
  324. {
  325. ptiglusb_t s = (ptiglusb_t) drv_context;
  326. if (!s || !s->dev)
  327. info ("bogus disconnect");
  328. s->remove_pending = 1;
  329. wake_up (&s->wait);
  330. if (s->state == _started)
  331. sleep_on (&s->remove_ok);
  332. down (&s->mutex);
  333. s->dev = NULL;
  334. s->opened = 0;
  335. devfs_unregister (s->devfs);
  336. s->devfs = NULL;
  337. info ("device %d removed", s->minor);
  338. up (&s->mutex);
  339. }
  340. static struct usb_device_id tiglusb_ids[] = {
  341. {USB_DEVICE (0x0451, 0xe001)},
  342. {}
  343. };
  344. MODULE_DEVICE_TABLE (usb, tiglusb_ids);
  345. static struct usb_driver tiglusb_driver = {
  346. .name = "tiglusb",
  347. .probe = tiglusb_probe,
  348. .disconnect = tiglusb_disconnect,
  349. .id_table = tiglusb_ids,
  350. };
  351. /* --- initialisation code ------------------------------------- */
  352. #ifndef MODULE
  353. /*
  354.  * You can use 'tiusb=timeout'
  355.  */
  356. static int __init
  357. tiglusb_setup (char *str)
  358. {
  359. int ints[2];
  360. str = get_options (str, ARRAY_SIZE (ints), ints);
  361. if (ints[0] > 0) {
  362. timeout = ints[1];
  363. }
  364. return 1;
  365. }
  366. #endif
  367. static int __init
  368. tiglusb_init (void)
  369. {
  370. unsigned u;
  371. int result;
  372. /* initialize struct */
  373. for (u = 0; u < MAXTIGL; u++) {
  374. ptiglusb_t s = &tiglusb[u];
  375. memset (s, 0, sizeof (tiglusb_t));
  376. init_MUTEX (&s->mutex);
  377. s->dev = NULL;
  378. s->minor = u;
  379. s->opened = 0;
  380. init_waitqueue_head (&s->wait);
  381. init_waitqueue_head (&s->remove_ok);
  382. }
  383. /* register device */
  384. if (devfs_register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
  385. err ("unable to get major %d", TIUSB_MAJOR);
  386. return -EIO;
  387. }
  388. /* Use devfs, tree: /dev/ticables/usb/[0..3] */
  389. devfs_handle = devfs_mk_dir (NULL, "ticables/usb", NULL);
  390. /* register USB module */
  391. result = usb_register (&tiglusb_driver);
  392. if (result < 0) {
  393. devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
  394. return -1;
  395. }
  396. info (DRIVER_DESC ", " DRIVER_VERSION);
  397. return 0;
  398. }
  399. static void __exit
  400. tiglusb_cleanup (void)
  401. {
  402. usb_deregister (&tiglusb_driver);
  403. devfs_unregister (devfs_handle);
  404. devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
  405. }
  406. /* --------------------------------------------------------------------- */
  407. __setup ("tiusb=", tiglusb_setup);
  408. module_init (tiglusb_init);
  409. module_exit (tiglusb_cleanup);
  410. MODULE_AUTHOR (DRIVER_AUTHOR);
  411. MODULE_DESCRIPTION (DRIVER_DESC);
  412. MODULE_LICENSE (DRIVER_LICENSE);
  413. MODULE_PARM (timeout, "i");
  414. MODULE_PARM_DESC (timeout, "Timeout (default=1.5 seconds)");
  415. /* --------------------------------------------------------------------- */