blob: 96c73726d74a4b5fe23a25a489582c13cc2282a1 [file] [log] [blame]
Greg KH3b86b202005-04-25 21:46:29 -07001/*
2 * AirPrime CDMA Wireless Serial USB driver
3 *
Andy Gay5dda1712006-07-03 18:43:01 -04004 * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
Greg KH3b86b202005-04-25 21:46:29 -07005 *
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
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/tty.h>
Andy Gay5dda1712006-07-03 18:43:01 -040014#include <linux/tty_flip.h>
Greg KH3b86b202005-04-25 21:46:29 -070015#include <linux/module.h>
16#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070017#include <linux/usb/serial.h>
Greg KH3b86b202005-04-25 21:46:29 -070018
19static struct usb_device_id id_table [] = {
Timothy Sipples34ab86e2006-06-16 20:42:59 +090020 { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
Andy Gay5dda1712006-07-03 18:43:01 -040021 { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
daniel@centurion.net.nzad0327d2006-11-11 15:47:52 +130022 { USB_DEVICE(0x1410, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */
Luiz Fernando N. Capitulino931b0412006-10-03 10:31:36 -030023 { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
Greg KH3b86b202005-04-25 21:46:29 -070024 { },
25};
26MODULE_DEVICE_TABLE(usb, id_table);
27
Andy Gay5dda1712006-07-03 18:43:01 -040028#define URB_TRANSFER_BUFFER_SIZE 4096
29#define NUM_READ_URBS 4
30#define NUM_WRITE_URBS 4
31#define NUM_BULK_EPS 3
32#define MAX_BULK_EPS 6
33
34/* if overridden by the user, then use their value for the size of the
35 * read and write urbs, and the number of endpoints */
36static int buffer_size = URB_TRANSFER_BUFFER_SIZE;
37static int endpoints = NUM_BULK_EPS;
38static int debug;
39struct airprime_private {
40 spinlock_t lock;
41 int outstanding_urbs;
42 int throttled;
43 struct urb *read_urbp[NUM_READ_URBS];
44};
45
David Howells7d12e782006-10-05 14:55:46 +010046static void airprime_read_bulk_callback(struct urb *urb)
Andy Gay5dda1712006-07-03 18:43:01 -040047{
48 struct usb_serial_port *port = urb->context;
49 unsigned char *data = urb->transfer_buffer;
50 struct tty_struct *tty;
51 int result;
52
53 dbg("%s - port %d", __FUNCTION__, port->number);
54
55 if (urb->status) {
56 dbg("%s - nonzero read bulk status received: %d",
57 __FUNCTION__, urb->status);
58 /* something happened, so free up the memory for this urb */
59 if (urb->transfer_buffer) {
60 kfree (urb->transfer_buffer);
61 urb->transfer_buffer = NULL;
62 }
63 return;
64 }
65 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
66
67 tty = port->tty;
68 if (tty && urb->actual_length) {
69 tty_insert_flip_string (tty, data, urb->actual_length);
70 tty_flip_buffer_push (tty);
71 }
72
73 result = usb_submit_urb (urb, GFP_ATOMIC);
74 if (result)
75 dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
76 __FUNCTION__, result);
77 return;
78}
79
David Howells7d12e782006-10-05 14:55:46 +010080static void airprime_write_bulk_callback(struct urb *urb)
Andy Gay5dda1712006-07-03 18:43:01 -040081{
82 struct usb_serial_port *port = urb->context;
83 struct airprime_private *priv = usb_get_serial_port_data(port);
84 unsigned long flags;
85
86 dbg("%s - port %d", __FUNCTION__, port->number);
87
88 /* free up the transfer buffer, as usb_free_urb() does not do this */
89 kfree (urb->transfer_buffer);
90
91 if (urb->status)
92 dbg("%s - nonzero write bulk status received: %d",
93 __FUNCTION__, urb->status);
94 spin_lock_irqsave(&priv->lock, flags);
95 --priv->outstanding_urbs;
96 spin_unlock_irqrestore(&priv->lock, flags);
97
98 usb_serial_port_softint(port);
99}
100
101static int airprime_open(struct usb_serial_port *port, struct file *filp)
102{
103 struct airprime_private *priv = usb_get_serial_port_data(port);
104 struct usb_serial *serial = port->serial;
105 struct urb *urb;
106 char *buffer = NULL;
107 int i;
108 int result = 0;
109
110 dbg("%s - port %d", __FUNCTION__, port->number);
111
112 /* initialize our private data structure if it isn't already created */
113 if (!priv) {
114 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
115 if (!priv) {
116 result = -ENOMEM;
117 goto out;
118 }
119 spin_lock_init(&priv->lock);
120 usb_set_serial_port_data(port, priv);
121 }
122
123 for (i = 0; i < NUM_READ_URBS; ++i) {
124 buffer = kmalloc(buffer_size, GFP_KERNEL);
125 if (!buffer) {
126 dev_err(&port->dev, "%s - out of memory.\n",
127 __FUNCTION__);
128 result = -ENOMEM;
129 goto errout;
130 }
131 urb = usb_alloc_urb(0, GFP_KERNEL);
132 if (!urb) {
Eric Sesterhenn0e185b72006-10-10 14:42:50 -0700133 kfree(buffer);
Andy Gay5dda1712006-07-03 18:43:01 -0400134 dev_err(&port->dev, "%s - no more urbs?\n",
135 __FUNCTION__);
136 result = -ENOMEM;
137 goto errout;
138 }
139 usb_fill_bulk_urb(urb, serial->dev,
140 usb_rcvbulkpipe(serial->dev,
141 port->bulk_out_endpointAddress),
142 buffer, buffer_size,
143 airprime_read_bulk_callback, port);
144 result = usb_submit_urb(urb, GFP_KERNEL);
145 if (result) {
146 dev_err(&port->dev,
147 "%s - failed submitting read urb %d for port %d, error %d\n",
148 __FUNCTION__, i, port->number, result);
149 goto errout;
150 }
151 /* remember this urb so we can kill it when the port is closed */
152 priv->read_urbp[i] = urb;
153 }
154 goto out;
155
156 errout:
157 /* some error happened, cancel any submitted urbs and clean up anything that
158 got allocated successfully */
159
160 for ( ; i >= 0; --i) {
161 urb = priv->read_urbp[i];
162 if (urb) {
163 /* This urb was submitted successfully. So we have to
164 cancel it.
165 Unlinking the urb will invoke read_bulk_callback()
166 with an error status, so its transfer buffer will
167 be freed there */
168 if (usb_unlink_urb (urb) != -EINPROGRESS) {
169 /* comments in drivers/usb/core/urb.c say this
170 can only happen if the urb was never submitted,
171 or has completed already.
172 Either way we may have to free the transfer
173 buffer here. */
174 if (urb->transfer_buffer) {
175 kfree (urb->transfer_buffer);
176 urb->transfer_buffer = NULL;
177 }
178 }
179 usb_free_urb (urb);
180 }
181 }
182
183 out:
184 return result;
185}
186
187static void airprime_close(struct usb_serial_port *port, struct file * filp)
188{
189 struct airprime_private *priv = usb_get_serial_port_data(port);
190 int i;
191
192 dbg("%s - port %d", __FUNCTION__, port->number);
193
194 /* killing the urb will invoke read_bulk_callback() with an error status,
195 so the transfer buffer will be freed there */
196 for (i = 0; i < NUM_READ_URBS; ++i) {
197 usb_kill_urb (priv->read_urbp[i]);
198 usb_free_urb (priv->read_urbp[i]);
199 }
200
201 /* free up private structure */
202 kfree (priv);
203 usb_set_serial_port_data(port, NULL);
204}
205
206static int airprime_write(struct usb_serial_port *port,
207 const unsigned char *buf, int count)
208{
209 struct airprime_private *priv = usb_get_serial_port_data(port);
210 struct usb_serial *serial = port->serial;
211 struct urb *urb;
212 unsigned char *buffer;
213 unsigned long flags;
214 int status;
215 dbg("%s - port %d", __FUNCTION__, port->number);
216
217 spin_lock_irqsave(&priv->lock, flags);
218 if (priv->outstanding_urbs > NUM_WRITE_URBS) {
219 spin_unlock_irqrestore(&priv->lock, flags);
220 dbg("%s - write limit hit\n", __FUNCTION__);
221 return 0;
222 }
223 spin_unlock_irqrestore(&priv->lock, flags);
224 buffer = kmalloc(count, GFP_ATOMIC);
225 if (!buffer) {
226 dev_err(&port->dev, "out of memory\n");
227 return -ENOMEM;
228 }
229 urb = usb_alloc_urb(0, GFP_ATOMIC);
230 if (!urb) {
231 dev_err(&port->dev, "no more free urbs\n");
232 kfree (buffer);
233 return -ENOMEM;
234 }
235 memcpy (buffer, buf, count);
236
237 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
238
239 usb_fill_bulk_urb(urb, serial->dev,
240 usb_sndbulkpipe(serial->dev,
241 port->bulk_out_endpointAddress),
242 buffer, count,
243 airprime_write_bulk_callback, port);
244
245 /* send it down the pipe */
246 status = usb_submit_urb(urb, GFP_ATOMIC);
247 if (status) {
248 dev_err(&port->dev,
249 "%s - usb_submit_urb(write bulk) failed with status = %d\n",
250 __FUNCTION__, status);
251 count = status;
252 kfree (buffer);
253 } else {
254 spin_lock_irqsave(&priv->lock, flags);
255 ++priv->outstanding_urbs;
256 spin_unlock_irqrestore(&priv->lock, flags);
257 }
258 /* we are done with this urb, so let the host driver
259 * really free it when it is finished with it */
260 usb_free_urb (urb);
261 return count;
262}
263
Greg KH3b86b202005-04-25 21:46:29 -0700264static struct usb_driver airprime_driver = {
Greg KH3b86b202005-04-25 21:46:29 -0700265 .name = "airprime",
266 .probe = usb_serial_probe,
267 .disconnect = usb_serial_disconnect,
268 .id_table = id_table,
Andy Gay5dda1712006-07-03 18:43:01 -0400269 .no_dynamic_id = 1,
Greg KH3b86b202005-04-25 21:46:29 -0700270};
271
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700272static struct usb_serial_driver airprime_device = {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700273 .driver = {
274 .owner = THIS_MODULE,
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700275 .name = "airprime",
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700276 },
Greg KH3b86b202005-04-25 21:46:29 -0700277 .id_table = id_table,
278 .num_interrupt_in = NUM_DONT_CARE,
279 .num_bulk_in = NUM_DONT_CARE,
280 .num_bulk_out = NUM_DONT_CARE,
Andy Gay5dda1712006-07-03 18:43:01 -0400281 .open = airprime_open,
282 .close = airprime_close,
283 .write = airprime_write,
Greg KH3b86b202005-04-25 21:46:29 -0700284};
285
286static int __init airprime_init(void)
287{
288 int retval;
289
Andy Gay5dda1712006-07-03 18:43:01 -0400290 airprime_device.num_ports =
291 (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
Greg KH3b86b202005-04-25 21:46:29 -0700292 retval = usb_serial_register(&airprime_device);
293 if (retval)
294 return retval;
295 retval = usb_register(&airprime_driver);
296 if (retval)
297 usb_serial_deregister(&airprime_device);
298 return retval;
299}
300
301static void __exit airprime_exit(void)
302{
Andy Gay5dda1712006-07-03 18:43:01 -0400303 dbg("%s", __FUNCTION__);
304
Greg KH3b86b202005-04-25 21:46:29 -0700305 usb_deregister(&airprime_driver);
306 usb_serial_deregister(&airprime_device);
307}
308
309module_init(airprime_init);
310module_exit(airprime_exit);
311MODULE_LICENSE("GPL");
Andy Gay5dda1712006-07-03 18:43:01 -0400312
313module_param(debug, bool, S_IRUGO | S_IWUSR);
314MODULE_PARM_DESC(debug, "Debug enabled");
315module_param(buffer_size, int, 0);
316MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
317module_param(endpoints, int, 0);
318MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");