sam-ba.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Atmel SAM Boot Assistant (SAM-BA) driver
  3. *
  4. * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License version
  8. * 2 as published by the Free Software Foundation.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/tty.h>
  12. #include <linux/module.h>
  13. #include <linux/moduleparam.h>
  14. #include <linux/usb.h>
  15. #include <linux/usb/serial.h>
  16. #define DRIVER_VERSION "v1.0"
  17. #define DRIVER_AUTHOR "Johan Hovold <jhovold@gmail.com>"
  18. #define DRIVER_DESC "Atmel SAM Boot Assistant (SAM-BA) driver"
  19. #define SAMBA_VENDOR_ID 0x3eb
  20. #define SAMBA_PRODUCT_ID 0x6124
  21. static int debug;
  22. static const struct usb_device_id id_table[] = {
  23. /*
  24. * NOTE: Only match the CDC Data interface.
  25. */
  26. { USB_DEVICE_AND_INTERFACE_INFO(SAMBA_VENDOR_ID, SAMBA_PRODUCT_ID,
  27. USB_CLASS_CDC_DATA, 0, 0) },
  28. { }
  29. };
  30. MODULE_DEVICE_TABLE(usb, id_table);
  31. static struct usb_driver samba_driver = {
  32. .name = "sam-ba",
  33. .probe = usb_serial_probe,
  34. .disconnect = usb_serial_disconnect,
  35. .id_table = id_table,
  36. .no_dynamic_id = 1,
  37. };
  38. /*
  39. * NOTE: The SAM-BA firmware cannot handle merged write requests so we cannot
  40. * use the generic write implementation (which uses the port write fifo).
  41. */
  42. static int samba_write(struct tty_struct *tty, struct usb_serial_port *port,
  43. const unsigned char *buf, int count)
  44. {
  45. struct urb *urb;
  46. unsigned long flags;
  47. int result;
  48. int i;
  49. if (!count)
  50. return 0;
  51. count = min_t(int, count, port->bulk_out_size);
  52. spin_lock_irqsave(&port->lock, flags);
  53. if (!port->write_urbs_free) {
  54. spin_unlock_irqrestore(&port->lock, flags);
  55. return 0;
  56. }
  57. i = find_first_bit(&port->write_urbs_free,
  58. ARRAY_SIZE(port->write_urbs));
  59. __clear_bit(i, &port->write_urbs_free);
  60. port->tx_bytes += count;
  61. spin_unlock_irqrestore(&port->lock, flags);
  62. urb = port->write_urbs[i];
  63. memcpy(urb->transfer_buffer, buf, count);
  64. urb->transfer_buffer_length = count;
  65. usb_serial_debug_data(debug, &port->dev, __func__, count,
  66. urb->transfer_buffer);
  67. result = usb_submit_urb(urb, GFP_ATOMIC);
  68. if (result) {
  69. dev_err(&port->dev, "%s - error submitting urb: %d\n",
  70. __func__, result);
  71. spin_lock_irqsave(&port->lock, flags);
  72. __set_bit(i, &port->write_urbs_free);
  73. port->tx_bytes -= count;
  74. spin_unlock_irqrestore(&port->lock, flags);
  75. return result;
  76. }
  77. return count;
  78. }
  79. static int samba_write_room(struct tty_struct *tty)
  80. {
  81. struct usb_serial_port *port = tty->driver_data;
  82. unsigned long flags;
  83. unsigned long free;
  84. int count;
  85. int room;
  86. spin_lock_irqsave(&port->lock, flags);
  87. free = port->write_urbs_free;
  88. spin_unlock_irqrestore(&port->lock, flags);
  89. count = hweight_long(free);
  90. room = count * port->bulk_out_size;
  91. dbg("%s - returns %d", __func__, room);
  92. return room;
  93. }
  94. static int samba_chars_in_buffer(struct tty_struct *tty)
  95. {
  96. struct usb_serial_port *port = tty->driver_data;
  97. unsigned long flags;
  98. int chars;
  99. spin_lock_irqsave(&port->lock, flags);
  100. chars = port->tx_bytes;
  101. spin_unlock_irqrestore(&port->lock, flags);
  102. dbg("%s - returns %d", __func__, chars);
  103. return chars;
  104. }
  105. static void samba_write_bulk_callback(struct urb *urb)
  106. {
  107. struct usb_serial_port *port = urb->context;
  108. unsigned long flags;
  109. int i;
  110. dbg("%s - port %d", __func__, port->number);
  111. for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
  112. if (port->write_urbs[i] == urb)
  113. break;
  114. }
  115. spin_lock_irqsave(&port->lock, flags);
  116. __set_bit(i, &port->write_urbs_free);
  117. port->tx_bytes -= urb->transfer_buffer_length;
  118. spin_unlock_irqrestore(&port->lock, flags);
  119. if (urb->status)
  120. dbg("%s - non-zero urb status: %d", __func__, urb->status);
  121. usb_serial_port_softint(port);
  122. }
  123. static struct usb_serial_driver samba_device = {
  124. .driver = {
  125. .owner = THIS_MODULE,
  126. .name = "sam-ba",
  127. },
  128. .usb_driver = &samba_driver,
  129. .id_table = id_table,
  130. .num_ports = 1,
  131. .bulk_in_size = 512,
  132. .bulk_out_size = 2048,
  133. .write = samba_write,
  134. .write_room = samba_write_room,
  135. .chars_in_buffer = samba_chars_in_buffer,
  136. .write_bulk_callback = samba_write_bulk_callback,
  137. .throttle = usb_serial_generic_throttle,
  138. .unthrottle = usb_serial_generic_unthrottle,
  139. };
  140. static int __init samba_init(void)
  141. {
  142. int retval;
  143. retval = usb_serial_register(&samba_device);
  144. if (retval)
  145. return retval;
  146. retval = usb_register(&samba_driver);
  147. if (retval) {
  148. usb_serial_deregister(&samba_device);
  149. return retval;
  150. }
  151. printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": "
  152. DRIVER_DESC "\n");
  153. return 0;
  154. }
  155. static void __exit samba_exit(void)
  156. {
  157. usb_deregister(&samba_driver);
  158. usb_serial_deregister(&samba_device);
  159. }
  160. module_init(samba_init);
  161. module_exit(samba_exit);
  162. MODULE_AUTHOR(DRIVER_AUTHOR);
  163. MODULE_DESCRIPTION(DRIVER_DESC);
  164. MODULE_VERSION(DRIVER_VERSION);
  165. MODULE_LICENSE("GPL");
  166. module_param(debug, bool, S_IRUGO | S_IWUSR);
  167. MODULE_PARM_DESC(debug, "Enable verbose debugging messages");