diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/usb/serial/generic.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/usb/serial/generic.c')
-rw-r--r-- | drivers/usb/serial/generic.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c new file mode 100644 index 000000000000..99214aa3cd19 --- /dev/null +++ b/drivers/usb/serial/generic.c | |||
@@ -0,0 +1,315 @@ | |||
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 */ | ||
39 | struct usb_serial_device_type usb_serial_generic_device = { | ||
40 | .owner = THIS_MODULE, | ||
41 | .name = "Generic", | ||
42 | .short_name = "generic", | ||
43 | .id_table = generic_device_ids, | ||
44 | .num_interrupt_in = NUM_DONT_CARE, | ||
45 | .num_bulk_in = NUM_DONT_CARE, | ||
46 | .num_bulk_out = NUM_DONT_CARE, | ||
47 | .num_ports = 1, | ||
48 | .shutdown = usb_serial_generic_shutdown, | ||
49 | }; | ||
50 | |||
51 | /* we want to look at all devices, as the vendor/product id can change | ||
52 | * depending on the command line argument */ | ||
53 | static struct usb_device_id generic_serial_ids[] = { | ||
54 | {.driver_info = 42}, | ||
55 | {} | ||
56 | }; | ||
57 | |||
58 | static int generic_probe(struct usb_interface *interface, | ||
59 | const struct usb_device_id *id) | ||
60 | { | ||
61 | const struct usb_device_id *id_pattern; | ||
62 | |||
63 | id_pattern = usb_match_id(interface, generic_device_ids); | ||
64 | if (id_pattern != NULL) | ||
65 | return usb_serial_probe(interface, id); | ||
66 | return -ENODEV; | ||
67 | } | ||
68 | |||
69 | static struct usb_driver generic_driver = { | ||
70 | .owner = THIS_MODULE, | ||
71 | .name = "usbserial_generic", | ||
72 | .probe = generic_probe, | ||
73 | .disconnect = usb_serial_disconnect, | ||
74 | .id_table = generic_serial_ids, | ||
75 | }; | ||
76 | #endif | ||
77 | |||
78 | int usb_serial_generic_register (int _debug) | ||
79 | { | ||
80 | int retval = 0; | ||
81 | |||
82 | debug = _debug; | ||
83 | #ifdef CONFIG_USB_SERIAL_GENERIC | ||
84 | generic_device_ids[0].idVendor = vendor; | ||
85 | generic_device_ids[0].idProduct = product; | ||
86 | generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; | ||
87 | |||
88 | /* register our generic driver with ourselves */ | ||
89 | retval = usb_serial_register (&usb_serial_generic_device); | ||
90 | if (retval) | ||
91 | goto exit; | ||
92 | retval = usb_register(&generic_driver); | ||
93 | if (retval) | ||
94 | usb_serial_deregister(&usb_serial_generic_device); | ||
95 | exit: | ||
96 | #endif | ||
97 | return retval; | ||
98 | } | ||
99 | |||
100 | void usb_serial_generic_deregister (void) | ||
101 | { | ||
102 | #ifdef CONFIG_USB_SERIAL_GENERIC | ||
103 | /* remove our generic driver */ | ||
104 | usb_deregister(&generic_driver); | ||
105 | usb_serial_deregister (&usb_serial_generic_device); | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) | ||
110 | { | ||
111 | struct usb_serial *serial = port->serial; | ||
112 | int result = 0; | ||
113 | |||
114 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
115 | |||
116 | /* force low_latency on so that our tty_push actually forces the data through, | ||
117 | otherwise it is scheduled, and with high data rates (like with OHCI) data | ||
118 | can get lost. */ | ||
119 | if (port->tty) | ||
120 | port->tty->low_latency = 1; | ||
121 | |||
122 | /* if we have a bulk interrupt, start reading from it */ | ||
123 | if (serial->num_bulk_in) { | ||
124 | /* Start reading from the device */ | ||
125 | usb_fill_bulk_urb (port->read_urb, serial->dev, | ||
126 | usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), | ||
127 | port->read_urb->transfer_buffer, | ||
128 | port->read_urb->transfer_buffer_length, | ||
129 | ((serial->type->read_bulk_callback) ? | ||
130 | serial->type->read_bulk_callback : | ||
131 | usb_serial_generic_read_bulk_callback), | ||
132 | port); | ||
133 | result = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
134 | if (result) | ||
135 | dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); | ||
136 | } | ||
137 | |||
138 | return result; | ||
139 | } | ||
140 | |||
141 | static void generic_cleanup (struct usb_serial_port *port) | ||
142 | { | ||
143 | struct usb_serial *serial = port->serial; | ||
144 | |||
145 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
146 | |||
147 | if (serial->dev) { | ||
148 | /* shutdown any bulk reads that might be going on */ | ||
149 | if (serial->num_bulk_out) | ||
150 | usb_kill_urb(port->write_urb); | ||
151 | if (serial->num_bulk_in) | ||
152 | usb_kill_urb(port->read_urb); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | void usb_serial_generic_close (struct usb_serial_port *port, struct file * filp) | ||
157 | { | ||
158 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
159 | generic_cleanup (port); | ||
160 | } | ||
161 | |||
162 | int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *buf, int count) | ||
163 | { | ||
164 | struct usb_serial *serial = port->serial; | ||
165 | int result; | ||
166 | unsigned char *data; | ||
167 | |||
168 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
169 | |||
170 | if (count == 0) { | ||
171 | dbg("%s - write request of 0 bytes", __FUNCTION__); | ||
172 | return (0); | ||
173 | } | ||
174 | |||
175 | /* only do something if we have a bulk out endpoint */ | ||
176 | if (serial->num_bulk_out) { | ||
177 | if (port->write_urb->status == -EINPROGRESS) { | ||
178 | dbg("%s - already writing", __FUNCTION__); | ||
179 | return (0); | ||
180 | } | ||
181 | |||
182 | count = (count > port->bulk_out_size) ? port->bulk_out_size : count; | ||
183 | |||
184 | memcpy (port->write_urb->transfer_buffer, buf, count); | ||
185 | data = port->write_urb->transfer_buffer; | ||
186 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, data); | ||
187 | |||
188 | /* set up our urb */ | ||
189 | usb_fill_bulk_urb (port->write_urb, serial->dev, | ||
190 | usb_sndbulkpipe (serial->dev, | ||
191 | port->bulk_out_endpointAddress), | ||
192 | port->write_urb->transfer_buffer, count, | ||
193 | ((serial->type->write_bulk_callback) ? | ||
194 | serial->type->write_bulk_callback : | ||
195 | usb_serial_generic_write_bulk_callback), port); | ||
196 | |||
197 | /* send the data out the bulk port */ | ||
198 | result = usb_submit_urb(port->write_urb, GFP_ATOMIC); | ||
199 | if (result) | ||
200 | dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); | ||
201 | else | ||
202 | result = count; | ||
203 | |||
204 | return result; | ||
205 | } | ||
206 | |||
207 | /* no bulk out, so return 0 bytes written */ | ||
208 | return (0); | ||
209 | } | ||
210 | |||
211 | int usb_serial_generic_write_room (struct usb_serial_port *port) | ||
212 | { | ||
213 | struct usb_serial *serial = port->serial; | ||
214 | int room = 0; | ||
215 | |||
216 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
217 | |||
218 | if (serial->num_bulk_out) { | ||
219 | if (port->write_urb->status != -EINPROGRESS) | ||
220 | room = port->bulk_out_size; | ||
221 | } | ||
222 | |||
223 | dbg("%s - returns %d", __FUNCTION__, room); | ||
224 | return (room); | ||
225 | } | ||
226 | |||
227 | int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port) | ||
228 | { | ||
229 | struct usb_serial *serial = port->serial; | ||
230 | int chars = 0; | ||
231 | |||
232 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
233 | |||
234 | if (serial->num_bulk_out) { | ||
235 | if (port->write_urb->status == -EINPROGRESS) | ||
236 | chars = port->write_urb->transfer_buffer_length; | ||
237 | } | ||
238 | |||
239 | dbg("%s - returns %d", __FUNCTION__, chars); | ||
240 | return (chars); | ||
241 | } | ||
242 | |||
243 | void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | ||
244 | { | ||
245 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | ||
246 | struct usb_serial *serial = port->serial; | ||
247 | struct tty_struct *tty; | ||
248 | unsigned char *data = urb->transfer_buffer; | ||
249 | int i; | ||
250 | int result; | ||
251 | |||
252 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
253 | |||
254 | if (urb->status) { | ||
255 | dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); | ||
256 | return; | ||
257 | } | ||
258 | |||
259 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); | ||
260 | |||
261 | tty = port->tty; | ||
262 | if (tty && urb->actual_length) { | ||
263 | for (i = 0; i < urb->actual_length ; ++i) { | ||
264 | /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ | ||
265 | if(tty->flip.count >= TTY_FLIPBUF_SIZE) { | ||
266 | tty_flip_buffer_push(tty); | ||
267 | } | ||
268 | /* this doesn't actually push the data through unless tty->low_latency is set */ | ||
269 | tty_insert_flip_char(tty, data[i], 0); | ||
270 | } | ||
271 | tty_flip_buffer_push(tty); | ||
272 | } | ||
273 | |||
274 | /* Continue trying to always read */ | ||
275 | usb_fill_bulk_urb (port->read_urb, serial->dev, | ||
276 | usb_rcvbulkpipe (serial->dev, | ||
277 | port->bulk_in_endpointAddress), | ||
278 | port->read_urb->transfer_buffer, | ||
279 | port->read_urb->transfer_buffer_length, | ||
280 | ((serial->type->read_bulk_callback) ? | ||
281 | serial->type->read_bulk_callback : | ||
282 | usb_serial_generic_read_bulk_callback), port); | ||
283 | result = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||
284 | if (result) | ||
285 | dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); | ||
286 | } | ||
287 | |||
288 | void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | ||
289 | { | ||
290 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | ||
291 | |||
292 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
293 | |||
294 | if (urb->status) { | ||
295 | dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); | ||
296 | return; | ||
297 | } | ||
298 | |||
299 | usb_serial_port_softint((void *)port); | ||
300 | |||
301 | schedule_work(&port->work); | ||
302 | } | ||
303 | |||
304 | void usb_serial_generic_shutdown (struct usb_serial *serial) | ||
305 | { | ||
306 | int i; | ||
307 | |||
308 | dbg("%s", __FUNCTION__); | ||
309 | |||
310 | /* stop reads and writes on all ports */ | ||
311 | for (i=0; i < serial->num_ports; ++i) { | ||
312 | generic_cleanup(serial->port[i]); | ||
313 | } | ||
314 | } | ||
315 | |||