blob: 3f499fcfd83c051b347daa97ffb3c92969808d6f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Prolific PL2303 USB to serial adaptor driver
3 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07004 * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2003 IBM Corp.
6 *
7 * Original driver for 2.2.x by anonymous
8 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07009 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 *
13 * See Documentation/usb/usb-serial.txt for more information on using this driver
14 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 */
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/tty.h>
22#include <linux/tty_driver.h>
23#include <linux/tty_flip.h>
24#include <linux/serial.h>
25#include <linux/module.h>
26#include <linux/moduleparam.h>
27#include <linux/spinlock.h>
28#include <asm/uaccess.h>
29#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070030#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include "pl2303.h"
32
33/*
34 * Version Information
35 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
37
38static int debug;
39
40#define PL2303_CLOSING_WAIT (30*HZ)
41
42#define PL2303_BUF_SIZE 1024
43#define PL2303_TMP_BUF_SIZE 1024
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045struct pl2303_buf {
46 unsigned int buf_size;
47 char *buf_buf;
48 char *buf_get;
49 char *buf_put;
50};
51
52static struct usb_device_id id_table [] = {
53 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
54 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100055 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
57 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
58 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090059 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
61 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
62 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
63 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
64 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080065 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
67 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
68 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
69 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
70 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
71 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
72 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
73 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080074 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080076 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020077 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070078 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010079 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
80 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010081 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010082 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080083 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040084 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100085 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020086 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
Wesley PA4WDHb697f702006-09-28 20:45:38 +020087 { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090088 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090089 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Piotr Roszatycki002e8f22008-01-02 11:16:57 +010090 { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050091 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 { } /* Terminating entry */
93};
94
Thiago Galesi372db8a2006-07-31 15:39:27 -030095MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 .name = "pl2303",
99 .probe = usb_serial_probe,
100 .disconnect = usb_serial_disconnect,
101 .id_table = id_table,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800102 .no_dynamic_id = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103};
104
105#define SET_LINE_REQUEST_TYPE 0x21
106#define SET_LINE_REQUEST 0x20
107
108#define SET_CONTROL_REQUEST_TYPE 0x21
109#define SET_CONTROL_REQUEST 0x22
110#define CONTROL_DTR 0x01
111#define CONTROL_RTS 0x02
112
113#define BREAK_REQUEST_TYPE 0x21
114#define BREAK_REQUEST 0x23
115#define BREAK_ON 0xffff
116#define BREAK_OFF 0x0000
117
118#define GET_LINE_REQUEST_TYPE 0xa1
119#define GET_LINE_REQUEST 0x21
120
121#define VENDOR_WRITE_REQUEST_TYPE 0x40
122#define VENDOR_WRITE_REQUEST 0x01
123
124#define VENDOR_READ_REQUEST_TYPE 0xc0
125#define VENDOR_READ_REQUEST 0x01
126
127#define UART_STATE 0x08
128#define UART_STATE_TRANSIENT_MASK 0x74
129#define UART_DCD 0x01
130#define UART_DSR 0x02
131#define UART_BREAK_ERROR 0x04
132#define UART_RING 0x08
133#define UART_FRAME_ERROR 0x10
134#define UART_PARITY_ERROR 0x20
135#define UART_OVERRUN_ERROR 0x40
136#define UART_CTS 0x80
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139enum pl2303_type {
140 type_0, /* don't know the difference between type 0 and */
141 type_1, /* type 1, until someone from prolific tells us... */
142 HX, /* HX version of the pl2303 chip */
143};
144
145struct pl2303_private {
146 spinlock_t lock;
147 struct pl2303_buf *buf;
148 int write_urb_in_use;
149 wait_queue_head_t delta_msr_wait;
150 u8 line_control;
151 u8 line_status;
152 u8 termios_initialized;
153 enum pl2303_type type;
154};
155
Thiago Galesi572d3132006-07-29 10:46:37 -0300156/*
157 * pl2303_buf_alloc
158 *
159 * Allocate a circular buffer and all associated memory.
160 */
161static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
162{
163 struct pl2303_buf *pb;
164
165 if (size == 0)
166 return NULL;
167
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800168 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300169 if (pb == NULL)
170 return NULL;
171
172 pb->buf_buf = kmalloc(size, GFP_KERNEL);
173 if (pb->buf_buf == NULL) {
174 kfree(pb);
175 return NULL;
176 }
177
178 pb->buf_size = size;
179 pb->buf_get = pb->buf_put = pb->buf_buf;
180
181 return pb;
182}
183
184/*
185 * pl2303_buf_free
186 *
187 * Free the buffer and all associated memory.
188 */
189static void pl2303_buf_free(struct pl2303_buf *pb)
190{
191 if (pb) {
192 kfree(pb->buf_buf);
193 kfree(pb);
194 }
195}
196
197/*
198 * pl2303_buf_clear
199 *
200 * Clear out all data in the circular buffer.
201 */
202static void pl2303_buf_clear(struct pl2303_buf *pb)
203{
204 if (pb != NULL)
205 pb->buf_get = pb->buf_put;
206 /* equivalent to a get of all data available */
207}
208
209/*
210 * pl2303_buf_data_avail
211 *
212 * Return the number of bytes of data available in the circular
213 * buffer.
214 */
215static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
216{
217 if (pb == NULL)
218 return 0;
219
220 return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
221}
222
223/*
224 * pl2303_buf_space_avail
225 *
226 * Return the number of bytes of space available in the circular
227 * buffer.
228 */
229static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
230{
231 if (pb == NULL)
232 return 0;
233
234 return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
235}
236
237/*
238 * pl2303_buf_put
239 *
240 * Copy data data from a user buffer and put it into the circular buffer.
241 * Restrict to the amount of space available.
242 *
243 * Return the number of bytes copied.
244 */
245static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
246 unsigned int count)
247{
248 unsigned int len;
249
250 if (pb == NULL)
251 return 0;
252
253 len = pl2303_buf_space_avail(pb);
254 if (count > len)
255 count = len;
256
257 if (count == 0)
258 return 0;
259
260 len = pb->buf_buf + pb->buf_size - pb->buf_put;
261 if (count > len) {
262 memcpy(pb->buf_put, buf, len);
263 memcpy(pb->buf_buf, buf+len, count - len);
264 pb->buf_put = pb->buf_buf + count - len;
265 } else {
266 memcpy(pb->buf_put, buf, count);
267 if (count < len)
268 pb->buf_put += count;
269 else /* count == len */
270 pb->buf_put = pb->buf_buf;
271 }
272
273 return count;
274}
275
276/*
277 * pl2303_buf_get
278 *
279 * Get data from the circular buffer and copy to the given buffer.
280 * Restrict to the amount of data available.
281 *
282 * Return the number of bytes copied.
283 */
284static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
285 unsigned int count)
286{
287 unsigned int len;
288
289 if (pb == NULL)
290 return 0;
291
292 len = pl2303_buf_data_avail(pb);
293 if (count > len)
294 count = len;
295
296 if (count == 0)
297 return 0;
298
299 len = pb->buf_buf + pb->buf_size - pb->buf_get;
300 if (count > len) {
301 memcpy(buf, pb->buf_get, len);
302 memcpy(buf+len, pb->buf_buf, count - len);
303 pb->buf_get = pb->buf_buf + count - len;
304 } else {
305 memcpy(buf, pb->buf_get, count);
306 if (count < len)
307 pb->buf_get += count;
308 else /* count == len */
309 pb->buf_get = pb->buf_buf;
310 }
311
312 return count;
313}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Thiago Galesi372db8a2006-07-31 15:39:27 -0300315static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 struct pl2303_private *priv;
318 enum pl2303_type type = type_0;
319 int i;
320
321 if (serial->dev->descriptor.bDeviceClass == 0x02)
322 type = type_0;
323 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
324 type = HX;
325 else if (serial->dev->descriptor.bDeviceClass == 0x00)
326 type = type_1;
327 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
328 type = type_1;
329 dbg("device type: %d", type);
330
331 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100332 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 if (!priv)
334 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 spin_lock_init(&priv->lock);
336 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
337 if (priv->buf == NULL) {
338 kfree(priv);
339 goto cleanup;
340 }
341 init_waitqueue_head(&priv->delta_msr_wait);
342 priv->type = type;
343 usb_set_serial_port_data(serial->port[i], priv);
344 }
345 return 0;
346
347cleanup:
348 for (--i; i>=0; --i) {
349 priv = usb_get_serial_port_data(serial->port[i]);
350 pl2303_buf_free(priv->buf);
351 kfree(priv);
352 usb_set_serial_port_data(serial->port[i], NULL);
353 }
354 return -ENOMEM;
355}
356
Thiago Galesi372db8a2006-07-31 15:39:27 -0300357static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
359 int retval;
360
Thiago Galesi372db8a2006-07-31 15:39:27 -0300361 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
362 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
363 value, 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
365 return retval;
366}
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368static void pl2303_send(struct usb_serial_port *port)
369{
370 int count, result;
371 struct pl2303_private *priv = usb_get_serial_port_data(port);
372 unsigned long flags;
373
374 dbg("%s - port %d", __FUNCTION__, port->number);
375
376 spin_lock_irqsave(&priv->lock, flags);
377
378 if (priv->write_urb_in_use) {
379 spin_unlock_irqrestore(&priv->lock, flags);
380 return;
381 }
382
383 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300384 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
386 if (count == 0) {
387 spin_unlock_irqrestore(&priv->lock, flags);
388 return;
389 }
390
391 priv->write_urb_in_use = 1;
392
393 spin_unlock_irqrestore(&priv->lock, flags);
394
Thiago Galesi372db8a2006-07-31 15:39:27 -0300395 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
396 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 port->write_urb->transfer_buffer_length = count;
399 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300400 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300402 dev_err(&port->dev, "%s - failed submitting write urb,"
403 " error %d\n", __FUNCTION__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 priv->write_urb_in_use = 0;
405 // TODO: reschedule pl2303_send
406 }
407
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700408 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409}
410
Thiago Galesi572d3132006-07-29 10:46:37 -0300411static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
412 int count)
413{
414 struct pl2303_private *priv = usb_get_serial_port_data(port);
415 unsigned long flags;
416
417 dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
418
419 if (!count)
420 return count;
421
422 spin_lock_irqsave(&priv->lock, flags);
423 count = pl2303_buf_put(priv->buf, buf, count);
424 spin_unlock_irqrestore(&priv->lock, flags);
425
426 pl2303_send(port);
427
428 return count;
429}
430
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431static int pl2303_write_room(struct usb_serial_port *port)
432{
433 struct pl2303_private *priv = usb_get_serial_port_data(port);
434 int room = 0;
435 unsigned long flags;
436
437 dbg("%s - port %d", __FUNCTION__, port->number);
438
439 spin_lock_irqsave(&priv->lock, flags);
440 room = pl2303_buf_space_avail(priv->buf);
441 spin_unlock_irqrestore(&priv->lock, flags);
442
443 dbg("%s - returns %d", __FUNCTION__, room);
444 return room;
445}
446
447static int pl2303_chars_in_buffer(struct usb_serial_port *port)
448{
449 struct pl2303_private *priv = usb_get_serial_port_data(port);
450 int chars = 0;
451 unsigned long flags;
452
453 dbg("%s - port %d", __FUNCTION__, port->number);
454
455 spin_lock_irqsave(&priv->lock, flags);
456 chars = pl2303_buf_data_avail(priv->buf);
457 spin_unlock_irqrestore(&priv->lock, flags);
458
459 dbg("%s - returns %d", __FUNCTION__, chars);
460 return chars;
461}
462
Thiago Galesi372db8a2006-07-31 15:39:27 -0300463static void pl2303_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800464 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
466 struct usb_serial *serial = port->serial;
467 struct pl2303_private *priv = usb_get_serial_port_data(port);
468 unsigned long flags;
469 unsigned int cflag;
470 unsigned char *buf;
471 int baud;
472 int i;
473 u8 control;
474
475 dbg("%s - port %d", __FUNCTION__, port->number);
476
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 spin_lock_irqsave(&priv->lock, flags);
478 if (!priv->termios_initialized) {
479 *(port->tty->termios) = tty_std_termios;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300480 port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
481 HUPCL | CLOCAL;
Alan Coxdf64c472007-10-15 20:54:47 +0100482 port->tty->termios->c_ispeed = 9600;
483 port->tty->termios->c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 priv->termios_initialized = 1;
485 }
486 spin_unlock_irqrestore(&priv->lock, flags);
487
Alan Coxbf5e5832008-01-08 14:55:51 +0000488 /* The PL2303 is reported to lose bytes if you change
489 serial settings even to the same values as before. Thus
490 we actually need to filter in this specific case */
491
492 if (!tty_termios_hw_change(port->tty->termios, old_termios))
493 return;
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 cflag = port->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Thiago Galesi372db8a2006-07-31 15:39:27 -0300497 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 if (!buf) {
499 dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
500 return;
501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Thiago Galesi372db8a2006-07-31 15:39:27 -0300503 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
504 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
505 0, 0, buf, 7, 100);
506 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
507 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 if (cflag & CSIZE) {
510 switch (cflag & CSIZE) {
511 case CS5: buf[6] = 5; break;
512 case CS6: buf[6] = 6; break;
513 case CS7: buf[6] = 7; break;
514 default:
515 case CS8: buf[6] = 8; break;
516 }
517 dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
518 }
519
Alan Coxe0c79f52007-07-09 12:03:10 -0700520 baud = tty_get_baud_rate(port->tty);;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 dbg("%s - baud = %d", __FUNCTION__, baud);
522 if (baud) {
523 buf[0] = baud & 0xff;
524 buf[1] = (baud >> 8) & 0xff;
525 buf[2] = (baud >> 16) & 0xff;
526 buf[3] = (baud >> 24) & 0xff;
527 }
528
529 /* For reference buf[4]=0 is 1 stop bits */
530 /* For reference buf[4]=1 is 1.5 stop bits */
531 /* For reference buf[4]=2 is 2 stop bits */
532 if (cflag & CSTOPB) {
533 buf[4] = 2;
534 dbg("%s - stop bits = 2", __FUNCTION__);
535 } else {
536 buf[4] = 0;
537 dbg("%s - stop bits = 1", __FUNCTION__);
538 }
539
540 if (cflag & PARENB) {
541 /* For reference buf[5]=0 is none parity */
542 /* For reference buf[5]=1 is odd parity */
543 /* For reference buf[5]=2 is even parity */
544 /* For reference buf[5]=3 is mark parity */
545 /* For reference buf[5]=4 is space parity */
546 if (cflag & PARODD) {
547 buf[5] = 1;
548 dbg("%s - parity = odd", __FUNCTION__);
549 } else {
550 buf[5] = 2;
551 dbg("%s - parity = even", __FUNCTION__);
552 }
553 } else {
554 buf[5] = 0;
555 dbg("%s - parity = none", __FUNCTION__);
556 }
557
Thiago Galesi372db8a2006-07-31 15:39:27 -0300558 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
559 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
560 0, 0, buf, 7, 100);
561 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 /* change control lines if we are switching to or from B0 */
564 spin_lock_irqsave(&priv->lock, flags);
565 control = priv->line_control;
566 if ((cflag & CBAUD) == B0)
567 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
568 else
569 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
570 if (control != priv->line_control) {
571 control = priv->line_control;
572 spin_unlock_irqrestore(&priv->lock, flags);
573 set_control_lines(serial->dev, control);
574 } else {
575 spin_unlock_irqrestore(&priv->lock, flags);
576 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
579
Thiago Galesi372db8a2006-07-31 15:39:27 -0300580 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
581 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
582 0, 0, buf, 7, 100);
583 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
585
586 if (cflag & CRTSCTS) {
587 __u16 index;
588 if (priv->type == HX)
589 index = 0x61;
590 else
591 index = 0x41;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300592 i = usb_control_msg(serial->dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 usb_sndctrlpipe(serial->dev, 0),
594 VENDOR_WRITE_REQUEST,
595 VENDOR_WRITE_REQUEST_TYPE,
596 0x0, index, NULL, 0, 100);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300597 dbg("0x40:0x1:0x0:0x%x %d", index, i);
t.sefzick715f9522007-04-25 15:05:22 +0200598 } else {
599 i = usb_control_msg(serial->dev,
600 usb_sndctrlpipe(serial->dev, 0),
601 VENDOR_WRITE_REQUEST,
602 VENDOR_WRITE_REQUEST_TYPE,
603 0x0, 0x0, NULL, 0, 100);
604 dbg ("0x40:0x1:0x0:0x0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
606
Alan Coxdf64c472007-10-15 20:54:47 +0100607 /* FIXME: Need to read back resulting baud rate */
608 if (baud)
609 tty_encode_baud_rate(port->tty, baud, baud);
610
Thiago Galesi372db8a2006-07-31 15:39:27 -0300611 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612}
613
Thiago Galesi572d3132006-07-29 10:46:37 -0300614static void pl2303_close(struct usb_serial_port *port, struct file *filp)
615{
616 struct pl2303_private *priv = usb_get_serial_port_data(port);
617 unsigned long flags;
618 unsigned int c_cflag;
619 int bps;
620 long timeout;
621 wait_queue_t wait;
622
623 dbg("%s - port %d", __FUNCTION__, port->number);
624
625 /* wait for data to drain from the buffer */
626 spin_lock_irqsave(&priv->lock, flags);
627 timeout = PL2303_CLOSING_WAIT;
628 init_waitqueue_entry(&wait, current);
629 add_wait_queue(&port->tty->write_wait, &wait);
630 for (;;) {
631 set_current_state(TASK_INTERRUPTIBLE);
632 if (pl2303_buf_data_avail(priv->buf) == 0 ||
633 timeout == 0 || signal_pending(current) ||
634 !usb_get_intfdata(port->serial->interface)) /* disconnect */
635 break;
636 spin_unlock_irqrestore(&priv->lock, flags);
637 timeout = schedule_timeout(timeout);
638 spin_lock_irqsave(&priv->lock, flags);
639 }
640 set_current_state(TASK_RUNNING);
641 remove_wait_queue(&port->tty->write_wait, &wait);
642 /* clear out any remaining data in the buffer */
643 pl2303_buf_clear(priv->buf);
644 spin_unlock_irqrestore(&priv->lock, flags);
645
646 /* wait for characters to drain from the device */
647 /* (this is long enough for the entire 256 byte */
648 /* pl2303 hardware buffer to drain with no flow */
649 /* control for data rates of 1200 bps or more, */
650 /* for lower rates we should really know how much */
651 /* data is in the buffer to compute a delay */
652 /* that is not unnecessarily long) */
653 bps = tty_get_baud_rate(port->tty);
654 if (bps > 1200)
655 timeout = max((HZ*2560)/bps,HZ/10);
656 else
657 timeout = 2*HZ;
658 schedule_timeout_interruptible(timeout);
659
660 /* shutdown our urbs */
661 dbg("%s - shutting down urbs", __FUNCTION__);
662 usb_kill_urb(port->write_urb);
663 usb_kill_urb(port->read_urb);
664 usb_kill_urb(port->interrupt_in_urb);
665
666 if (port->tty) {
667 c_cflag = port->tty->termios->c_cflag;
668 if (c_cflag & HUPCL) {
669 /* drop DTR and RTS */
670 spin_lock_irqsave(&priv->lock, flags);
671 priv->line_control = 0;
672 spin_unlock_irqrestore(&priv->lock, flags);
673 set_control_lines(port->serial->dev, 0);
674 }
675 }
676}
677
Thiago Galesi372db8a2006-07-31 15:39:27 -0300678static int pl2303_open(struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Alan Cox606d0992006-12-08 02:38:45 -0800680 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 struct usb_serial *serial = port->serial;
682 struct pl2303_private *priv = usb_get_serial_port_data(port);
683 unsigned char *buf;
684 int result;
685
686 dbg("%s - port %d", __FUNCTION__, port->number);
687
Dariusz M16948992005-07-28 18:06:13 +0200688 if (priv->type != HX) {
689 usb_clear_halt(serial->dev, port->write_urb->pipe);
690 usb_clear_halt(serial->dev, port->read_urb->pipe);
691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 buf = kmalloc(10, GFP_KERNEL);
694 if (buf==NULL)
695 return -ENOMEM;
696
697#define FISH(a,b,c,d) \
698 result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
699 b, a, c, d, buf, 1, 100); \
700 dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]);
701
702#define SOUP(a,b,c,d) \
703 result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
704 b, a, c, d, NULL, 0, 100); \
705 dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result);
706
707 FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
708 SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
709 FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
710 FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
711 FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
712 SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
713 FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
714 FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
715 SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
716 SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0);
717
718 if (priv->type == HX) {
719 /* HX chip */
720 SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44);
721 /* reset upstream data pipes */
722 SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0);
723 SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0);
724 } else {
725 SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24);
726 }
727
728 kfree(buf);
729
730 /* Setup termios */
731 if (port->tty) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300732 pl2303_set_termios(port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734
735 //FIXME: need to assert RTS and DTR if CRTSCTS off
736
737 dbg("%s - submitting read urb", __FUNCTION__);
738 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300739 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300741 dev_err(&port->dev, "%s - failed submitting read urb,"
742 " error %d\n", __FUNCTION__, result);
743 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return -EPROTO;
745 }
746
747 dbg("%s - submitting interrupt urb", __FUNCTION__);
748 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300749 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300751 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
752 " error %d\n", __FUNCTION__, result);
753 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 return -EPROTO;
755 }
756 return 0;
757}
758
Thiago Galesi372db8a2006-07-31 15:39:27 -0300759static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
760 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
762 struct pl2303_private *priv = usb_get_serial_port_data(port);
763 unsigned long flags;
764 u8 control;
765
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700766 if (!usb_get_intfdata(port->serial->interface))
767 return -ENODEV;
768
Thiago Galesi372db8a2006-07-31 15:39:27 -0300769 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (set & TIOCM_RTS)
771 priv->line_control |= CONTROL_RTS;
772 if (set & TIOCM_DTR)
773 priv->line_control |= CONTROL_DTR;
774 if (clear & TIOCM_RTS)
775 priv->line_control &= ~CONTROL_RTS;
776 if (clear & TIOCM_DTR)
777 priv->line_control &= ~CONTROL_DTR;
778 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300779 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Thiago Galesi372db8a2006-07-31 15:39:27 -0300781 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782}
783
Thiago Galesi372db8a2006-07-31 15:39:27 -0300784static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
786 struct pl2303_private *priv = usb_get_serial_port_data(port);
787 unsigned long flags;
788 unsigned int mcr;
789 unsigned int status;
790 unsigned int result;
791
792 dbg("%s (%d)", __FUNCTION__, port->number);
793
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700794 if (!usb_get_intfdata(port->serial->interface))
795 return -ENODEV;
796
Thiago Galesi372db8a2006-07-31 15:39:27 -0300797 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 mcr = priv->line_control;
799 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300800 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
803 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
804 | ((status & UART_CTS) ? TIOCM_CTS : 0)
805 | ((status & UART_DSR) ? TIOCM_DSR : 0)
806 | ((status & UART_RING) ? TIOCM_RI : 0)
807 | ((status & UART_DCD) ? TIOCM_CD : 0);
808
809 dbg("%s - result = %x", __FUNCTION__, result);
810
811 return result;
812}
813
814static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
815{
816 struct pl2303_private *priv = usb_get_serial_port_data(port);
817 unsigned long flags;
818 unsigned int prevstatus;
819 unsigned int status;
820 unsigned int changed;
821
Thiago Galesi372db8a2006-07-31 15:39:27 -0300822 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300824 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826 while (1) {
827 interruptible_sleep_on(&priv->delta_msr_wait);
828 /* see if a signal did it */
829 if (signal_pending(current))
830 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300831
832 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300834 spin_unlock_irqrestore(&priv->lock, flags);
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 changed=prevstatus^status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
839 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
840 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
841 ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
842 return 0;
843 }
844 prevstatus = status;
845 }
846 /* NOTREACHED */
847 return 0;
848}
849
Thiago Galesi372db8a2006-07-31 15:39:27 -0300850static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
851 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852{
853 dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
854
855 switch (cmd) {
856 case TIOCMIWAIT:
857 dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
858 return wait_modem_info(port, arg);
859
860 default:
861 dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
862 break;
863 }
864
865 return -ENOIOCTLCMD;
866}
867
Thiago Galesi372db8a2006-07-31 15:39:27 -0300868static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869{
870 struct usb_serial *serial = port->serial;
871 u16 state;
872 int result;
873
874 dbg("%s - port %d", __FUNCTION__, port->number);
875
876 if (break_state == 0)
877 state = BREAK_OFF;
878 else
879 state = BREAK_ON;
880 dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
881
Thiago Galesi372db8a2006-07-31 15:39:27 -0300882 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
883 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
884 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 if (result)
886 dbg("%s - error sending break = %d", __FUNCTION__, result);
887}
888
Thiago Galesi372db8a2006-07-31 15:39:27 -0300889static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
891 int i;
892 struct pl2303_private *priv;
893
894 dbg("%s", __FUNCTION__);
895
896 for (i = 0; i < serial->num_ports; ++i) {
897 priv = usb_get_serial_port_data(serial->port[i]);
898 if (priv) {
899 pl2303_buf_free(priv->buf);
900 kfree(priv);
901 usb_set_serial_port_data(serial->port[i], NULL);
902 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904}
905
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700906static void pl2303_update_line_status(struct usb_serial_port *port,
907 unsigned char *data,
908 unsigned int actual_length)
909{
910
911 struct pl2303_private *priv = usb_get_serial_port_data(port);
912 unsigned long flags;
913 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200914 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300915 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700916
Thiago Galesi9c537612006-07-29 10:47:12 -0300917 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
918 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
919
920
921 if (idv == SIEMENS_VENDOR_ID) {
922 if (idp == SIEMENS_PRODUCT_ID_X65 ||
923 idp == SIEMENS_PRODUCT_ID_SX1 ||
924 idp == SIEMENS_PRODUCT_ID_X75) {
925
926 length = 1;
927 status_idx = 0;
928 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700929 }
930
931 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300932 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700933
934 /* Save off the uart status for others to look at */
935 spin_lock_irqsave(&priv->lock, flags);
936 priv->line_status = data[status_idx];
937 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300938 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700939}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
David Howells7d12e782006-10-05 14:55:46 +0100941static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942{
943 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700945 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700946 int status = urb->status;
947 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 dbg("%s (%d)", __FUNCTION__, port->number);
950
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700951 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 case 0:
953 /* success */
954 break;
955 case -ECONNRESET:
956 case -ENOENT:
957 case -ESHUTDOWN:
958 /* this urb is terminated, clean up */
Thiago Galesi372db8a2006-07-31 15:39:27 -0300959 dbg("%s - urb shutting down with status: %d", __FUNCTION__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700960 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 return;
962 default:
Thiago Galesi372db8a2006-07-31 15:39:27 -0300963 dbg("%s - nonzero urb status received: %d", __FUNCTION__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700964 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 goto exit;
966 }
967
Thiago Galesi372db8a2006-07-31 15:39:27 -0300968 usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
969 urb->actual_length, urb->transfer_buffer);
970
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700971 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700974 retval = usb_submit_urb(urb, GFP_ATOMIC);
975 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300976 dev_err(&urb->dev->dev,
977 "%s - usb_submit_urb failed with result %d\n",
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700978 __FUNCTION__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979}
980
David Howells7d12e782006-10-05 14:55:46 +0100981static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
983 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
984 struct pl2303_private *priv = usb_get_serial_port_data(port);
985 struct tty_struct *tty;
986 unsigned char *data = urb->transfer_buffer;
987 unsigned long flags;
988 int i;
989 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700990 int status = urb->status;
991 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 char tty_flag;
993
994 dbg("%s - port %d", __FUNCTION__, port->number);
995
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700996 if (status) {
997 dbg("%s - urb status = %d", __FUNCTION__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (!port->open_count) {
999 dbg("%s - port is closed, exiting.", __FUNCTION__);
1000 return;
1001 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001002 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001003 /* PL2303 mysteriously fails with -EPROTO reschedule
1004 * the read */
1005 dbg("%s - caught -EPROTO, resubmitting the urb",
1006 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 urb->dev = port->serial->dev;
1008 result = usb_submit_urb(urb, GFP_ATOMIC);
1009 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001010 dev_err(&urb->dev->dev, "%s - failed"
1011 " resubmitting read urb, error %d\n",
1012 __FUNCTION__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 return;
1014 }
1015 dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
1016 return;
1017 }
1018
Thiago Galesi372db8a2006-07-31 15:39:27 -03001019 usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
1020 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022 /* get tty_flag from status */
1023 tty_flag = TTY_NORMAL;
1024
1025 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001026 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1028 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001029 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
1031 /* break takes precedence over parity, */
1032 /* which takes precedence over framing errors */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001033 if (line_status & UART_BREAK_ERROR )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001035 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001037 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 tty_flag = TTY_FRAME;
1039 dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
1040
1041 tty = port->tty;
1042 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001043 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001045 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001047 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001048 tty_insert_flip_char(tty, data[i], tty_flag);
1049 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 }
1051
1052 /* Schedule the next read _if_ we are still open */
1053 if (port->open_count) {
1054 urb->dev = port->serial->dev;
1055 result = usb_submit_urb(urb, GFP_ATOMIC);
1056 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001057 dev_err(&urb->dev->dev, "%s - failed resubmitting"
1058 " read urb, error %d\n", __FUNCTION__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
1060
1061 return;
1062}
1063
David Howells7d12e782006-10-05 14:55:46 +01001064static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065{
1066 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
1067 struct pl2303_private *priv = usb_get_serial_port_data(port);
1068 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001069 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
1071 dbg("%s - port %d", __FUNCTION__, port->number);
1072
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001073 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 case 0:
1075 /* success */
1076 break;
1077 case -ECONNRESET:
1078 case -ENOENT:
1079 case -ESHUTDOWN:
1080 /* this urb is terminated, clean up */
Thiago Galesi372db8a2006-07-31 15:39:27 -03001081 dbg("%s - urb shutting down with status: %d", __FUNCTION__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001082 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 priv->write_urb_in_use = 0;
1084 return;
1085 default:
1086 /* error in the urb, so we have to resubmit it */
1087 dbg("%s - Overflow in write", __FUNCTION__);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001088 dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001089 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 port->write_urb->transfer_buffer_length = 1;
1091 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001092 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001094 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
1095 " urb, error %d\n", __FUNCTION__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 else
1097 return;
1098 }
1099
1100 priv->write_urb_in_use = 0;
1101
1102 /* send any buffered data */
1103 pl2303_send(port);
1104}
1105
Thiago Galesi572d3132006-07-29 10:46:37 -03001106/* All of the device info needed for the PL2303 SIO serial converter */
1107static struct usb_serial_driver pl2303_device = {
1108 .driver = {
1109 .owner = THIS_MODULE,
1110 .name = "pl2303",
1111 },
1112 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001113 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001114 .num_interrupt_in = NUM_DONT_CARE,
1115 .num_bulk_in = 1,
1116 .num_bulk_out = 1,
1117 .num_ports = 1,
1118 .open = pl2303_open,
1119 .close = pl2303_close,
1120 .write = pl2303_write,
1121 .ioctl = pl2303_ioctl,
1122 .break_ctl = pl2303_break_ctl,
1123 .set_termios = pl2303_set_termios,
1124 .tiocmget = pl2303_tiocmget,
1125 .tiocmset = pl2303_tiocmset,
1126 .read_bulk_callback = pl2303_read_bulk_callback,
1127 .read_int_callback = pl2303_read_int_callback,
1128 .write_bulk_callback = pl2303_write_bulk_callback,
1129 .write_room = pl2303_write_room,
1130 .chars_in_buffer = pl2303_chars_in_buffer,
1131 .attach = pl2303_startup,
1132 .shutdown = pl2303_shutdown,
1133};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Thiago Galesi372db8a2006-07-31 15:39:27 -03001135static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136{
1137 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 retval = usb_serial_register(&pl2303_device);
1140 if (retval)
1141 goto failed_usb_serial_register;
1142 retval = usb_register(&pl2303_driver);
1143 if (retval)
1144 goto failed_usb_register;
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001145 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 return 0;
1147failed_usb_register:
1148 usb_serial_deregister(&pl2303_device);
1149failed_usb_serial_register:
1150 return retval;
1151}
1152
Thiago Galesi372db8a2006-07-31 15:39:27 -03001153static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001155 usb_deregister(&pl2303_driver);
1156 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157}
1158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159module_init(pl2303_init);
1160module_exit(pl2303_exit);
1161
1162MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163MODULE_LICENSE("GPL");
1164
1165module_param(debug, bool, S_IRUGO | S_IWUSR);
1166MODULE_PARM_DESC(debug, "Debug enabled or not");
1167