diff options
author | Aleksey Babahin <tamerlan311@gmail.com> | 2012-03-08 16:18:43 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-03-08 16:24:09 -0500 |
commit | 43d186fe992da93bb1dd34a7dd4534719624431c (patch) | |
tree | 680e7601f983dd716a540938c7a75c620505b2d8 /drivers/usb/serial/metro-usb.c | |
parent | 33d2832ab0149a26418d360af3c444969a63fb28 (diff) |
USB: serial: add metro-usb driver to the tree
This driver is for the Metrologic barcode scanner.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/serial/metro-usb.c')
-rw-r--r-- | drivers/usb/serial/metro-usb.c | 622 |
1 files changed, 622 insertions, 0 deletions
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c new file mode 100644 index 000000000000..5b8ed50e5dda --- /dev/null +++ b/drivers/usb/serial/metro-usb.c | |||
@@ -0,0 +1,622 @@ | |||
1 | /* | ||
2 | Date Created: 9/15/2006 | ||
3 | File Name: metro-usb.c | ||
4 | Description: metro-usb.c is the drivers main source file. The driver is a USB to Serial converter. | ||
5 | The driver takes USB data and sends it to a virtual ttyUSB# serial port. | ||
6 | The driver interfaces with the usbserial.ko driver supplied by Linux. | ||
7 | |||
8 | NOTES: | ||
9 | To install the driver: | ||
10 | 1. Install the usbserial.ko module supplied by Linux with: # insmod usbserial.ko | ||
11 | 2. Install the metro-usb.ko module with: # insmod metro-usb.ko vender=0x#### product=0x#### debug=1 | ||
12 | The vendor, product and debug parameters are optional. | ||
13 | |||
14 | Some of this code is credited to Linux USB open source files that are distributed with Linux. | ||
15 | |||
16 | Copyright: 2007 Metrologic Instruments. All rights reserved. | ||
17 | Copyright: 2011 Azimut Ltd. <http://azimutrzn.ru/> | ||
18 | Requirements: gedit.exe, notepad.exe | ||
19 | |||
20 | Revision History: | ||
21 | |||
22 | Date: Developer: Revisions: | ||
23 | ------------------------------------------------------------------------------ | ||
24 | 1/30/2007 Philip Nicastro Initial release. (v1.0.0.0) | ||
25 | 2/27/2007 Philip Nicastro Changed the metrousb_read_int_callback function to use a loop with the tty_insert_flip_char function to copy each byte to the tty layer. Removed the tty_buffer_request_room and the tty_insert_flip_string function calls. These calls were not supported on Fedora. | ||
26 | 2/27/2007 Philip Nicastro Released. (v1.1.0.0) | ||
27 | 10/07/2011 Aleksey Babahin Update for new kernel (tested on 2.6.38) | ||
28 | Add unidirection mode support | ||
29 | |||
30 | |||
31 | */ | ||
32 | |||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/tty.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/usb.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/tty_driver.h> | ||
41 | #include <linux/tty_flip.h> | ||
42 | #include <linux/moduleparam.h> | ||
43 | #include <linux/spinlock.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | #include <linux/errno.h> | ||
46 | #include "metro-usb.h" | ||
47 | #include <linux/usb/serial.h> | ||
48 | |||
49 | /* Version Information */ | ||
50 | #define DRIVER_VERSION "v1.2.0.0" | ||
51 | #define DRIVER_DESC "Metrologic Instruments Inc. - USB-POS driver" | ||
52 | |||
53 | /* Device table list. */ | ||
54 | static struct usb_device_id id_table [] = { | ||
55 | { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID) }, | ||
56 | { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) }, | ||
57 | { }, /* Optional paramenter entry. */ | ||
58 | { }, /* Terminating entry. */ | ||
59 | }; | ||
60 | MODULE_DEVICE_TABLE(usb, id_table); | ||
61 | |||
62 | /* Input parameter constants. */ | ||
63 | static int debug; | ||
64 | static __u16 vendor; | ||
65 | static __u16 product; | ||
66 | |||
67 | /* Function prototypes. */ | ||
68 | static void metrousb_cleanup (struct usb_serial_port *port); | ||
69 | static void metrousb_close (struct usb_serial_port *port); | ||
70 | static int metrousb_open (struct tty_struct *tty, struct usb_serial_port *port); | ||
71 | static void metrousb_read_int_callback (struct urb *urb); | ||
72 | static void metrousb_shutdown (struct usb_serial *serial); | ||
73 | static int metrousb_startup (struct usb_serial *serial); | ||
74 | static void metrousb_throttle(struct tty_struct *tty); | ||
75 | static int metrousb_tiocmget(struct tty_struct *tty); | ||
76 | static int metrousb_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); | ||
77 | static void metrousb_unthrottle(struct tty_struct *tty); | ||
78 | |||
79 | /* Driver structure. */ | ||
80 | static struct usb_driver metrousb_driver = { | ||
81 | .name = "metro-usb", | ||
82 | .probe = usb_serial_probe, | ||
83 | .disconnect = usb_serial_disconnect, | ||
84 | .id_table = id_table | ||
85 | }; | ||
86 | |||
87 | /* Device structure. */ | ||
88 | static struct usb_serial_driver metrousb_device = { | ||
89 | .driver = { | ||
90 | .owner = THIS_MODULE, | ||
91 | .name = "metro-usb", | ||
92 | }, | ||
93 | .description = "Metrologic USB to serial converter.", | ||
94 | .id_table = id_table, | ||
95 | .usb_driver = &metrousb_driver, | ||
96 | .num_ports = 1, | ||
97 | .open = metrousb_open, | ||
98 | .close = metrousb_close, | ||
99 | .read_int_callback = metrousb_read_int_callback, | ||
100 | .attach = metrousb_startup, | ||
101 | .release = metrousb_shutdown, | ||
102 | .throttle = metrousb_throttle, | ||
103 | .unthrottle = metrousb_unthrottle, | ||
104 | .tiocmget = metrousb_tiocmget, | ||
105 | .tiocmset = metrousb_tiocmset, | ||
106 | }; | ||
107 | |||
108 | /* ---------------------------------------------------------------------------------------------- | ||
109 | Description: | ||
110 | Clean up any urbs and port information. | ||
111 | |||
112 | Input: | ||
113 | struct usb_serial_port *: pointer to a usb_serial_port structure. | ||
114 | |||
115 | Output: | ||
116 | int: Returns true (0) if successful, false otherwise. | ||
117 | */ | ||
118 | static void metrousb_cleanup (struct usb_serial_port *port) | ||
119 | { | ||
120 | dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number); | ||
121 | |||
122 | if (port->serial->dev) { | ||
123 | /* Shutdown any interrupt in urbs. */ | ||
124 | if (port->interrupt_in_urb) { | ||
125 | usb_unlink_urb(port->interrupt_in_urb); | ||
126 | usb_kill_urb(port->interrupt_in_urb); | ||
127 | } | ||
128 | |||
129 | // temp | ||
130 | // this will be needed for the write urb | ||
131 | /* Shutdown any interrupt_out_urbs. */ | ||
132 | //if (serial->num_bulk_in) | ||
133 | // usb_kill_urb(port->read_urb); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* ---------------------------------------------------------------------------------------------- | ||
138 | Description: | ||
139 | Close the open serial port. Cleanup any open serial port information. | ||
140 | |||
141 | Input: | ||
142 | struct usb_serial_port *: pointer to a usb_serial_port structure. | ||
143 | struct file *: pointer to a file structure. | ||
144 | |||
145 | Output: | ||
146 | int: Returns true (0) if successful, false otherwise. | ||
147 | */ | ||
148 | static void metrousb_close (struct usb_serial_port *port) | ||
149 | { | ||
150 | dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number); | ||
151 | metrousb_cleanup(port); | ||
152 | } | ||
153 | |||
154 | /* ---------------------------------------------------------------------------------------------- | ||
155 | Description: | ||
156 | Driver exit. | ||
157 | |||
158 | Input: | ||
159 | None: | ||
160 | |||
161 | Output: | ||
162 | None: | ||
163 | */ | ||
164 | static void __exit metrousb_exit(void) | ||
165 | { | ||
166 | dbg("METRO-USB - %s", __FUNCTION__); | ||
167 | |||
168 | usb_deregister(&metrousb_driver); | ||
169 | usb_serial_deregister(&metrousb_device); | ||
170 | } | ||
171 | |||
172 | /* ---------------------------------------------------------------------------------------------- | ||
173 | Description: | ||
174 | Driver initialization. | ||
175 | |||
176 | Input: | ||
177 | None: | ||
178 | |||
179 | Output: | ||
180 | int: Returns true (0) if successful, false otherwise. | ||
181 | */ | ||
182 | static int __init metrousb_init(void) | ||
183 | { | ||
184 | int retval = 0; | ||
185 | int i = 0; | ||
186 | |||
187 | dbg("METRO-USB - %s", __FUNCTION__); | ||
188 | |||
189 | /* Add the device parameters if entered. */ | ||
190 | if ((vendor > 0) && (product > 0)) { | ||
191 | struct usb_device_id usb_dev_temp[] = { {USB_DEVICE(vendor, product) } }; | ||
192 | |||
193 | /* Find the last entry in id_table */ | ||
194 | for (i=0; i < ARRAY_SIZE(id_table); i++) { | ||
195 | if (id_table[i].idVendor == 0) { | ||
196 | id_table[i] = usb_dev_temp[0]; | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | dbg("METRO-USB - %s - support added for unknown device: vendor=0x%x - product=0x%x", __FUNCTION__, vendor, product); | ||
202 | printk(KERN_INFO "Metro USB-POS support added for unknown device: vendor=0x%x - product=0x%x", vendor, product); | ||
203 | } | ||
204 | |||
205 | /* Register the devices. */ | ||
206 | retval = usb_serial_register(&metrousb_device); | ||
207 | if (retval) | ||
208 | return retval; | ||
209 | |||
210 | /* Register the driver. */ | ||
211 | retval = usb_register(&metrousb_driver); | ||
212 | if (retval) | ||
213 | usb_serial_deregister(&metrousb_device); | ||
214 | |||
215 | printk(KERN_INFO DRIVER_DESC " : " DRIVER_VERSION); | ||
216 | |||
217 | return retval; | ||
218 | } | ||
219 | |||
220 | /* ---------------------------------------------------------------------------------------------- | ||
221 | Description: | ||
222 | Open the drivers serial port. | ||
223 | |||
224 | Input: | ||
225 | struct usb_serial_port *: pointer to a usb_serial_port structure. | ||
226 | struct file *: pointer to a file structure. | ||
227 | |||
228 | Output: | ||
229 | int: Returns true (0) if successful, false otherwise. | ||
230 | */ | ||
231 | static int metrousb_open (struct tty_struct *tty, struct usb_serial_port *port) | ||
232 | { | ||
233 | struct usb_serial *serial = port->serial; | ||
234 | struct metrousb_private *metro_priv = usb_get_serial_port_data(port); | ||
235 | unsigned long flags = 0; | ||
236 | int result = 0; | ||
237 | |||
238 | dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number); | ||
239 | |||
240 | /* Make sure the urb is initialized. */ | ||
241 | if (!port->interrupt_in_urb) { | ||
242 | dbg("METRO-USB - %s - interrupt urb not initialized for port number=%d", __FUNCTION__, port->number); | ||
243 | return -ENODEV; | ||
244 | } | ||
245 | |||
246 | /* Set the private data information for the port. */ | ||
247 | spin_lock_irqsave(&metro_priv->lock, flags); | ||
248 | metro_priv->control_state = 0; | ||
249 | metro_priv->throttled = 0; | ||
250 | spin_unlock_irqrestore(&metro_priv->lock, flags); | ||
251 | |||
252 | /* | ||
253 | * Force low_latency on so that our tty_push actually forces the data | ||
254 | * through, otherwise it is scheduled, and with high data rates (like | ||
255 | * with OHCI) data can get lost. | ||
256 | */ | ||
257 | if (tty) { | ||
258 | tty->low_latency = 1; | ||
259 | } | ||
260 | |||
261 | /* Clear the urb pipe. */ | ||
262 | usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe); | ||
263 | |||
264 | /* Start reading from the device */ | ||
265 | usb_fill_int_urb (port->interrupt_in_urb, serial->dev, | ||
266 | usb_rcvintpipe (serial->dev, port->interrupt_in_endpointAddress), | ||
267 | port->interrupt_in_urb->transfer_buffer, | ||
268 | port->interrupt_in_urb->transfer_buffer_length, | ||
269 | metrousb_read_int_callback, port, 1); | ||
270 | result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); | ||
271 | |||
272 | if (result) { | ||
273 | dbg("METRO-USB - %s - failed submitting interrupt in urb for port number=%d, error code=%d" | ||
274 | , __FUNCTION__, port->number, result); | ||
275 | goto exit; | ||
276 | } | ||
277 | |||
278 | dbg("METRO-USB - %s - port open for port number=%d", __FUNCTION__, port->number); | ||
279 | exit: | ||
280 | return result; | ||
281 | } | ||
282 | |||
283 | /* ---------------------------------------------------------------------------------------------- | ||
284 | Description: | ||
285 | Read the port from the read interrupt. | ||
286 | |||
287 | Input: | ||
288 | struct urb *: urb structure to get data. | ||
289 | struct pt_regs *: pt_regs structure. | ||
290 | |||
291 | Output: | ||
292 | None: | ||
293 | */ | ||
294 | static void metrousb_read_int_callback (struct urb *urb) | ||
295 | { | ||
296 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | ||
297 | struct metrousb_private *metro_priv = usb_get_serial_port_data(port); | ||
298 | struct tty_struct *tty; | ||
299 | unsigned char *data = urb->transfer_buffer; | ||
300 | int throttled = 0; | ||
301 | int result = 0; | ||
302 | unsigned long flags = 0; | ||
303 | |||
304 | dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number); | ||
305 | |||
306 | switch (urb->status) { | ||
307 | case 0: | ||
308 | /* Success status, read from the port. */ | ||
309 | break; | ||
310 | case -ECONNRESET: | ||
311 | case -ENOENT: | ||
312 | case -ESHUTDOWN: | ||
313 | /* urb has been terminated. */ | ||
314 | dbg("METRO-USB - %s - urb shutting down, port number=%d, error code=%d", | ||
315 | __FUNCTION__, port->number, result); | ||
316 | return; | ||
317 | default: | ||
318 | dbg("METRO-USB - %s - non-zero urb received, port number=%d, error code=%d", | ||
319 | __FUNCTION__, port->number, result); | ||
320 | goto exit; | ||
321 | } | ||
322 | |||
323 | |||
324 | /* Set the data read from the usb port into the serial port buffer. */ | ||
325 | tty = tty_port_tty_get(&port->port); | ||
326 | if (!tty) { | ||
327 | dbg("%s - bad tty pointer - exiting", __func__); | ||
328 | return; | ||
329 | } | ||
330 | |||
331 | if (tty && urb->actual_length) { | ||
332 | // Loop through the data copying each byte to the tty layer. | ||
333 | tty_insert_flip_string(tty, data, urb->actual_length); | ||
334 | |||
335 | // Force the data to the tty layer. | ||
336 | tty_flip_buffer_push(tty); | ||
337 | } | ||
338 | tty_kref_put(tty); | ||
339 | |||
340 | /* Set any port variables. */ | ||
341 | spin_lock_irqsave(&metro_priv->lock, flags); | ||
342 | throttled = metro_priv->throttled; | ||
343 | spin_unlock_irqrestore(&metro_priv->lock, flags); | ||
344 | |||
345 | /* Continue trying to read if set. */ | ||
346 | if (!throttled) { | ||
347 | usb_fill_int_urb (port->interrupt_in_urb, port->serial->dev, | ||
348 | usb_rcvintpipe (port->serial->dev, port->interrupt_in_endpointAddress), | ||
349 | port->interrupt_in_urb->transfer_buffer, | ||
350 | port->interrupt_in_urb->transfer_buffer_length, | ||
351 | metrousb_read_int_callback, port, 1); | ||
352 | |||
353 | result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); | ||
354 | |||
355 | if (result) { | ||
356 | dbg("METRO-USB - %s - failed submitting interrupt in urb for port number=%d, error code=%d", | ||
357 | __FUNCTION__, port->number, result); | ||
358 | } | ||
359 | } | ||
360 | return; | ||
361 | |||
362 | exit: | ||
363 | /* Try to resubmit the urb. */ | ||
364 | result = usb_submit_urb (urb, GFP_ATOMIC); | ||
365 | if (result) { | ||
366 | dbg("METRO-USB - %s - failed submitting interrupt in urb for port number=%d, error code=%d", | ||
367 | __FUNCTION__, port->number, result); | ||
368 | } | ||
369 | } | ||
370 | |||
371 | /* ---------------------------------------------------------------------------------------------- | ||
372 | Description: | ||
373 | Set the modem control state for the entered serial port. | ||
374 | |||
375 | Input: | ||
376 | struct usb_serial_port *: pointer to a usb_serial_port structure. | ||
377 | unsigned int: control state value to set. | ||
378 | |||
379 | Output: | ||
380 | int: Returns true (0) if successful, false otherwise. | ||
381 | */ | ||
382 | static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int control_state) | ||
383 | { | ||
384 | int retval = 0; | ||
385 | unsigned char mcr = METROUSB_MCR_NONE; | ||
386 | |||
387 | dbg("METRO-USB - %s - control state=%d", __FUNCTION__, control_state); | ||
388 | |||
389 | /* Set the modem control value. */ | ||
390 | if (control_state & TIOCM_DTR) | ||
391 | mcr |= METROUSB_MCR_DTR; | ||
392 | if (control_state & TIOCM_RTS) | ||
393 | mcr |= METROUSB_MCR_RTS; | ||
394 | |||
395 | /* Send the command to the usb port. */ | ||
396 | retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), | ||
397 | METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST, | ||
398 | control_state, 0, NULL, 0, WDR_TIMEOUT); | ||
399 | if (retval < 0) | ||
400 | dbg("METRO-USB - %s - set modem ctrl=0x%x failed, error code=%d", __FUNCTION__, mcr, retval); | ||
401 | |||
402 | return retval; | ||
403 | } | ||
404 | |||
405 | |||
406 | /* ---------------------------------------------------------------------------------------------- | ||
407 | Description: | ||
408 | Shutdown the driver. | ||
409 | |||
410 | Input: | ||
411 | struct usb_serial *: pointer to a usb-serial structure. | ||
412 | |||
413 | Output: | ||
414 | int: Returns true (0) if successful, false otherwise. | ||
415 | */ | ||
416 | static void metrousb_shutdown (struct usb_serial *serial) | ||
417 | { | ||
418 | int i = 0; | ||
419 | |||
420 | dbg("METRO-USB - %s", __FUNCTION__); | ||
421 | |||
422 | /* Stop reading and writing on all ports. */ | ||
423 | for (i=0; i < serial->num_ports; ++i) { | ||
424 | /* Close any open urbs. */ | ||
425 | metrousb_cleanup(serial->port[i]); | ||
426 | |||
427 | /* Free memory. */ | ||
428 | kfree(usb_get_serial_port_data(serial->port[i])); | ||
429 | usb_set_serial_port_data(serial->port[i], NULL); | ||
430 | |||
431 | dbg("METRO-USB - %s - freed port number=%d", __FUNCTION__, serial->port[i]->number); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | /* ---------------------------------------------------------------------------------------------- | ||
436 | Description: | ||
437 | Startup the driver. | ||
438 | |||
439 | Input: | ||
440 | struct usb_serial *: pointer to a usb-serial structure. | ||
441 | |||
442 | Output: | ||
443 | int: Returns true (0) if successful, false otherwise. | ||
444 | */ | ||
445 | static int metrousb_startup(struct usb_serial *serial) | ||
446 | { | ||
447 | struct metrousb_private *metro_priv; | ||
448 | struct usb_serial_port *port; | ||
449 | int i = 0; | ||
450 | |||
451 | dbg("METRO-USB - %s", __FUNCTION__); | ||
452 | |||
453 | /* Loop through the serial ports setting up the private structures. | ||
454 | * Currently we only use one port. */ | ||
455 | for (i = 0; i < serial->num_ports; ++i) { | ||
456 | port = serial->port[i]; | ||
457 | |||
458 | /* Declare memory. */ | ||
459 | metro_priv = (struct metrousb_private *) kmalloc (sizeof(struct metrousb_private), GFP_KERNEL); | ||
460 | if (!metro_priv) | ||
461 | return -ENOMEM; | ||
462 | |||
463 | /* Clear memory. */ | ||
464 | memset (metro_priv, 0x00, sizeof(struct metrousb_private)); | ||
465 | |||
466 | /* Initialize memory. */ | ||
467 | spin_lock_init(&metro_priv->lock); | ||
468 | usb_set_serial_port_data(port, metro_priv); | ||
469 | |||
470 | dbg("METRO-USB - %s - port number=%d.", __FUNCTION__, port->number); | ||
471 | } | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | /* ---------------------------------------------------------------------------------------------- | ||
477 | Description: | ||
478 | Set the serial port throttle to stop reading from the port. | ||
479 | |||
480 | Input: | ||
481 | struct usb_serial_port *: pointer to a usb_serial_port structure. | ||
482 | |||
483 | Output: | ||
484 | None: | ||
485 | */ | ||
486 | static void metrousb_throttle (struct tty_struct *tty) | ||
487 | { | ||
488 | struct usb_serial_port *port = tty->driver_data; | ||
489 | struct metrousb_private *metro_priv = usb_get_serial_port_data(port); | ||
490 | unsigned long flags = 0; | ||
491 | |||
492 | dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number); | ||
493 | |||
494 | /* Set the private information for the port to stop reading data. */ | ||
495 | spin_lock_irqsave(&metro_priv->lock, flags); | ||
496 | metro_priv->throttled = 1; | ||
497 | spin_unlock_irqrestore(&metro_priv->lock, flags); | ||
498 | } | ||
499 | |||
500 | /* ---------------------------------------------------------------------------------------------- | ||
501 | Description: | ||
502 | Get the serial port control line states. | ||
503 | |||
504 | Input: | ||
505 | struct usb_serial_port *: pointer to a usb_serial_port structure. | ||
506 | struct file *: pointer to a file structure. | ||
507 | |||
508 | Output: | ||
509 | int: Returns the state of the control lines. | ||
510 | */ | ||
511 | static int metrousb_tiocmget (struct tty_struct *tty) | ||
512 | { | ||
513 | unsigned long control_state = 0; | ||
514 | struct usb_serial_port *port = tty->driver_data; | ||
515 | struct metrousb_private *metro_priv = usb_get_serial_port_data(port); | ||
516 | unsigned long flags = 0; | ||
517 | |||
518 | dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number); | ||
519 | |||
520 | spin_lock_irqsave(&metro_priv->lock, flags); | ||
521 | control_state = metro_priv->control_state; | ||
522 | spin_unlock_irqrestore(&metro_priv->lock, flags); | ||
523 | |||
524 | return control_state; | ||
525 | } | ||
526 | |||
527 | /* ---------------------------------------------------------------------------------------------- | ||
528 | Description: | ||
529 | Set the serial port control line states. | ||
530 | |||
531 | Input: | ||
532 | struct usb_serial_port *: pointer to a usb_serial_port structure. | ||
533 | struct file *: pointer to a file structure. | ||
534 | unsigned int: line state to set. | ||
535 | unsigned int: line state to clear. | ||
536 | |||
537 | Output: | ||
538 | int: Returns the state of the control lines. | ||
539 | */ | ||
540 | static int metrousb_tiocmset (struct tty_struct *tty, | ||
541 | unsigned int set, unsigned int clear) | ||
542 | { | ||
543 | struct usb_serial_port *port = tty->driver_data; | ||
544 | struct usb_serial *serial = port->serial; | ||
545 | struct metrousb_private *metro_priv = usb_get_serial_port_data(port); | ||
546 | unsigned long flags = 0; | ||
547 | unsigned long control_state = 0; | ||
548 | |||
549 | dbg("METRO-USB - %s - port number=%d, set=%d, clear=%d", __FUNCTION__, port->number, set, clear); | ||
550 | |||
551 | spin_lock_irqsave(&metro_priv->lock, flags); | ||
552 | control_state = metro_priv->control_state; | ||
553 | |||
554 | // Set the RTS and DTR values. | ||
555 | if (set & TIOCM_RTS) | ||
556 | control_state |= TIOCM_RTS; | ||
557 | if (set & TIOCM_DTR) | ||
558 | control_state |= TIOCM_DTR; | ||
559 | if (clear & TIOCM_RTS) | ||
560 | control_state &= ~TIOCM_RTS; | ||
561 | if (clear & TIOCM_DTR) | ||
562 | control_state &= ~TIOCM_DTR; | ||
563 | |||
564 | metro_priv->control_state = control_state; | ||
565 | spin_unlock_irqrestore(&metro_priv->lock, flags); | ||
566 | return metrousb_set_modem_ctrl(serial, control_state); | ||
567 | } | ||
568 | |||
569 | /* ---------------------------------------------------------------------------------------------- | ||
570 | Description: | ||
571 | Set the serial port unthrottle to resume reading from the port. | ||
572 | |||
573 | Input: | ||
574 | struct usb_serial_port *: pointer to a usb_serial_port structure. | ||
575 | |||
576 | Output: | ||
577 | None: | ||
578 | */ | ||
579 | static void metrousb_unthrottle (struct tty_struct *tty) | ||
580 | { | ||
581 | struct usb_serial_port *port = tty->driver_data; | ||
582 | struct metrousb_private *metro_priv = usb_get_serial_port_data(port); | ||
583 | unsigned long flags = 0; | ||
584 | int result = 0; | ||
585 | |||
586 | dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number); | ||
587 | |||
588 | /* Set the private information for the port to resume reading data. */ | ||
589 | spin_lock_irqsave(&metro_priv->lock, flags); | ||
590 | metro_priv->throttled = 0; | ||
591 | spin_unlock_irqrestore(&metro_priv->lock, flags); | ||
592 | |||
593 | /* Submit the urb to read from the port. */ | ||
594 | port->interrupt_in_urb->dev = port->serial->dev; | ||
595 | result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); | ||
596 | if (result) { | ||
597 | dbg("METRO-USB - %s - failed submitting interrupt in urb for port number=%d, error code=%d", | ||
598 | __FUNCTION__, port->number, result); | ||
599 | } | ||
600 | } | ||
601 | |||
602 | /* Standard module function. */ | ||
603 | module_init(metrousb_init); | ||
604 | module_exit(metrousb_exit); | ||
605 | MODULE_LICENSE("GPL"); | ||
606 | MODULE_AUTHOR( "Philip Nicastro" ); | ||
607 | MODULE_AUTHOR( "Aleksey Babahin <tamerlan311@gmail.com>" ); | ||
608 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
609 | |||
610 | /* Module input parameters */ | ||
611 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
612 | MODULE_PARM_DESC(debug, "Print debug info (bool 1=on, 0=off)"); | ||
613 | |||
614 | module_param(vendor, ushort, 0); | ||
615 | MODULE_PARM_DESC(vendor, "User specified vendor ID (ushort)"); | ||
616 | |||
617 | module_param(product, ushort, 0); | ||
618 | MODULE_PARM_DESC(product, "User specified product ID (ushort)"); | ||
619 | |||
620 | |||
621 | |||
622 | |||