aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/metro-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/metro-usb.c')
-rw-r--r--drivers/usb/serial/metro-usb.c92
1 files changed, 73 insertions, 19 deletions
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 08d16e8c002d..81423f7361db 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -17,7 +17,6 @@
17#include <linux/tty_flip.h> 17#include <linux/tty_flip.h>
18#include <linux/moduleparam.h> 18#include <linux/moduleparam.h>
19#include <linux/spinlock.h> 19#include <linux/spinlock.h>
20#include <linux/errno.h>
21#include <linux/uaccess.h> 20#include <linux/uaccess.h>
22#include <linux/usb/serial.h> 21#include <linux/usb/serial.h>
23 22
@@ -56,6 +55,47 @@ MODULE_DEVICE_TABLE(usb, id_table);
56/* Input parameter constants. */ 55/* Input parameter constants. */
57static bool debug; 56static bool debug;
58 57
58/* UNI-Directional mode commands for device configure */
59#define UNI_CMD_OPEN 0x80
60#define UNI_CMD_CLOSE 0xFF
61
62inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
63{
64 __u16 product_id = le16_to_cpu(
65 port->serial->dev->descriptor.idProduct);
66
67 return product_id == FOCUS_PRODUCT_ID_UNI;
68}
69
70static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
71{
72 int ret;
73 int actual_len;
74 u8 *buffer_cmd = NULL;
75
76 if (!metrousb_is_unidirectional_mode(port))
77 return 0;
78
79 buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
80 if (!buffer_cmd)
81 return -ENOMEM;
82
83 *buffer_cmd = cmd;
84
85 ret = usb_interrupt_msg(port->serial->dev,
86 usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
87 buffer_cmd, sizeof(cmd),
88 &actual_len, USB_CTRL_SET_TIMEOUT);
89
90 kfree(buffer_cmd);
91
92 if (ret < 0)
93 return ret;
94 else if (actual_len != sizeof(cmd))
95 return -EIO;
96 return 0;
97}
98
59static void metrousb_read_int_callback(struct urb *urb) 99static void metrousb_read_int_callback(struct urb *urb)
60{ 100{
61 struct usb_serial_port *port = urb->context; 101 struct usb_serial_port *port = urb->context;
@@ -78,12 +118,12 @@ static void metrousb_read_int_callback(struct urb *urb)
78 /* urb has been terminated. */ 118 /* urb has been terminated. */
79 dev_dbg(&port->dev, 119 dev_dbg(&port->dev,
80 "%s - urb shutting down, error code=%d\n", 120 "%s - urb shutting down, error code=%d\n",
81 __func__, result); 121 __func__, urb->status);
82 return; 122 return;
83 default: 123 default:
84 dev_dbg(&port->dev, 124 dev_dbg(&port->dev,
85 "%s - non-zero urb received, error code=%d\n", 125 "%s - non-zero urb received, error code=%d\n",
86 __func__, result); 126 __func__, urb->status);
87 goto exit; 127 goto exit;
88 } 128 }
89 129
@@ -91,7 +131,7 @@ static void metrousb_read_int_callback(struct urb *urb)
91 /* Set the data read from the usb port into the serial port buffer. */ 131 /* Set the data read from the usb port into the serial port buffer. */
92 tty = tty_port_tty_get(&port->port); 132 tty = tty_port_tty_get(&port->port);
93 if (!tty) { 133 if (!tty) {
94 dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n", 134 dev_err(&port->dev, "%s - bad tty pointer - exiting\n",
95 __func__); 135 __func__);
96 return; 136 return;
97 } 137 }
@@ -121,7 +161,7 @@ static void metrousb_read_int_callback(struct urb *urb)
121 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 161 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
122 162
123 if (result) 163 if (result)
124 dev_dbg(&port->dev, 164 dev_err(&port->dev,
125 "%s - failed submitting interrupt in urb, error code=%d\n", 165 "%s - failed submitting interrupt in urb, error code=%d\n",
126 __func__, result); 166 __func__, result);
127 } 167 }
@@ -131,11 +171,19 @@ exit:
131 /* Try to resubmit the urb. */ 171 /* Try to resubmit the urb. */
132 result = usb_submit_urb(urb, GFP_ATOMIC); 172 result = usb_submit_urb(urb, GFP_ATOMIC);
133 if (result) 173 if (result)
134 dev_dbg(&port->dev, 174 dev_err(&port->dev,
135 "%s - failed submitting interrupt in urb, error code=%d\n", 175 "%s - failed submitting interrupt in urb, error code=%d\n",
136 __func__, result); 176 __func__, result);
137} 177}
138 178
179static void metrousb_write_int_callback(struct urb *urb)
180{
181 struct usb_serial_port *port = urb->context;
182
183 dev_warn(&port->dev, "%s not implemented yet.\n",
184 __func__);
185}
186
139static void metrousb_cleanup(struct usb_serial_port *port) 187static void metrousb_cleanup(struct usb_serial_port *port)
140{ 188{
141 dev_dbg(&port->dev, "%s\n", __func__); 189 dev_dbg(&port->dev, "%s\n", __func__);
@@ -146,6 +194,9 @@ static void metrousb_cleanup(struct usb_serial_port *port)
146 usb_unlink_urb(port->interrupt_in_urb); 194 usb_unlink_urb(port->interrupt_in_urb);
147 usb_kill_urb(port->interrupt_in_urb); 195 usb_kill_urb(port->interrupt_in_urb);
148 } 196 }
197
198 /* Send deactivate cmd to device */
199 metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
149 } 200 }
150} 201}
151 202
@@ -160,7 +211,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
160 211
161 /* Make sure the urb is initialized. */ 212 /* Make sure the urb is initialized. */
162 if (!port->interrupt_in_urb) { 213 if (!port->interrupt_in_urb) {
163 dev_dbg(&port->dev, "%s - interrupt urb not initialized\n", 214 dev_err(&port->dev, "%s - interrupt urb not initialized\n",
164 __func__); 215 __func__);
165 return -ENODEV; 216 return -ENODEV;
166 } 217 }
@@ -191,12 +242,21 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
191 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 242 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
192 243
193 if (result) { 244 if (result) {
194 dev_dbg(&port->dev, 245 dev_err(&port->dev,
195 "%s - failed submitting interrupt in urb, error code=%d\n", 246 "%s - failed submitting interrupt in urb, error code=%d\n",
196 __func__, result); 247 __func__, result);
197 goto exit; 248 goto exit;
198 } 249 }
199 250
251 /* Send activate cmd to device */
252 result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port);
253 if (result) {
254 dev_err(&port->dev,
255 "%s - failed to configure device for port number=%d, error code=%d\n",
256 __func__, port->number, result);
257 goto exit;
258 }
259
200 dev_dbg(&port->dev, "%s - port open\n", __func__); 260 dev_dbg(&port->dev, "%s - port open\n", __func__);
201exit: 261exit:
202 return result; 262 return result;
@@ -221,7 +281,7 @@ static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int contr
221 METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST, 281 METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST,
222 control_state, 0, NULL, 0, WDR_TIMEOUT); 282 control_state, 0, NULL, 0, WDR_TIMEOUT);
223 if (retval < 0) 283 if (retval < 0)
224 dev_dbg(&serial->dev->dev, 284 dev_err(&serial->dev->dev,
225 "%s - set modem ctrl=0x%x failed, error code=%d\n", 285 "%s - set modem ctrl=0x%x failed, error code=%d\n",
226 __func__, mcr, retval); 286 __func__, mcr, retval);
227 287
@@ -354,29 +414,23 @@ static void metrousb_unthrottle(struct tty_struct *tty)
354 port->interrupt_in_urb->dev = port->serial->dev; 414 port->interrupt_in_urb->dev = port->serial->dev;
355 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 415 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
356 if (result) 416 if (result)
357 dev_dbg(tty->dev, 417 dev_err(tty->dev,
358 "failed submitting interrupt in urb error code=%d\n", 418 "failed submitting interrupt in urb error code=%d\n",
359 result); 419 result);
360} 420}
361 421
362static struct usb_driver metrousb_driver = {
363 .name = "metro-usb",
364 .probe = usb_serial_probe,
365 .disconnect = usb_serial_disconnect,
366 .id_table = id_table
367};
368
369static struct usb_serial_driver metrousb_device = { 422static struct usb_serial_driver metrousb_device = {
370 .driver = { 423 .driver = {
371 .owner = THIS_MODULE, 424 .owner = THIS_MODULE,
372 .name = "metro-usb", 425 .name = "metro-usb",
373 }, 426 },
374 .description = "Metrologic USB to serial converter.", 427 .description = "Metrologic USB to Serial",
375 .id_table = id_table, 428 .id_table = id_table,
376 .num_ports = 1, 429 .num_ports = 1,
377 .open = metrousb_open, 430 .open = metrousb_open,
378 .close = metrousb_cleanup, 431 .close = metrousb_cleanup,
379 .read_int_callback = metrousb_read_int_callback, 432 .read_int_callback = metrousb_read_int_callback,
433 .write_int_callback = metrousb_write_int_callback,
380 .attach = metrousb_startup, 434 .attach = metrousb_startup,
381 .release = metrousb_shutdown, 435 .release = metrousb_shutdown,
382 .throttle = metrousb_throttle, 436 .throttle = metrousb_throttle,
@@ -390,7 +444,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
390 NULL, 444 NULL,
391}; 445};
392 446
393module_usb_serial_driver(metrousb_driver, serial_drivers); 447module_usb_serial_driver(serial_drivers, id_table);
394 448
395MODULE_LICENSE("GPL"); 449MODULE_LICENSE("GPL");
396MODULE_AUTHOR("Philip Nicastro"); 450MODULE_AUTHOR("Philip Nicastro");