aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/airprime.c
diff options
context:
space:
mode:
authorAlan Cox <alan@redhat.com>2008-07-22 06:09:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-22 16:03:22 -0400
commit95da310e66ee8090119596c70ca8432e57f9a97f (patch)
tree7f18c30e9c9ad4d7d53df6453fa338be06f09a85 /drivers/usb/serial/airprime.c
parent1aa3692da57c773e5c76de55c5c4a953962d360e (diff)
usb_serial: API all change
USB serial likes to use port->tty back pointers for the real work it does and to do so without any actual locking. Unfortunately when you consider hangup events, hangup/parallel reopen or even worse hangup followed by parallel close events the tty->port and port->tty pointers are not guaranteed to be the same as port->tty is the active tty while tty->port is the port the tty may or may not still be attached to. So rework the entire API to pass the tty struct. For console cases we need to pass both for now. This shows up multiple drivers that immediately crash with USB console some of which have been fixed in the process. Longer term we need a proper tty as console abstraction Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/usb/serial/airprime.c')
-rw-r--r--drivers/usb/serial/airprime.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
new file mode 100644
index 000000000000..b3f1d1e82468
--- /dev/null
+++ b/drivers/usb/serial/airprime.c
@@ -0,0 +1,355 @@
1/*
2 * AirPrime CDMA Wireless Serial USB driver
3 *
4 * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
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
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/tty.h>
14#include <linux/tty_flip.h>
15#include <linux/module.h>
16#include <linux/usb.h>
17#include <linux/usb/serial.h>
18
19static struct usb_device_id id_table [] = {
20 { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
21 { },
22};
23MODULE_DEVICE_TABLE(usb, id_table);
24
25#define URB_TRANSFER_BUFFER_SIZE 4096
26#define NUM_READ_URBS 4
27#define NUM_WRITE_URBS 4
28#define NUM_BULK_EPS 3
29#define MAX_BULK_EPS 6
30
31/* if overridden by the user, then use their value for the size of the
32 * read and write urbs, and the number of endpoints */
33static int buffer_size = URB_TRANSFER_BUFFER_SIZE;
34static int endpoints = NUM_BULK_EPS;
35static int debug;
36struct airprime_private {
37 spinlock_t lock;
38 int outstanding_urbs;
39 int throttled;
40 struct urb *read_urbp[NUM_READ_URBS];
41
42 /* Settings for the port */
43 int rts_state; /* Handshaking pins (outputs) */
44 int dtr_state;
45 int cts_state; /* Handshaking pins (inputs) */
46 int dsr_state;
47 int dcd_state;
48 int ri_state;
49};
50
51static int airprime_send_setup(struct usb_serial_port *port)
52{
53 struct usb_serial *serial = port->serial;
54 struct airprime_private *priv;
55
56 dbg("%s", __func__);
57
58 if (port->number != 0)
59 return 0;
60
61 priv = usb_get_serial_port_data(port);
62
63 if (port->port.tty) {
64 int val = 0;
65 if (priv->dtr_state)
66 val |= 0x01;
67 if (priv->rts_state)
68 val |= 0x02;
69
70 return usb_control_msg(serial->dev,
71 usb_rcvctrlpipe(serial->dev, 0),
72 0x22, 0x21, val, 0, NULL, 0,
73 USB_CTRL_SET_TIMEOUT);
74 }
75
76 return 0;
77}
78
79static void airprime_read_bulk_callback(struct urb *urb)
80{
81 struct usb_serial_port *port = urb->context;
82 unsigned char *data = urb->transfer_buffer;
83 struct tty_struct *tty;
84 int result;
85 int status = urb->status;
86
87 dbg("%s - port %d", __func__, port->number);
88
89 if (status) {
90 dbg("%s - nonzero read bulk status received: %d",
91 __func__, status);
92 return;
93 }
94 usb_serial_debug_data(debug, &port->dev, __func__,
95 urb->actual_length, data);
96
97 tty = port->port.tty;
98 if (tty && urb->actual_length) {
99 tty_insert_flip_string(tty, data, urb->actual_length);
100 tty_flip_buffer_push(tty);
101 }
102
103 result = usb_submit_urb(urb, GFP_ATOMIC);
104 if (result)
105 dev_err(&port->dev,
106 "%s - failed resubmitting read urb, error %d\n",
107 __func__, result);
108 return;
109}
110
111static void airprime_write_bulk_callback(struct urb *urb)
112{
113 struct usb_serial_port *port = urb->context;
114 struct airprime_private *priv = usb_get_serial_port_data(port);
115 int status = urb->status;
116 unsigned long flags;
117
118 dbg("%s - port %d", __func__, port->number);
119
120 /* free up the transfer buffer, as usb_free_urb() does not do this */
121 kfree(urb->transfer_buffer);
122
123 if (status)
124 dbg("%s - nonzero write bulk status received: %d",
125 __func__, status);
126 spin_lock_irqsave(&priv->lock, flags);
127 --priv->outstanding_urbs;
128 spin_unlock_irqrestore(&priv->lock, flags);
129
130 usb_serial_port_softint(port);
131}
132
133static int airprime_open(struct tty_struct *tty, struct usb_serial_port *port,
134 struct file *filp)
135{
136 struct airprime_private *priv = usb_get_serial_port_data(port);
137 struct usb_serial *serial = port->serial;
138 struct urb *urb;
139 char *buffer = NULL;
140 int i;
141 int result = 0;
142
143 dbg("%s - port %d", __func__, port->number);
144
145 /* initialize our private data structure if it isn't already created */
146 if (!priv) {
147 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
148 if (!priv) {
149 result = -ENOMEM;
150 goto out;
151 }
152 spin_lock_init(&priv->lock);
153 usb_set_serial_port_data(port, priv);
154 }
155
156 /* Set some sane defaults */
157 priv->rts_state = 1;
158 priv->dtr_state = 1;
159
160 for (i = 0; i < NUM_READ_URBS; ++i) {
161 buffer = kmalloc(buffer_size, GFP_KERNEL);
162 if (!buffer) {
163 dev_err(&port->dev, "%s - out of memory.\n",
164 __func__);
165 result = -ENOMEM;
166 goto errout;
167 }
168 urb = usb_alloc_urb(0, GFP_KERNEL);
169 if (!urb) {
170 kfree(buffer);
171 dev_err(&port->dev, "%s - no more urbs?\n",
172 __func__);
173 result = -ENOMEM;
174 goto errout;
175 }
176 usb_fill_bulk_urb(urb, serial->dev,
177 usb_rcvbulkpipe(serial->dev,
178 port->bulk_out_endpointAddress),
179 buffer, buffer_size,
180 airprime_read_bulk_callback, port);
181 result = usb_submit_urb(urb, GFP_KERNEL);
182 if (result) {
183 usb_free_urb(urb);
184 kfree(buffer);
185 dev_err(&port->dev,
186 "%s - failed submitting read urb %d for port %d, error %d\n",
187 __func__, i, port->number, result);
188 goto errout;
189 }
190 /* remember this urb so we can kill it when the
191 port is closed */
192 priv->read_urbp[i] = urb;
193 }
194
195 airprime_send_setup(port);
196
197 goto out;
198
199 errout:
200 /* some error happened, cancel any submitted urbs and clean up
201 anything that got allocated successfully */
202
203 while (i-- != 0) {
204 urb = priv->read_urbp[i];
205 buffer = urb->transfer_buffer;
206 usb_kill_urb(urb);
207 usb_free_urb(urb);
208 kfree(buffer);
209 }
210
211 out:
212 return result;
213}
214
215static void airprime_close(struct tty_struct *tty,
216 struct usb_serial_port *port, struct file *filp)
217{
218 struct airprime_private *priv = usb_get_serial_port_data(port);
219 int i;
220
221 dbg("%s - port %d", __func__, port->number);
222
223 priv->rts_state = 0;
224 priv->dtr_state = 0;
225
226 mutex_lock(&port->serial->disc_mutex);
227 if (!port->serial->disconnected)
228 airprime_send_setup(port);
229 mutex_unlock(&port->serial->disc_mutex);
230
231 for (i = 0; i < NUM_READ_URBS; ++i) {
232 usb_kill_urb(priv->read_urbp[i]);
233 kfree(priv->read_urbp[i]->transfer_buffer);
234 usb_free_urb(priv->read_urbp[i]);
235 }
236
237 /* free up private structure */
238 kfree(priv);
239 usb_set_serial_port_data(port, NULL);
240}
241
242static int airprime_write(struct tty_struct *tty, struct usb_serial_port *port,
243 const unsigned char *buf, int count)
244{
245 struct airprime_private *priv = usb_get_serial_port_data(port);
246 struct usb_serial *serial = port->serial;
247 struct urb *urb;
248 unsigned char *buffer;
249 unsigned long flags;
250 int status;
251 dbg("%s - port %d", __func__, port->number);
252
253 spin_lock_irqsave(&priv->lock, flags);
254 if (priv->outstanding_urbs > NUM_WRITE_URBS) {
255 spin_unlock_irqrestore(&priv->lock, flags);
256 dbg("%s - write limit hit\n", __func__);
257 return 0;
258 }
259 spin_unlock_irqrestore(&priv->lock, flags);
260 buffer = kmalloc(count, GFP_ATOMIC);
261 if (!buffer) {
262 dev_err(&port->dev, "out of memory\n");
263 return -ENOMEM;
264 }
265 urb = usb_alloc_urb(0, GFP_ATOMIC);
266 if (!urb) {
267 dev_err(&port->dev, "no more free urbs\n");
268 kfree(buffer);
269 return -ENOMEM;
270 }
271 memcpy(buffer, buf, count);
272
273 usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
274
275 usb_fill_bulk_urb(urb, serial->dev,
276 usb_sndbulkpipe(serial->dev,
277 port->bulk_out_endpointAddress),
278 buffer, count,
279 airprime_write_bulk_callback, port);
280
281 /* send it down the pipe */
282 status = usb_submit_urb(urb, GFP_ATOMIC);
283 if (status) {
284 dev_err(&port->dev,
285 "%s - usb_submit_urb(write bulk) failed with status = %d\n",
286 __func__, status);
287 count = status;
288 kfree(buffer);
289 } else {
290 spin_lock_irqsave(&priv->lock, flags);
291 ++priv->outstanding_urbs;
292 spin_unlock_irqrestore(&priv->lock, flags);
293 }
294 /* we are done with this urb, so let the host driver
295 * really free it when it is finished with it */
296 usb_free_urb(urb);
297 return count;
298}
299
300static struct usb_driver airprime_driver = {
301 .name = "airprime",
302 .probe = usb_serial_probe,
303 .disconnect = usb_serial_disconnect,
304 .id_table = id_table,
305 .no_dynamic_id = 1,
306};
307
308static struct usb_serial_driver airprime_device = {
309 .driver = {
310 .owner = THIS_MODULE,
311 .name = "airprime",
312 },
313 .usb_driver = &airprime_driver,
314 .id_table = id_table,
315 .open = airprime_open,
316 .close = airprime_close,
317 .write = airprime_write,
318};
319
320static int __init airprime_init(void)
321{
322 int retval;
323
324 airprime_device.num_ports = endpoints;
325 if (endpoints < 0 || endpoints >= MAX_BULK_EPS)
326 airprime_device.num_ports = NUM_BULK_EPS;
327
328 retval = usb_serial_register(&airprime_device);
329 if (retval)
330 return retval;
331 retval = usb_register(&airprime_driver);
332 if (retval)
333 usb_serial_deregister(&airprime_device);
334 return retval;
335}
336
337static void __exit airprime_exit(void)
338{
339 dbg("%s", __func__);
340
341 usb_deregister(&airprime_driver);
342 usb_serial_deregister(&airprime_device);
343}
344
345module_init(airprime_init);
346module_exit(airprime_exit);
347MODULE_LICENSE("GPL");
348
349module_param(debug, bool, S_IRUGO | S_IWUSR);
350MODULE_PARM_DESC(debug, "Debug enabled");
351module_param(buffer_size, int, 0);
352MODULE_PARM_DESC(buffer_size,
353 "Size of the transfer buffers in bytes (default 4096)");
354module_param(endpoints, int, 0);
355MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");