usblcd.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*****************************************************************************
  2. * USBLCD Kernel Driver *
  3. * Version 1.05 *
  4. * (C) 2005 Georges Toth <g.toth@e-biz.lu> *
  5. * *
  6. * This file is licensed under the GPL. See COPYING in the package. *
  7. * Based on usb-skeleton.c 2.0 by Greg Kroah-Hartman (greg@kroah.com) *
  8. * *
  9. * *
  10. * 28.02.05 Complete rewrite of the original usblcd.c driver, *
  11. * based on usb_skeleton.c. *
  12. * This new driver allows more than one USB-LCD to be connected *
  13. * and controlled, at once *
  14. *****************************************************************************/
  15. #include <linux/module.h>
  16. #include <linux/kernel.h>
  17. #include <linux/init.h>
  18. #include <linux/slab.h>
  19. #include <linux/errno.h>
  20. #include <linux/mutex.h>
  21. #include <linux/uaccess.h>
  22. #include <linux/usb.h>
  23. #define DRIVER_VERSION "USBLCD Driver Version 1.05"
  24. #define USBLCD_MINOR 144
  25. #define IOCTL_GET_HARD_VERSION 1
  26. #define IOCTL_GET_DRV_VERSION 2
  27. static DEFINE_MUTEX(lcd_mutex);
  28. static const struct usb_device_id id_table[] = {
  29. { .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
  30. { },
  31. };
  32. MODULE_DEVICE_TABLE(usb, id_table);
  33. static DEFINE_MUTEX(open_disc_mutex);
  34. struct usb_lcd {
  35. struct usb_device *udev; /* init: probe_lcd */
  36. struct usb_interface *interface; /* the interface for
  37. this device */
  38. unsigned char *bulk_in_buffer; /* the buffer to receive
  39. data */
  40. size_t bulk_in_size; /* the size of the
  41. receive buffer */
  42. __u8 bulk_in_endpointAddr; /* the address of the
  43. bulk in endpoint */
  44. __u8 bulk_out_endpointAddr; /* the address of the
  45. bulk out endpoint */
  46. struct kref kref;
  47. struct semaphore limit_sem; /* to stop writes at
  48. full throttle from
  49. using up all RAM */
  50. struct usb_anchor submitted; /* URBs to wait for
  51. before suspend */
  52. };
  53. #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
  54. #define USB_LCD_CONCURRENT_WRITES 5
  55. static struct usb_driver lcd_driver;
  56. static void lcd_delete(struct kref *kref)
  57. {
  58. struct usb_lcd *dev = to_lcd_dev(kref);
  59. usb_put_dev(dev->udev);
  60. kfree(dev->bulk_in_buffer);
  61. kfree(dev);
  62. }
  63. static int lcd_open(struct inode *inode, struct file *file)
  64. {
  65. struct usb_lcd *dev;
  66. struct usb_interface *interface;
  67. int subminor, r;
  68. mutex_lock(&lcd_mutex);
  69. subminor = iminor(inode);
  70. interface = usb_find_interface(&lcd_driver, subminor);
  71. if (!interface) {
  72. mutex_unlock(&lcd_mutex);
  73. err("USBLCD: %s - error, can't find device for minor %d",
  74. __func__, subminor);
  75. return -ENODEV;
  76. }
  77. mutex_lock(&open_disc_mutex);
  78. dev = usb_get_intfdata(interface);
  79. if (!dev) {
  80. mutex_unlock(&open_disc_mutex);
  81. mutex_unlock(&lcd_mutex);
  82. return -ENODEV;
  83. }
  84. /* increment our usage count for the device */
  85. kref_get(&dev->kref);
  86. mutex_unlock(&open_disc_mutex);
  87. /* grab a power reference */
  88. r = usb_autopm_get_interface(interface);
  89. if (r < 0) {
  90. kref_put(&dev->kref, lcd_delete);
  91. mutex_unlock(&lcd_mutex);
  92. return r;
  93. }
  94. /* save our object in the file's private structure */
  95. file->private_data = dev;
  96. mutex_unlock(&lcd_mutex);
  97. return 0;
  98. }
  99. static int lcd_release(struct inode *inode, struct file *file)
  100. {
  101. struct usb_lcd *dev;
  102. dev = file->private_data;
  103. if (dev == NULL)
  104. return -ENODEV;
  105. /* decrement the count on our device */
  106. usb_autopm_put_interface(dev->interface);
  107. kref_put(&dev->kref, lcd_delete);
  108. return 0;
  109. }
  110. static ssize_t lcd_read(struct file *file, char __user * buffer,
  111. size_t count, loff_t *ppos)
  112. {
  113. struct usb_lcd *dev;
  114. int retval = 0;
  115. int bytes_read;
  116. dev = file->private_data;
  117. /* do a blocking bulk read to get data from the device */
  118. retval = usb_bulk_msg(dev->udev,
  119. usb_rcvbulkpipe(dev->udev,
  120. dev->bulk_in_endpointAddr),
  121. dev->bulk_in_buffer,
  122. min(dev->bulk_in_size, count),
  123. &bytes_read, 10000);
  124. /* if the read was successful, copy the data to userspace */
  125. if (!retval) {
  126. if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read))
  127. retval = -EFAULT;
  128. else
  129. retval = bytes_read;
  130. }
  131. return retval;
  132. }
  133. static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  134. {
  135. struct usb_lcd *dev;
  136. u16 bcdDevice;
  137. char buf[30];
  138. dev = file->private_data;
  139. if (dev == NULL)
  140. return -ENODEV;
  141. switch (cmd) {
  142. case IOCTL_GET_HARD_VERSION:
  143. mutex_lock(&lcd_mutex);
  144. bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
  145. sprintf(buf, "%1d%1d.%1d%1d",
  146. (bcdDevice & 0xF000)>>12,
  147. (bcdDevice & 0xF00)>>8,
  148. (bcdDevice & 0xF0)>>4,
  149. (bcdDevice & 0xF));
  150. mutex_unlock(&lcd_mutex);
  151. if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
  152. return -EFAULT;
  153. break;
  154. case IOCTL_GET_DRV_VERSION:
  155. sprintf(buf, DRIVER_VERSION);
  156. if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
  157. return -EFAULT;
  158. break;
  159. default:
  160. return -ENOTTY;
  161. break;
  162. }
  163. return 0;
  164. }
  165. static void lcd_write_bulk_callback(struct urb *urb)
  166. {
  167. struct usb_lcd *dev;
  168. int status = urb->status;
  169. dev = urb->context;
  170. /* sync/async unlink faults aren't errors */
  171. if (status &&
  172. !(status == -ENOENT ||
  173. status == -ECONNRESET ||
  174. status == -ESHUTDOWN)) {
  175. dbg("USBLCD: %s - nonzero write bulk status received: %d",
  176. __func__, status);
  177. }
  178. /* free up our allocated buffer */
  179. usb_free_coherent(urb->dev, urb->transfer_buffer_length,
  180. urb->transfer_buffer, urb->transfer_dma);
  181. up(&dev->limit_sem);
  182. }
  183. static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
  184. size_t count, loff_t *ppos)
  185. {
  186. struct usb_lcd *dev;
  187. int retval = 0, r;
  188. struct urb *urb = NULL;
  189. char *buf = NULL;
  190. dev = file->private_data;
  191. /* verify that we actually have some data to write */
  192. if (count == 0)
  193. goto exit;
  194. r = down_interruptible(&dev->limit_sem);
  195. if (r < 0)
  196. return -EINTR;
  197. /* create a urb, and a buffer for it, and copy the data to the urb */
  198. urb = usb_alloc_urb(0, GFP_KERNEL);
  199. if (!urb) {
  200. retval = -ENOMEM;
  201. goto err_no_buf;
  202. }
  203. buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL,
  204. &urb->transfer_dma);
  205. if (!buf) {
  206. retval = -ENOMEM;
  207. goto error;
  208. }
  209. if (copy_from_user(buf, user_buffer, count)) {
  210. retval = -EFAULT;
  211. goto error;
  212. }
  213. /* initialize the urb properly */
  214. usb_fill_bulk_urb(urb, dev->udev,
  215. usb_sndbulkpipe(dev->udev,
  216. dev->bulk_out_endpointAddr),
  217. buf, count, lcd_write_bulk_callback, dev);
  218. urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
  219. usb_anchor_urb(urb, &dev->submitted);
  220. /* send the data out the bulk port */
  221. retval = usb_submit_urb(urb, GFP_KERNEL);
  222. if (retval) {
  223. err("USBLCD: %s - failed submitting write urb, error %d",
  224. __func__, retval);
  225. goto error_unanchor;
  226. }
  227. /* release our reference to this urb,
  228. the USB core will eventually free it entirely */
  229. usb_free_urb(urb);
  230. exit:
  231. return count;
  232. error_unanchor:
  233. usb_unanchor_urb(urb);
  234. error:
  235. usb_free_coherent(dev->udev, count, buf, urb->transfer_dma);
  236. usb_free_urb(urb);
  237. err_no_buf:
  238. up(&dev->limit_sem);
  239. return retval;
  240. }
  241. static const struct file_operations lcd_fops = {
  242. .owner = THIS_MODULE,
  243. .read = lcd_read,
  244. .write = lcd_write,
  245. .open = lcd_open,
  246. .unlocked_ioctl = lcd_ioctl,
  247. .release = lcd_release,
  248. .llseek = noop_llseek,
  249. };
  250. /*
  251. * usb class driver info in order to get a minor number from the usb core,
  252. * and to have the device registered with the driver core
  253. */
  254. static struct usb_class_driver lcd_class = {
  255. .name = "lcd%d",
  256. .fops = &lcd_fops,
  257. .minor_base = USBLCD_MINOR,
  258. };
  259. static int lcd_probe(struct usb_interface *interface,
  260. const struct usb_device_id *id)
  261. {
  262. struct usb_lcd *dev = NULL;
  263. struct usb_host_interface *iface_desc;
  264. struct usb_endpoint_descriptor *endpoint;
  265. size_t buffer_size;
  266. int i;
  267. int retval = -ENOMEM;
  268. /* allocate memory for our device state and initialize it */
  269. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  270. if (dev == NULL) {
  271. err("Out of memory");
  272. goto error;
  273. }
  274. kref_init(&dev->kref);
  275. sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
  276. init_usb_anchor(&dev->submitted);
  277. dev->udev = usb_get_dev(interface_to_usbdev(interface));
  278. dev->interface = interface;
  279. if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) {
  280. dev_warn(&interface->dev, "USBLCD model not supported.\n");
  281. retval = -ENODEV;
  282. goto error;
  283. }
  284. /* set up the endpoint information */
  285. /* use only the first bulk-in and bulk-out endpoints */
  286. iface_desc = interface->cur_altsetting;
  287. for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
  288. endpoint = &iface_desc->endpoint[i].desc;
  289. if (!dev->bulk_in_endpointAddr &&
  290. usb_endpoint_is_bulk_in(endpoint)) {
  291. /* we found a bulk in endpoint */
  292. buffer_size = usb_endpoint_maxp(endpoint);
  293. dev->bulk_in_size = buffer_size;
  294. dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
  295. dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
  296. if (!dev->bulk_in_buffer) {
  297. err("Could not allocate bulk_in_buffer");
  298. goto error;
  299. }
  300. }
  301. if (!dev->bulk_out_endpointAddr &&
  302. usb_endpoint_is_bulk_out(endpoint)) {
  303. /* we found a bulk out endpoint */
  304. dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
  305. }
  306. }
  307. if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
  308. err("Could not find both bulk-in and bulk-out endpoints");
  309. goto error;
  310. }
  311. /* save our data pointer in this interface device */
  312. usb_set_intfdata(interface, dev);
  313. /* we can register the device now, as it is ready */
  314. retval = usb_register_dev(interface, &lcd_class);
  315. if (retval) {
  316. /* something prevented us from registering this driver */
  317. err("Not able to get a minor for this device.");
  318. usb_set_intfdata(interface, NULL);
  319. goto error;
  320. }
  321. i = le16_to_cpu(dev->udev->descriptor.bcdDevice);
  322. dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found "
  323. "at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8,
  324. (i & 0xF0)>>4, (i & 0xF), dev->udev->devnum);
  325. /* let the user know what node this device is now attached to */
  326. dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n",
  327. interface->minor);
  328. return 0;
  329. error:
  330. if (dev)
  331. kref_put(&dev->kref, lcd_delete);
  332. return retval;
  333. }
  334. static void lcd_draw_down(struct usb_lcd *dev)
  335. {
  336. int time;
  337. time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000);
  338. if (!time)
  339. usb_kill_anchored_urbs(&dev->submitted);
  340. }
  341. static int lcd_suspend(struct usb_interface *intf, pm_message_t message)
  342. {
  343. struct usb_lcd *dev = usb_get_intfdata(intf);
  344. if (!dev)
  345. return 0;
  346. lcd_draw_down(dev);
  347. return 0;
  348. }
  349. static int lcd_resume(struct usb_interface *intf)
  350. {
  351. return 0;
  352. }
  353. static void lcd_disconnect(struct usb_interface *interface)
  354. {
  355. struct usb_lcd *dev;
  356. int minor = interface->minor;
  357. mutex_lock(&open_disc_mutex);
  358. dev = usb_get_intfdata(interface);
  359. usb_set_intfdata(interface, NULL);
  360. mutex_unlock(&open_disc_mutex);
  361. /* give back our minor */
  362. usb_deregister_dev(interface, &lcd_class);
  363. /* decrement our usage count */
  364. kref_put(&dev->kref, lcd_delete);
  365. dev_info(&interface->dev, "USB LCD #%d now disconnected\n", minor);
  366. }
  367. static struct usb_driver lcd_driver = {
  368. .name = "usblcd",
  369. .probe = lcd_probe,
  370. .disconnect = lcd_disconnect,
  371. .suspend = lcd_suspend,
  372. .resume = lcd_resume,
  373. .id_table = id_table,
  374. .supports_autosuspend = 1,
  375. };
  376. module_usb_driver(lcd_driver);
  377. MODULE_AUTHOR("Georges Toth <g.toth@e-biz.lu>");
  378. MODULE_DESCRIPTION(DRIVER_VERSION);
  379. MODULE_LICENSE("GPL");