aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Gay <andy@andynet.net>2006-07-03 18:43:01 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 14:59:00 -0400
commit5dda171202f94127e49c12daf780cdae1b4e668b (patch)
tree475853f201f78fe7401d6a0e44d22ae46ec5d2be
parentfc849b85fb14ccbbc10098d501a870bc9b44a641 (diff)
USB: Airprime driver improvements to allow full speed EvDO transfers
Adapted from an earlier patch by Greg KH <gregkh@suse.de>. That patch added multiple read urbs and larger transfer buffers to allow data transfers at full EvDO speed. This version includes additional device IDs and fixes a memory leak in the transfer buffer allocation. Some (maybe all?) of the supported devices present multiple bulk endpoints, the additional EPs can be used for control and status functions, This version allocates 3 EPs by default, that can be changed using the 'endpoints' module parameter. Tested with Sierra Wireless EM5625 and MC5720 embedded modules. Device ID (0x0c88, 0x17da) for the Kyocera Wireless KPC650/Passport was added but is not yet tested. From: Andy Gay <andy@andynet.net> Cc: Kevin Lloyd <linux@sierrawireless.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/serial/airprime.c261
1 files changed, 256 insertions, 5 deletions
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 62082532a8b3..6e1a84a858d4 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * AirPrime CDMA Wireless Serial USB driver 2 * AirPrime CDMA Wireless Serial USB driver
3 * 3 *
4 * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de> 4 * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
5 * 5 *
6 * This program is free software; you can redistribute it and/or 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 7 * modify it under the terms of the GNU General Public License version
@@ -11,26 +11,264 @@
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/tty.h> 13#include <linux/tty.h>
14#include <linux/tty_flip.h>
14#include <linux/module.h> 15#include <linux/module.h>
15#include <linux/usb.h> 16#include <linux/usb.h>
16#include <linux/usb/serial.h> 17#include <linux/usb/serial.h>
17 18
18static struct usb_device_id id_table [] = { 19static struct usb_device_id id_table [] = {
19 { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ 20 { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
20 { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ 21 { USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
21 { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ 22 { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
23 { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
22 { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ 24 { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
23 { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ 25 { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
26 { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
24 { }, 27 { },
25}; 28};
26MODULE_DEVICE_TABLE(usb, id_table); 29MODULE_DEVICE_TABLE(usb, id_table);
27 30
31#define URB_TRANSFER_BUFFER_SIZE 4096
32#define NUM_READ_URBS 4
33#define NUM_WRITE_URBS 4
34#define NUM_BULK_EPS 3
35#define MAX_BULK_EPS 6
36
37/* if overridden by the user, then use their value for the size of the
38 * read and write urbs, and the number of endpoints */
39static int buffer_size = URB_TRANSFER_BUFFER_SIZE;
40static int endpoints = NUM_BULK_EPS;
41static int debug;
42struct airprime_private {
43 spinlock_t lock;
44 int outstanding_urbs;
45 int throttled;
46 struct urb *read_urbp[NUM_READ_URBS];
47};
48
49static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
50{
51 struct usb_serial_port *port = urb->context;
52 unsigned char *data = urb->transfer_buffer;
53 struct tty_struct *tty;
54 int result;
55
56 dbg("%s - port %d", __FUNCTION__, port->number);
57
58 if (urb->status) {
59 dbg("%s - nonzero read bulk status received: %d",
60 __FUNCTION__, urb->status);
61 /* something happened, so free up the memory for this urb */
62 if (urb->transfer_buffer) {
63 kfree (urb->transfer_buffer);
64 urb->transfer_buffer = NULL;
65 }
66 return;
67 }
68 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
69
70 tty = port->tty;
71 if (tty && urb->actual_length) {
72 tty_insert_flip_string (tty, data, urb->actual_length);
73 tty_flip_buffer_push (tty);
74 }
75
76 result = usb_submit_urb (urb, GFP_ATOMIC);
77 if (result)
78 dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
79 __FUNCTION__, result);
80 return;
81}
82
83static void airprime_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
84{
85 struct usb_serial_port *port = urb->context;
86 struct airprime_private *priv = usb_get_serial_port_data(port);
87 unsigned long flags;
88
89 dbg("%s - port %d", __FUNCTION__, port->number);
90
91 /* free up the transfer buffer, as usb_free_urb() does not do this */
92 kfree (urb->transfer_buffer);
93
94 if (urb->status)
95 dbg("%s - nonzero write bulk status received: %d",
96 __FUNCTION__, urb->status);
97 spin_lock_irqsave(&priv->lock, flags);
98 --priv->outstanding_urbs;
99 spin_unlock_irqrestore(&priv->lock, flags);
100
101 usb_serial_port_softint(port);
102}
103
104static int airprime_open(struct usb_serial_port *port, struct file *filp)
105{
106 struct airprime_private *priv = usb_get_serial_port_data(port);
107 struct usb_serial *serial = port->serial;
108 struct urb *urb;
109 char *buffer = NULL;
110 int i;
111 int result = 0;
112
113 dbg("%s - port %d", __FUNCTION__, port->number);
114
115 /* initialize our private data structure if it isn't already created */
116 if (!priv) {
117 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
118 if (!priv) {
119 result = -ENOMEM;
120 goto out;
121 }
122 spin_lock_init(&priv->lock);
123 usb_set_serial_port_data(port, priv);
124 }
125
126 for (i = 0; i < NUM_READ_URBS; ++i) {
127 buffer = kmalloc(buffer_size, GFP_KERNEL);
128 if (!buffer) {
129 dev_err(&port->dev, "%s - out of memory.\n",
130 __FUNCTION__);
131 result = -ENOMEM;
132 goto errout;
133 }
134 urb = usb_alloc_urb(0, GFP_KERNEL);
135 if (!urb) {
136 dev_err(&port->dev, "%s - no more urbs?\n",
137 __FUNCTION__);
138 result = -ENOMEM;
139 goto errout;
140 }
141 usb_fill_bulk_urb(urb, serial->dev,
142 usb_rcvbulkpipe(serial->dev,
143 port->bulk_out_endpointAddress),
144 buffer, buffer_size,
145 airprime_read_bulk_callback, port);
146 result = usb_submit_urb(urb, GFP_KERNEL);
147 if (result) {
148 dev_err(&port->dev,
149 "%s - failed submitting read urb %d for port %d, error %d\n",
150 __FUNCTION__, i, port->number, result);
151 goto errout;
152 }
153 /* remember this urb so we can kill it when the port is closed */
154 priv->read_urbp[i] = urb;
155 }
156 goto out;
157
158 errout:
159 /* some error happened, cancel any submitted urbs and clean up anything that
160 got allocated successfully */
161
162 for ( ; i >= 0; --i) {
163 urb = priv->read_urbp[i];
164 if (urb) {
165 /* This urb was submitted successfully. So we have to
166 cancel it.
167 Unlinking the urb will invoke read_bulk_callback()
168 with an error status, so its transfer buffer will
169 be freed there */
170 if (usb_unlink_urb (urb) != -EINPROGRESS) {
171 /* comments in drivers/usb/core/urb.c say this
172 can only happen if the urb was never submitted,
173 or has completed already.
174 Either way we may have to free the transfer
175 buffer here. */
176 if (urb->transfer_buffer) {
177 kfree (urb->transfer_buffer);
178 urb->transfer_buffer = NULL;
179 }
180 }
181 usb_free_urb (urb);
182 }
183 }
184
185 out:
186 return result;
187}
188
189static void airprime_close(struct usb_serial_port *port, struct file * filp)
190{
191 struct airprime_private *priv = usb_get_serial_port_data(port);
192 int i;
193
194 dbg("%s - port %d", __FUNCTION__, port->number);
195
196 /* killing the urb will invoke read_bulk_callback() with an error status,
197 so the transfer buffer will be freed there */
198 for (i = 0; i < NUM_READ_URBS; ++i) {
199 usb_kill_urb (priv->read_urbp[i]);
200 usb_free_urb (priv->read_urbp[i]);
201 }
202
203 /* free up private structure */
204 kfree (priv);
205 usb_set_serial_port_data(port, NULL);
206}
207
208static int airprime_write(struct usb_serial_port *port,
209 const unsigned char *buf, int count)
210{
211 struct airprime_private *priv = usb_get_serial_port_data(port);
212 struct usb_serial *serial = port->serial;
213 struct urb *urb;
214 unsigned char *buffer;
215 unsigned long flags;
216 int status;
217 dbg("%s - port %d", __FUNCTION__, port->number);
218
219 spin_lock_irqsave(&priv->lock, flags);
220 if (priv->outstanding_urbs > NUM_WRITE_URBS) {
221 spin_unlock_irqrestore(&priv->lock, flags);
222 dbg("%s - write limit hit\n", __FUNCTION__);
223 return 0;
224 }
225 spin_unlock_irqrestore(&priv->lock, flags);
226 buffer = kmalloc(count, GFP_ATOMIC);
227 if (!buffer) {
228 dev_err(&port->dev, "out of memory\n");
229 return -ENOMEM;
230 }
231 urb = usb_alloc_urb(0, GFP_ATOMIC);
232 if (!urb) {
233 dev_err(&port->dev, "no more free urbs\n");
234 kfree (buffer);
235 return -ENOMEM;
236 }
237 memcpy (buffer, buf, count);
238
239 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
240
241 usb_fill_bulk_urb(urb, serial->dev,
242 usb_sndbulkpipe(serial->dev,
243 port->bulk_out_endpointAddress),
244 buffer, count,
245 airprime_write_bulk_callback, port);
246
247 /* send it down the pipe */
248 status = usb_submit_urb(urb, GFP_ATOMIC);
249 if (status) {
250 dev_err(&port->dev,
251 "%s - usb_submit_urb(write bulk) failed with status = %d\n",
252 __FUNCTION__, status);
253 count = status;
254 kfree (buffer);
255 } else {
256 spin_lock_irqsave(&priv->lock, flags);
257 ++priv->outstanding_urbs;
258 spin_unlock_irqrestore(&priv->lock, flags);
259 }
260 /* we are done with this urb, so let the host driver
261 * really free it when it is finished with it */
262 usb_free_urb (urb);
263 return count;
264}
265
28static struct usb_driver airprime_driver = { 266static struct usb_driver airprime_driver = {
29 .name = "airprime", 267 .name = "airprime",
30 .probe = usb_serial_probe, 268 .probe = usb_serial_probe,
31 .disconnect = usb_serial_disconnect, 269 .disconnect = usb_serial_disconnect,
32 .id_table = id_table, 270 .id_table = id_table,
33 .no_dynamic_id = 1, 271 .no_dynamic_id = 1,
34}; 272};
35 273
36static struct usb_serial_driver airprime_device = { 274static struct usb_serial_driver airprime_device = {
@@ -42,13 +280,17 @@ static struct usb_serial_driver airprime_device = {
42 .num_interrupt_in = NUM_DONT_CARE, 280 .num_interrupt_in = NUM_DONT_CARE,
43 .num_bulk_in = NUM_DONT_CARE, 281 .num_bulk_in = NUM_DONT_CARE,
44 .num_bulk_out = NUM_DONT_CARE, 282 .num_bulk_out = NUM_DONT_CARE,
45 .num_ports = 1, 283 .open = airprime_open,
284 .close = airprime_close,
285 .write = airprime_write,
46}; 286};
47 287
48static int __init airprime_init(void) 288static int __init airprime_init(void)
49{ 289{
50 int retval; 290 int retval;
51 291
292 airprime_device.num_ports =
293 (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
52 retval = usb_serial_register(&airprime_device); 294 retval = usb_serial_register(&airprime_device);
53 if (retval) 295 if (retval)
54 return retval; 296 return retval;
@@ -60,6 +302,8 @@ static int __init airprime_init(void)
60 302
61static void __exit airprime_exit(void) 303static void __exit airprime_exit(void)
62{ 304{
305 dbg("%s", __FUNCTION__);
306
63 usb_deregister(&airprime_driver); 307 usb_deregister(&airprime_driver);
64 usb_serial_deregister(&airprime_device); 308 usb_serial_deregister(&airprime_device);
65} 309}
@@ -67,3 +311,10 @@ static void __exit airprime_exit(void)
67module_init(airprime_init); 311module_init(airprime_init);
68module_exit(airprime_exit); 312module_exit(airprime_exit);
69MODULE_LICENSE("GPL"); 313MODULE_LICENSE("GPL");
314
315module_param(debug, bool, S_IRUGO | S_IWUSR);
316MODULE_PARM_DESC(debug, "Debug enabled");
317module_param(buffer_size, int, 0);
318MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
319module_param(endpoints, int, 0);
320MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");