Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * USB Serial Converter Generic functions | |
3 | * | |
4 | * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.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 | */ | |
11 | ||
12 | #include <linux/config.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/errno.h> | |
15 | #include <linux/slab.h> | |
16 | #include <linux/tty.h> | |
17 | #include <linux/tty_flip.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/moduleparam.h> | |
20 | #include <linux/usb.h> | |
21 | #include <asm/uaccess.h> | |
22 | #include "usb-serial.h" | |
23 | ||
24 | static int debug; | |
25 | ||
26 | #ifdef CONFIG_USB_SERIAL_GENERIC | |
27 | static __u16 vendor = 0x05f9; | |
28 | static __u16 product = 0xffff; | |
29 | ||
30 | module_param(vendor, ushort, 0); | |
31 | MODULE_PARM_DESC(vendor, "User specified USB idVendor"); | |
32 | ||
33 | module_param(product, ushort, 0); | |
34 | MODULE_PARM_DESC(product, "User specified USB idProduct"); | |
35 | ||
36 | static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ | |
37 | ||
38 | /* All of the device info needed for the Generic Serial Converter */ | |
ea65370d | 39 | struct usb_serial_driver usb_serial_generic_device = { |
18fcac35 GKH |
40 | .driver = { |
41 | .owner = THIS_MODULE, | |
269bda1c | 42 | .name = "generic", |
18fcac35 | 43 | }, |
1da177e4 LT |
44 | .id_table = generic_device_ids, |
45 | .num_interrupt_in = NUM_DONT_CARE, | |
46 | .num_bulk_in = NUM_DONT_CARE, | |
47 | .num_bulk_out = NUM_DONT_CARE, | |
48 | .num_ports = 1, | |
49 | .shutdown = usb_serial_generic_shutdown, | |
50 | }; | |
51 | ||
52 | /* we want to look at all devices, as the vendor/product id can change | |
53 | * depending on the command line argument */ | |
54 | static struct usb_device_id generic_serial_ids[] = { | |
55 | {.driver_info = 42}, | |
56 | {} | |
57 | }; | |
58 | ||
59 | static int generic_probe(struct usb_interface *interface, | |
60 | const struct usb_device_id *id) | |
61 | { | |
62 | const struct usb_device_id *id_pattern; | |
63 | ||
64 | id_pattern = usb_match_id(interface, generic_device_ids); | |
65 | if (id_pattern != NULL) | |
66 | return usb_serial_probe(interface, id); | |
67 | return -ENODEV; | |
68 | } | |
69 | ||
70 | static struct usb_driver generic_driver = { | |
1da177e4 LT |
71 | .name = "usbserial_generic", |
72 | .probe = generic_probe, | |
73 | .disconnect = usb_serial_disconnect, | |
74 | .id_table = generic_serial_ids, | |
ba9dc657 | 75 | .no_dynamic_id = 1, |
1da177e4 LT |
76 | }; |
77 | #endif | |
78 | ||
79 | int usb_serial_generic_register (int _debug) | |
80 | { | |
81 | int retval = 0; | |
82 | ||
83 | debug = _debug; | |
84 | #ifdef CONFIG_USB_SERIAL_GENERIC | |
85 | generic_device_ids[0].idVendor = vendor; | |
86 | generic_device_ids[0].idProduct = product; | |
87 | generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; | |
88 | ||
89 | /* register our generic driver with ourselves */ | |
90 | retval = usb_serial_register (&usb_serial_generic_device); | |
91 | if (retval) | |
92 | goto exit; | |
93 | retval = usb_register(&generic_driver); | |
94 | if (retval) | |
95 | usb_serial_deregister(&usb_serial_generic_device); | |
96 | exit: | |
97 | #endif | |
98 | return retval; | |
99 | } | |
100 | ||
101 | void usb_serial_generic_deregister (void) | |
102 | { | |
103 | #ifdef CONFIG_USB_SERIAL_GENERIC | |
104 | /* remove our generic driver */ | |
105 | usb_deregister(&generic_driver); | |
106 | usb_serial_deregister (&usb_serial_generic_device); | |
107 | #endif | |
108 | } | |
109 | ||
110 | int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) | |
111 | { | |
112 | struct usb_serial *serial = port->serial; | |
113 | int result = 0; | |
114 | ||
115 | dbg("%s - port %d", __FUNCTION__, port->number); | |
116 | ||
117 | /* force low_latency on so that our tty_push actually forces the data through, | |
118 | otherwise it is scheduled, and with high data rates (like with OHCI) data | |
119 | can get lost. */ | |
120 | if (port->tty) | |
121 | port->tty->low_latency = 1; | |
122 | ||
123 | /* if we have a bulk interrupt, start reading from it */ | |
124 | if (serial->num_bulk_in) { | |
125 | /* Start reading from the device */ | |
126 | usb_fill_bulk_urb (port->read_urb, serial->dev, | |
127 | usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), | |
128 | port->read_urb->transfer_buffer, | |
129 | port->read_urb->transfer_buffer_length, | |
130 | ((serial->type->read_bulk_callback) ? | |
131 | serial->type->read_bulk_callback : | |
132 | usb_serial_generic_read_bulk_callback), | |
133 | port); | |
134 | result = usb_submit_urb(port->read_urb, GFP_KERNEL); | |
135 | if (result) | |
136 | dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); | |
137 | } | |
138 | ||
139 | return result; | |
140 | } | |
141 | ||
142 | static void generic_cleanup (struct usb_serial_port *port) | |
143 | { | |
144 | struct usb_serial *serial = port->serial; | |
145 | ||
146 | dbg("%s - port %d", __FUNCTION__, port->number); | |
147 | ||
148 | if (serial->dev) { | |
149 | /* shutdown any bulk reads that might be going on */ | |
150 | if (serial->num_bulk_out) | |
151 | usb_kill_urb(port->write_urb); | |
152 | if (serial->num_bulk_in) | |
153 | usb_kill_urb(port->read_urb); | |
154 | } | |
155 | } | |
156 | ||
157 | void usb_serial_generic_close (struct usb_serial_port *port, struct file * filp) | |
158 | { | |
159 | dbg("%s - port %d", __FUNCTION__, port->number); | |
160 | generic_cleanup (port); | |
161 | } | |
162 | ||
163 | int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *buf, int count) | |
164 | { | |
165 | struct usb_serial *serial = port->serial; | |
166 | int result; | |
167 | unsigned char *data; | |
168 | ||
169 | dbg("%s - port %d", __FUNCTION__, port->number); | |
170 | ||
171 | if (count == 0) { | |
172 | dbg("%s - write request of 0 bytes", __FUNCTION__); | |
173 | return (0); | |
174 | } | |
175 | ||
176 | /* only do something if we have a bulk out endpoint */ | |
177 | if (serial->num_bulk_out) { | |
507ca9bc GKH |
178 | spin_lock(&port->lock); |
179 | if (port->write_urb_busy) { | |
180 | spin_unlock(&port->lock); | |
1da177e4 | 181 | dbg("%s - already writing", __FUNCTION__); |
507ca9bc | 182 | return 0; |
1da177e4 | 183 | } |
507ca9bc GKH |
184 | port->write_urb_busy = 1; |
185 | spin_unlock(&port->lock); | |
1da177e4 LT |
186 | |
187 | count = (count > port->bulk_out_size) ? port->bulk_out_size : count; | |
188 | ||
189 | memcpy (port->write_urb->transfer_buffer, buf, count); | |
190 | data = port->write_urb->transfer_buffer; | |
191 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, data); | |
192 | ||
193 | /* set up our urb */ | |
194 | usb_fill_bulk_urb (port->write_urb, serial->dev, | |
195 | usb_sndbulkpipe (serial->dev, | |
196 | port->bulk_out_endpointAddress), | |
197 | port->write_urb->transfer_buffer, count, | |
198 | ((serial->type->write_bulk_callback) ? | |
199 | serial->type->write_bulk_callback : | |
200 | usb_serial_generic_write_bulk_callback), port); | |
201 | ||
202 | /* send the data out the bulk port */ | |
507ca9bc | 203 | port->write_urb_busy = 1; |
1da177e4 | 204 | result = usb_submit_urb(port->write_urb, GFP_ATOMIC); |
507ca9bc | 205 | if (result) { |
1da177e4 | 206 | dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); |
507ca9bc GKH |
207 | /* don't have to grab the lock here, as we will retry if != 0 */ |
208 | port->write_urb_busy = 0; | |
209 | } else | |
1da177e4 LT |
210 | result = count; |
211 | ||
212 | return result; | |
213 | } | |
214 | ||
215 | /* no bulk out, so return 0 bytes written */ | |
507ca9bc | 216 | return 0; |
1da177e4 LT |
217 | } |
218 | ||
219 | int usb_serial_generic_write_room (struct usb_serial_port *port) | |
220 | { | |
221 | struct usb_serial *serial = port->serial; | |
222 | int room = 0; | |
223 | ||
224 | dbg("%s - port %d", __FUNCTION__, port->number); | |
507ca9bc | 225 | |
1da177e4 | 226 | if (serial->num_bulk_out) { |
7a3ca7d2 | 227 | if (!(port->write_urb_busy)) |
1da177e4 LT |
228 | room = port->bulk_out_size; |
229 | } | |
230 | ||
231 | dbg("%s - returns %d", __FUNCTION__, room); | |
232 | return (room); | |
233 | } | |
234 | ||
235 | int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port) | |
236 | { | |
237 | struct usb_serial *serial = port->serial; | |
238 | int chars = 0; | |
239 | ||
240 | dbg("%s - port %d", __FUNCTION__, port->number); | |
241 | ||
242 | if (serial->num_bulk_out) { | |
507ca9bc | 243 | if (port->write_urb_busy) |
1da177e4 LT |
244 | chars = port->write_urb->transfer_buffer_length; |
245 | } | |
246 | ||
247 | dbg("%s - returns %d", __FUNCTION__, chars); | |
248 | return (chars); | |
249 | } | |
250 | ||
251 | void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | |
252 | { | |
253 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | |
254 | struct usb_serial *serial = port->serial; | |
255 | struct tty_struct *tty; | |
256 | unsigned char *data = urb->transfer_buffer; | |
1da177e4 LT |
257 | int result; |
258 | ||
259 | dbg("%s - port %d", __FUNCTION__, port->number); | |
260 | ||
261 | if (urb->status) { | |
262 | dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); | |
263 | return; | |
264 | } | |
265 | ||
266 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); | |
267 | ||
268 | tty = port->tty; | |
269 | if (tty && urb->actual_length) { | |
33f0f88f AC |
270 | tty_buffer_request_room(tty, urb->actual_length); |
271 | tty_insert_flip_string(tty, data, urb->actual_length); | |
1da177e4 LT |
272 | tty_flip_buffer_push(tty); |
273 | } | |
274 | ||
275 | /* Continue trying to always read */ | |
276 | usb_fill_bulk_urb (port->read_urb, serial->dev, | |
277 | usb_rcvbulkpipe (serial->dev, | |
278 | port->bulk_in_endpointAddress), | |
279 | port->read_urb->transfer_buffer, | |
280 | port->read_urb->transfer_buffer_length, | |
281 | ((serial->type->read_bulk_callback) ? | |
282 | serial->type->read_bulk_callback : | |
283 | usb_serial_generic_read_bulk_callback), port); | |
284 | result = usb_submit_urb(port->read_urb, GFP_ATOMIC); | |
285 | if (result) | |
286 | dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); | |
287 | } | |
288 | ||
289 | void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |
290 | { | |
291 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | |
292 | ||
293 | dbg("%s - port %d", __FUNCTION__, port->number); | |
294 | ||
507ca9bc | 295 | port->write_urb_busy = 0; |
1da177e4 LT |
296 | if (urb->status) { |
297 | dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); | |
298 | return; | |
299 | } | |
300 | ||
301 | usb_serial_port_softint((void *)port); | |
302 | ||
303 | schedule_work(&port->work); | |
304 | } | |
bb833986 | 305 | EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); |
1da177e4 LT |
306 | |
307 | void usb_serial_generic_shutdown (struct usb_serial *serial) | |
308 | { | |
309 | int i; | |
310 | ||
311 | dbg("%s", __FUNCTION__); | |
312 | ||
313 | /* stop reads and writes on all ports */ | |
314 | for (i=0; i < serial->num_ports; ++i) { | |
315 | generic_cleanup(serial->port[i]); | |
316 | } | |
317 | } | |
318 |