diff options
Diffstat (limited to 'drivers/usb/serial/opticon.c')
-rw-r--r-- | drivers/usb/serial/opticon.c | 161 |
1 files changed, 127 insertions, 34 deletions
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index ed01f3b2de8c..96423f3c8ef3 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Opticon USB barcode to serial driver | 2 | * Opticon USB barcode to serial driver |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Martin Jansen <martin.jansen@opticon.com> | ||
4 | * Copyright (C) 2008 - 2009 Greg Kroah-Hartman <gregkh@suse.de> | 5 | * Copyright (C) 2008 - 2009 Greg Kroah-Hartman <gregkh@suse.de> |
5 | * Copyright (C) 2008 - 2009 Novell Inc. | 6 | * Copyright (C) 2008 - 2009 Novell Inc. |
6 | * | 7 | * |
@@ -21,6 +22,16 @@ | |||
21 | #include <linux/usb/serial.h> | 22 | #include <linux/usb/serial.h> |
22 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
23 | 24 | ||
25 | #define CONTROL_RTS 0x02 | ||
26 | #define RESEND_CTS_STATE 0x03 | ||
27 | |||
28 | /* max number of write urbs in flight */ | ||
29 | #define URB_UPPER_LIMIT 8 | ||
30 | |||
31 | /* This driver works for the Opticon 1D barcode reader | ||
32 | * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */ | ||
33 | #define DRIVER_DESC "Opticon USB barcode to serial driver (1D)" | ||
34 | |||
24 | static int debug; | 35 | static int debug; |
25 | 36 | ||
26 | static const struct usb_device_id id_table[] = { | 37 | static const struct usb_device_id id_table[] = { |
@@ -42,13 +53,13 @@ struct opticon_private { | |||
42 | bool throttled; | 53 | bool throttled; |
43 | bool actually_throttled; | 54 | bool actually_throttled; |
44 | bool rts; | 55 | bool rts; |
56 | bool cts; | ||
45 | int outstanding_urbs; | 57 | int outstanding_urbs; |
46 | }; | 58 | }; |
47 | 59 | ||
48 | /* max number of write urbs in flight */ | ||
49 | #define URB_UPPER_LIMIT 4 | ||
50 | 60 | ||
51 | static void opticon_bulk_callback(struct urb *urb) | 61 | |
62 | static void opticon_read_bulk_callback(struct urb *urb) | ||
52 | { | 63 | { |
53 | struct opticon_private *priv = urb->context; | 64 | struct opticon_private *priv = urb->context; |
54 | unsigned char *data = urb->transfer_buffer; | 65 | unsigned char *data = urb->transfer_buffer; |
@@ -57,6 +68,7 @@ static void opticon_bulk_callback(struct urb *urb) | |||
57 | struct tty_struct *tty; | 68 | struct tty_struct *tty; |
58 | int result; | 69 | int result; |
59 | int data_length; | 70 | int data_length; |
71 | unsigned long flags; | ||
60 | 72 | ||
61 | dbg("%s - port %d", __func__, port->number); | 73 | dbg("%s - port %d", __func__, port->number); |
62 | 74 | ||
@@ -87,31 +99,34 @@ static void opticon_bulk_callback(struct urb *urb) | |||
87 | * Data from the device comes with a 2 byte header: | 99 | * Data from the device comes with a 2 byte header: |
88 | * | 100 | * |
89 | * <0x00><0x00>data... | 101 | * <0x00><0x00>data... |
90 | * This is real data to be sent to the tty layer | 102 | * This is real data to be sent to the tty layer |
91 | * <0x00><0x01)level | 103 | * <0x00><0x01)level |
92 | * This is a RTS level change, the third byte is the RTS | 104 | * This is a CTS level change, the third byte is the CTS |
93 | * value (0 for low, 1 for high). | 105 | * value (0 for low, 1 for high). |
94 | */ | 106 | */ |
95 | if ((data[0] == 0x00) && (data[1] == 0x00)) { | 107 | if ((data[0] == 0x00) && (data[1] == 0x00)) { |
96 | /* real data, send it to the tty layer */ | 108 | /* real data, send it to the tty layer */ |
97 | tty = tty_port_tty_get(&port->port); | 109 | tty = tty_port_tty_get(&port->port); |
98 | if (tty) { | 110 | if (tty) { |
99 | tty_insert_flip_string(tty, data, | 111 | tty_insert_flip_string(tty, data + 2, |
100 | data_length); | 112 | data_length); |
101 | tty_flip_buffer_push(tty); | 113 | tty_flip_buffer_push(tty); |
102 | tty_kref_put(tty); | 114 | tty_kref_put(tty); |
103 | } | 115 | } |
104 | } else { | 116 | } else { |
105 | if ((data[0] == 0x00) && (data[1] == 0x01)) { | 117 | if ((data[0] == 0x00) && (data[1] == 0x01)) { |
118 | spin_lock_irqsave(&priv->lock, flags); | ||
119 | /* CTS status information package */ | ||
106 | if (data[2] == 0x00) | 120 | if (data[2] == 0x00) |
107 | priv->rts = false; | 121 | priv->cts = false; |
108 | else | 122 | else |
109 | priv->rts = true; | 123 | priv->cts = true; |
124 | spin_unlock_irqrestore(&priv->lock, flags); | ||
110 | } else { | 125 | } else { |
111 | dev_dbg(&priv->udev->dev, | 126 | dev_dbg(&priv->udev->dev, |
112 | "Unknown data packet received from the device:" | 127 | "Unknown data packet received from the device:" |
113 | " %2x %2x\n", | 128 | " %2x %2x\n", |
114 | data[0], data[1]); | 129 | data[0], data[1]); |
115 | } | 130 | } |
116 | } | 131 | } |
117 | } else { | 132 | } else { |
@@ -129,8 +144,8 @@ exit: | |||
129 | usb_rcvbulkpipe(priv->udev, | 144 | usb_rcvbulkpipe(priv->udev, |
130 | priv->bulk_address), | 145 | priv->bulk_address), |
131 | priv->bulk_in_buffer, priv->buffer_size, | 146 | priv->bulk_in_buffer, priv->buffer_size, |
132 | opticon_bulk_callback, priv); | 147 | opticon_read_bulk_callback, priv); |
133 | result = usb_submit_urb(port->read_urb, GFP_ATOMIC); | 148 | result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); |
134 | if (result) | 149 | if (result) |
135 | dev_err(&port->dev, | 150 | dev_err(&port->dev, |
136 | "%s - failed resubmitting read urb, error %d\n", | 151 | "%s - failed resubmitting read urb, error %d\n", |
@@ -140,6 +155,24 @@ exit: | |||
140 | spin_unlock(&priv->lock); | 155 | spin_unlock(&priv->lock); |
141 | } | 156 | } |
142 | 157 | ||
158 | static int send_control_msg(struct usb_serial_port *port, u8 requesttype, | ||
159 | u8 val) | ||
160 | { | ||
161 | struct usb_serial *serial = port->serial; | ||
162 | int retval; | ||
163 | u8 buffer[2]; | ||
164 | |||
165 | buffer[0] = val; | ||
166 | /* Send the message to the vendor control endpoint | ||
167 | * of the connected device */ | ||
168 | retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), | ||
169 | requesttype, | ||
170 | USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, | ||
171 | 0, 0, buffer, 1, 0); | ||
172 | |||
173 | return retval; | ||
174 | } | ||
175 | |||
143 | static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) | 176 | static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) |
144 | { | 177 | { |
145 | struct opticon_private *priv = usb_get_serial_data(port->serial); | 178 | struct opticon_private *priv = usb_get_serial_data(port->serial); |
@@ -152,19 +185,30 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
152 | priv->throttled = false; | 185 | priv->throttled = false; |
153 | priv->actually_throttled = false; | 186 | priv->actually_throttled = false; |
154 | priv->port = port; | 187 | priv->port = port; |
188 | priv->rts = false; | ||
155 | spin_unlock_irqrestore(&priv->lock, flags); | 189 | spin_unlock_irqrestore(&priv->lock, flags); |
156 | 190 | ||
157 | /* Start reading from the device */ | 191 | /* Clear RTS line */ |
192 | send_control_msg(port, CONTROL_RTS, 0); | ||
193 | |||
194 | /* Setup the read URB and start reading from the device */ | ||
158 | usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, | 195 | usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, |
159 | usb_rcvbulkpipe(priv->udev, | 196 | usb_rcvbulkpipe(priv->udev, |
160 | priv->bulk_address), | 197 | priv->bulk_address), |
161 | priv->bulk_in_buffer, priv->buffer_size, | 198 | priv->bulk_in_buffer, priv->buffer_size, |
162 | opticon_bulk_callback, priv); | 199 | opticon_read_bulk_callback, priv); |
200 | |||
201 | /* clear the halt status of the enpoint */ | ||
202 | usb_clear_halt(priv->udev, priv->bulk_read_urb->pipe); | ||
203 | |||
163 | result = usb_submit_urb(priv->bulk_read_urb, GFP_KERNEL); | 204 | result = usb_submit_urb(priv->bulk_read_urb, GFP_KERNEL); |
164 | if (result) | 205 | if (result) |
165 | dev_err(&port->dev, | 206 | dev_err(&port->dev, |
166 | "%s - failed resubmitting read urb, error %d\n", | 207 | "%s - failed resubmitting read urb, error %d\n", |
167 | __func__, result); | 208 | __func__, result); |
209 | /* Request CTS line state, sometimes during opening the current | ||
210 | * CTS state can be missed. */ | ||
211 | send_control_msg(port, RESEND_CTS_STATE, 1); | ||
168 | return result; | 212 | return result; |
169 | } | 213 | } |
170 | 214 | ||
@@ -178,7 +222,7 @@ static void opticon_close(struct usb_serial_port *port) | |||
178 | usb_kill_urb(priv->bulk_read_urb); | 222 | usb_kill_urb(priv->bulk_read_urb); |
179 | } | 223 | } |
180 | 224 | ||
181 | static void opticon_write_bulk_callback(struct urb *urb) | 225 | static void opticon_write_control_callback(struct urb *urb) |
182 | { | 226 | { |
183 | struct opticon_private *priv = urb->context; | 227 | struct opticon_private *priv = urb->context; |
184 | int status = urb->status; | 228 | int status = urb->status; |
@@ -187,6 +231,9 @@ static void opticon_write_bulk_callback(struct urb *urb) | |||
187 | /* free up the transfer buffer, as usb_free_urb() does not do this */ | 231 | /* free up the transfer buffer, as usb_free_urb() does not do this */ |
188 | kfree(urb->transfer_buffer); | 232 | kfree(urb->transfer_buffer); |
189 | 233 | ||
234 | /* setup packet may be set if we're using it for writing */ | ||
235 | kfree(urb->setup_packet); | ||
236 | |||
190 | if (status) | 237 | if (status) |
191 | dbg("%s - nonzero write bulk status received: %d", | 238 | dbg("%s - nonzero write bulk status received: %d", |
192 | __func__, status); | 239 | __func__, status); |
@@ -207,6 +254,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
207 | unsigned char *buffer; | 254 | unsigned char *buffer; |
208 | unsigned long flags; | 255 | unsigned long flags; |
209 | int status; | 256 | int status; |
257 | struct usb_ctrlrequest *dr; | ||
210 | 258 | ||
211 | dbg("%s - port %d", __func__, port->number); | 259 | dbg("%s - port %d", __func__, port->number); |
212 | 260 | ||
@@ -223,6 +271,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
223 | if (!buffer) { | 271 | if (!buffer) { |
224 | dev_err(&port->dev, "out of memory\n"); | 272 | dev_err(&port->dev, "out of memory\n"); |
225 | count = -ENOMEM; | 273 | count = -ENOMEM; |
274 | |||
226 | goto error_no_buffer; | 275 | goto error_no_buffer; |
227 | } | 276 | } |
228 | 277 | ||
@@ -237,16 +286,31 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
237 | 286 | ||
238 | usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); | 287 | usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); |
239 | 288 | ||
240 | usb_fill_bulk_urb(urb, serial->dev, | 289 | /* The conncected devices do not have a bulk write endpoint, |
241 | usb_sndbulkpipe(serial->dev, | 290 | * to transmit data to de barcode device the control endpoint is used */ |
242 | port->bulk_out_endpointAddress), | 291 | dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); |
243 | buffer, count, opticon_write_bulk_callback, priv); | 292 | if (!dr) { |
293 | dev_err(&port->dev, "out of memory\n"); | ||
294 | count = -ENOMEM; | ||
295 | goto error; | ||
296 | } | ||
297 | |||
298 | dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; | ||
299 | dr->bRequest = 0x01; | ||
300 | dr->wValue = 0; | ||
301 | dr->wIndex = 0; | ||
302 | dr->wLength = cpu_to_le16(count); | ||
303 | |||
304 | usb_fill_control_urb(urb, serial->dev, | ||
305 | usb_sndctrlpipe(serial->dev, 0), | ||
306 | (unsigned char *)dr, buffer, count, | ||
307 | opticon_write_control_callback, priv); | ||
244 | 308 | ||
245 | /* send it down the pipe */ | 309 | /* send it down the pipe */ |
246 | status = usb_submit_urb(urb, GFP_ATOMIC); | 310 | status = usb_submit_urb(urb, GFP_ATOMIC); |
247 | if (status) { | 311 | if (status) { |
248 | dev_err(&port->dev, | 312 | dev_err(&port->dev, |
249 | "%s - usb_submit_urb(write bulk) failed with status = %d\n", | 313 | "%s - usb_submit_urb(write endpoint) failed status = %d\n", |
250 | __func__, status); | 314 | __func__, status); |
251 | count = status; | 315 | count = status; |
252 | goto error; | 316 | goto error; |
@@ -330,7 +394,7 @@ static void opticon_unthrottle(struct tty_struct *tty) | |||
330 | } | 394 | } |
331 | } | 395 | } |
332 | 396 | ||
333 | static int opticon_tiocmget(struct tty_struct *tty, struct file *file) | 397 | static int opticon_tiocmget(struct tty_struct *tty) |
334 | { | 398 | { |
335 | struct usb_serial_port *port = tty->driver_data; | 399 | struct usb_serial_port *port = tty->driver_data; |
336 | struct opticon_private *priv = usb_get_serial_data(port->serial); | 400 | struct opticon_private *priv = usb_get_serial_data(port->serial); |
@@ -338,16 +402,49 @@ static int opticon_tiocmget(struct tty_struct *tty, struct file *file) | |||
338 | int result = 0; | 402 | int result = 0; |
339 | 403 | ||
340 | dbg("%s - port %d", __func__, port->number); | 404 | dbg("%s - port %d", __func__, port->number); |
405 | if (!usb_get_intfdata(port->serial->interface)) | ||
406 | return -ENODEV; | ||
341 | 407 | ||
342 | spin_lock_irqsave(&priv->lock, flags); | 408 | spin_lock_irqsave(&priv->lock, flags); |
343 | if (priv->rts) | 409 | if (priv->rts) |
344 | result = TIOCM_RTS; | 410 | result |= TIOCM_RTS; |
411 | if (priv->cts) | ||
412 | result |= TIOCM_CTS; | ||
345 | spin_unlock_irqrestore(&priv->lock, flags); | 413 | spin_unlock_irqrestore(&priv->lock, flags); |
346 | 414 | ||
347 | dbg("%s - %x", __func__, result); | 415 | dbg("%s - %x", __func__, result); |
348 | return result; | 416 | return result; |
349 | } | 417 | } |
350 | 418 | ||
419 | static int opticon_tiocmset(struct tty_struct *tty, | ||
420 | unsigned int set, unsigned int clear) | ||
421 | { | ||
422 | struct usb_serial_port *port = tty->driver_data; | ||
423 | struct opticon_private *priv = usb_get_serial_data(port->serial); | ||
424 | unsigned long flags; | ||
425 | bool rts; | ||
426 | bool changed = false; | ||
427 | |||
428 | if (!usb_get_intfdata(port->serial->interface)) | ||
429 | return -ENODEV; | ||
430 | /* We only support RTS so we only handle that */ | ||
431 | spin_lock_irqsave(&priv->lock, flags); | ||
432 | |||
433 | rts = priv->rts; | ||
434 | if (set & TIOCM_RTS) | ||
435 | priv->rts = true; | ||
436 | if (clear & TIOCM_RTS) | ||
437 | priv->rts = false; | ||
438 | changed = rts ^ priv->rts; | ||
439 | spin_unlock_irqrestore(&priv->lock, flags); | ||
440 | |||
441 | if (!changed) | ||
442 | return 0; | ||
443 | |||
444 | /* Send the new RTS state to the connected device */ | ||
445 | return send_control_msg(port, CONTROL_RTS, !rts); | ||
446 | } | ||
447 | |||
351 | static int get_serial_info(struct opticon_private *priv, | 448 | static int get_serial_info(struct opticon_private *priv, |
352 | struct serial_struct __user *serial) | 449 | struct serial_struct __user *serial) |
353 | { | 450 | { |
@@ -374,7 +471,7 @@ static int get_serial_info(struct opticon_private *priv, | |||
374 | return 0; | 471 | return 0; |
375 | } | 472 | } |
376 | 473 | ||
377 | static int opticon_ioctl(struct tty_struct *tty, struct file *file, | 474 | static int opticon_ioctl(struct tty_struct *tty, |
378 | unsigned int cmd, unsigned long arg) | 475 | unsigned int cmd, unsigned long arg) |
379 | { | 476 | { |
380 | struct usb_serial_port *port = tty->driver_data; | 477 | struct usb_serial_port *port = tty->driver_data; |
@@ -409,6 +506,7 @@ static int opticon_startup(struct usb_serial *serial) | |||
409 | priv->serial = serial; | 506 | priv->serial = serial; |
410 | priv->port = serial->port[0]; | 507 | priv->port = serial->port[0]; |
411 | priv->udev = serial->dev; | 508 | priv->udev = serial->dev; |
509 | priv->outstanding_urbs = 0; /* Init the outstanding urbs */ | ||
412 | 510 | ||
413 | /* find our bulk endpoint */ | 511 | /* find our bulk endpoint */ |
414 | intf = serial->interface->altsetting; | 512 | intf = serial->interface->altsetting; |
@@ -434,13 +532,6 @@ static int opticon_startup(struct usb_serial *serial) | |||
434 | 532 | ||
435 | priv->bulk_address = endpoint->bEndpointAddress; | 533 | priv->bulk_address = endpoint->bEndpointAddress; |
436 | 534 | ||
437 | /* set up our bulk urb */ | ||
438 | usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, | ||
439 | usb_rcvbulkpipe(priv->udev, | ||
440 | endpoint->bEndpointAddress), | ||
441 | priv->bulk_in_buffer, priv->buffer_size, | ||
442 | opticon_bulk_callback, priv); | ||
443 | |||
444 | bulk_in_found = true; | 535 | bulk_in_found = true; |
445 | break; | 536 | break; |
446 | } | 537 | } |
@@ -536,6 +627,7 @@ static struct usb_serial_driver opticon_device = { | |||
536 | .unthrottle = opticon_unthrottle, | 627 | .unthrottle = opticon_unthrottle, |
537 | .ioctl = opticon_ioctl, | 628 | .ioctl = opticon_ioctl, |
538 | .tiocmget = opticon_tiocmget, | 629 | .tiocmget = opticon_tiocmget, |
630 | .tiocmset = opticon_tiocmset, | ||
539 | }; | 631 | }; |
540 | 632 | ||
541 | static int __init opticon_init(void) | 633 | static int __init opticon_init(void) |
@@ -559,6 +651,7 @@ static void __exit opticon_exit(void) | |||
559 | 651 | ||
560 | module_init(opticon_init); | 652 | module_init(opticon_init); |
561 | module_exit(opticon_exit); | 653 | module_exit(opticon_exit); |
654 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
562 | MODULE_LICENSE("GPL"); | 655 | MODULE_LICENSE("GPL"); |
563 | 656 | ||
564 | module_param(debug, bool, S_IRUGO | S_IWUSR); | 657 | module_param(debug, bool, S_IRUGO | S_IWUSR); |