2 * Atmel SAM Boot Assistant (SAM-BA) driver
4 * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
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.
11 #include <linux/kernel.h>
12 #include <linux/tty.h>
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/usb.h>
16 #include <linux/usb/serial.h>
19 #define DRIVER_VERSION "v1.0"
20 #define DRIVER_AUTHOR "Johan Hovold <jhovold@gmail.com>"
21 #define DRIVER_DESC "Atmel SAM Boot Assistant (SAM-BA) driver"
23 #define SAMBA_VENDOR_ID 0x3eb
24 #define SAMBA_PRODUCT_ID 0x6124
29 static const struct usb_device_id id_table
[] = {
31 * NOTE: Only match the CDC Data interface.
33 { USB_DEVICE_AND_INTERFACE_INFO(SAMBA_VENDOR_ID
, SAMBA_PRODUCT_ID
,
34 USB_CLASS_CDC_DATA
, 0, 0) },
37 MODULE_DEVICE_TABLE(usb
, id_table
);
39 static struct usb_driver samba_driver
= {
41 .probe
= usb_serial_probe
,
42 .disconnect
= usb_serial_disconnect
,
49 * NOTE: The SAM-BA firmware cannot handle merged write requests so we cannot
50 * use the generic write implementation (which uses the port write fifo).
52 static int samba_write(struct tty_struct
*tty
, struct usb_serial_port
*port
,
53 const unsigned char *buf
, int count
)
63 count
= min_t(int, count
, port
->bulk_out_size
);
65 spin_lock_irqsave(&port
->lock
, flags
);
66 if (!port
->write_urbs_free
) {
67 spin_unlock_irqrestore(&port
->lock
, flags
);
70 i
= find_first_bit(&port
->write_urbs_free
,
71 ARRAY_SIZE(port
->write_urbs
));
72 __clear_bit(i
, &port
->write_urbs_free
);
73 port
->tx_bytes
+= count
;
74 spin_unlock_irqrestore(&port
->lock
, flags
);
76 urb
= port
->write_urbs
[i
];
77 memcpy(urb
->transfer_buffer
, buf
, count
);
78 urb
->transfer_buffer_length
= count
;
79 usb_serial_debug_data(debug
, &port
->dev
, __func__
, count
,
80 urb
->transfer_buffer
);
81 result
= usb_submit_urb(urb
, GFP_ATOMIC
);
83 dev_err(&port
->dev
, "%s - error submitting urb: %d\n",
85 spin_lock_irqsave(&port
->lock
, flags
);
86 __set_bit(i
, &port
->write_urbs_free
);
87 port
->tx_bytes
-= count
;
88 spin_unlock_irqrestore(&port
->lock
, flags
);
96 static int samba_write_room(struct tty_struct
*tty
)
98 struct usb_serial_port
*port
= tty
->driver_data
;
104 spin_lock_irqsave(&port
->lock
, flags
);
105 free
= port
->write_urbs_free
;
106 spin_unlock_irqrestore(&port
->lock
, flags
);
108 count
= hweight_long(free
);
109 room
= count
* port
->bulk_out_size
;
111 dbg("%s - returns %d", __func__
, room
);
116 static int samba_chars_in_buffer(struct tty_struct
*tty
)
118 struct usb_serial_port
*port
= tty
->driver_data
;
122 spin_lock_irqsave(&port
->lock
, flags
);
123 chars
= port
->tx_bytes
;
124 spin_unlock_irqrestore(&port
->lock
, flags
);
126 dbg("%s - returns %d", __func__
, chars
);
131 static void samba_write_bulk_callback(struct urb
*urb
)
133 struct usb_serial_port
*port
= urb
->context
;
137 dbg("%s - port %d", __func__
, port
->number
);
139 for (i
= 0; i
< ARRAY_SIZE(port
->write_urbs
); ++i
) {
140 if (port
->write_urbs
[i
] == urb
)
143 spin_lock_irqsave(&port
->lock
, flags
);
144 __set_bit(i
, &port
->write_urbs_free
);
145 port
->tx_bytes
-= urb
->transfer_buffer_length
;
146 spin_unlock_irqrestore(&port
->lock
, flags
);
149 dbg("%s - non-zero urb status: %d", __func__
, urb
->status
);
151 usb_serial_port_softint(port
);
154 static struct usb_serial_driver samba_device
= {
156 .owner
= THIS_MODULE
,
159 .usb_driver
= &samba_driver
,
160 .id_table
= id_table
,
163 .bulk_out_size
= 2048,
164 .write
= samba_write
,
165 .write_room
= samba_write_room
,
166 .chars_in_buffer
= samba_chars_in_buffer
,
167 .write_bulk_callback
= samba_write_bulk_callback
,
168 .throttle
= usb_serial_generic_throttle
,
169 .unthrottle
= usb_serial_generic_unthrottle
,
172 static int __init
samba_init(void)
176 retval
= usb_serial_register(&samba_device
);
180 retval
= usb_register(&samba_driver
);
182 usb_serial_deregister(&samba_device
);
186 printk(KERN_INFO KBUILD_MODNAME
": " DRIVER_VERSION
": "
191 static void __exit
samba_exit(void)
193 usb_deregister(&samba_driver
);
194 usb_serial_deregister(&samba_device
);
197 module_init(samba_init
);
198 module_exit(samba_exit
);
200 MODULE_AUTHOR(DRIVER_AUTHOR
);
201 MODULE_DESCRIPTION(DRIVER_DESC
);
202 MODULE_VERSION(DRIVER_VERSION
);
203 MODULE_LICENSE("GPL");
205 module_param(debug
, bool, S_IRUGO
| S_IWUSR
);
206 MODULE_PARM_DESC(debug
, "Enable verbose debugging messages");