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