diff options
Diffstat (limited to 'drivers/usb/serial/metro-usb.c')
-rw-r--r-- | drivers/usb/serial/metro-usb.c | 92 |
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. */ |
57 | static bool debug; | 56 | static 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 | |||
62 | inline 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 | |||
70 | static 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 | |||
59 | static void metrousb_read_int_callback(struct urb *urb) | 99 | static 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 | ||
179 | static 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 | |||
139 | static void metrousb_cleanup(struct usb_serial_port *port) | 187 | static 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__); |
201 | exit: | 261 | exit: |
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 | ||
362 | static 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 | |||
369 | static struct usb_serial_driver metrousb_device = { | 422 | static 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 | ||
393 | module_usb_serial_driver(metrousb_driver, serial_drivers); | 447 | module_usb_serial_driver(serial_drivers, id_table); |
394 | 448 | ||
395 | MODULE_LICENSE("GPL"); | 449 | MODULE_LICENSE("GPL"); |
396 | MODULE_AUTHOR("Philip Nicastro"); | 450 | MODULE_AUTHOR("Philip Nicastro"); |