blob: c27f2f822f13c376453ed4d269b82901ffe7d52b [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) },
Akira Tsukamoto57833ea2008-01-18 18:58:28 +090068 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
70 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
71 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
72 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
73 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
74 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080075 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080077 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020078 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070079 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010080 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
81 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010082 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010083 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080084 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040085 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100086 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020087 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_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
Sarah Sharpeb44da02007-12-14 14:08:00 -0800315static int pl2303_vendor_read(__u16 value, __u16 index,
316 struct usb_serial *serial, unsigned char *buf)
317{
318 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
319 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
320 value, index, buf, 1, 100);
321 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
322 VENDOR_READ_REQUEST, value, index, res, buf[0]);
323 return res;
324}
325
326static int pl2303_vendor_write(__u16 value, __u16 index,
327 struct usb_serial *serial)
328{
329 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
330 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
331 value, index, NULL, 0, 100);
332 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
333 VENDOR_WRITE_REQUEST, value, index, res);
334 return res;
335}
336
Thiago Galesi372db8a2006-07-31 15:39:27 -0300337static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 struct pl2303_private *priv;
340 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800341 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 int i;
343
Sarah Sharp3e152502007-12-14 14:08:35 -0800344 buf = kmalloc(10, GFP_KERNEL);
345 if (buf == NULL)
346 return -ENOMEM;
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if (serial->dev->descriptor.bDeviceClass == 0x02)
349 type = type_0;
350 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
351 type = HX;
352 else if (serial->dev->descriptor.bDeviceClass == 0x00)
353 type = type_1;
354 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
355 type = type_1;
356 dbg("device type: %d", type);
357
358 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100359 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 if (!priv)
361 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 spin_lock_init(&priv->lock);
363 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
364 if (priv->buf == NULL) {
365 kfree(priv);
366 goto cleanup;
367 }
368 init_waitqueue_head(&priv->delta_msr_wait);
369 priv->type = type;
370 usb_set_serial_port_data(serial->port[i], priv);
371 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800372
373 pl2303_vendor_read(0x8484, 0, serial, buf);
374 pl2303_vendor_write(0x0404, 0, serial);
375 pl2303_vendor_read(0x8484, 0, serial, buf);
376 pl2303_vendor_read(0x8383, 0, serial, buf);
377 pl2303_vendor_read(0x8484, 0, serial, buf);
378 pl2303_vendor_write(0x0404, 1, serial);
379 pl2303_vendor_read(0x8484, 0, serial, buf);
380 pl2303_vendor_read(0x8383, 0, serial, buf);
381 pl2303_vendor_write(0, 1, serial);
382 pl2303_vendor_write(1, 0, serial);
383 if (type == HX)
384 pl2303_vendor_write(2, 0x44, serial);
385 else
386 pl2303_vendor_write(2, 0x24, serial);
387
388 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return 0;
390
391cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800392 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 for (--i; i>=0; --i) {
394 priv = usb_get_serial_port_data(serial->port[i]);
395 pl2303_buf_free(priv->buf);
396 kfree(priv);
397 usb_set_serial_port_data(serial->port[i], NULL);
398 }
399 return -ENOMEM;
400}
401
Thiago Galesi372db8a2006-07-31 15:39:27 -0300402static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
404 int retval;
405
Thiago Galesi372db8a2006-07-31 15:39:27 -0300406 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
407 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
408 value, 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
410 return retval;
411}
412
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413static void pl2303_send(struct usb_serial_port *port)
414{
415 int count, result;
416 struct pl2303_private *priv = usb_get_serial_port_data(port);
417 unsigned long flags;
418
419 dbg("%s - port %d", __FUNCTION__, port->number);
420
421 spin_lock_irqsave(&priv->lock, flags);
422
423 if (priv->write_urb_in_use) {
424 spin_unlock_irqrestore(&priv->lock, flags);
425 return;
426 }
427
428 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300429 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431 if (count == 0) {
432 spin_unlock_irqrestore(&priv->lock, flags);
433 return;
434 }
435
436 priv->write_urb_in_use = 1;
437
438 spin_unlock_irqrestore(&priv->lock, flags);
439
Thiago Galesi372db8a2006-07-31 15:39:27 -0300440 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
441 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 port->write_urb->transfer_buffer_length = count;
444 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300445 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300447 dev_err(&port->dev, "%s - failed submitting write urb,"
448 " error %d\n", __FUNCTION__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 priv->write_urb_in_use = 0;
450 // TODO: reschedule pl2303_send
451 }
452
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700453 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454}
455
Thiago Galesi572d3132006-07-29 10:46:37 -0300456static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
457 int count)
458{
459 struct pl2303_private *priv = usb_get_serial_port_data(port);
460 unsigned long flags;
461
462 dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
463
464 if (!count)
465 return count;
466
467 spin_lock_irqsave(&priv->lock, flags);
468 count = pl2303_buf_put(priv->buf, buf, count);
469 spin_unlock_irqrestore(&priv->lock, flags);
470
471 pl2303_send(port);
472
473 return count;
474}
475
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476static int pl2303_write_room(struct usb_serial_port *port)
477{
478 struct pl2303_private *priv = usb_get_serial_port_data(port);
479 int room = 0;
480 unsigned long flags;
481
482 dbg("%s - port %d", __FUNCTION__, port->number);
483
484 spin_lock_irqsave(&priv->lock, flags);
485 room = pl2303_buf_space_avail(priv->buf);
486 spin_unlock_irqrestore(&priv->lock, flags);
487
488 dbg("%s - returns %d", __FUNCTION__, room);
489 return room;
490}
491
492static int pl2303_chars_in_buffer(struct usb_serial_port *port)
493{
494 struct pl2303_private *priv = usb_get_serial_port_data(port);
495 int chars = 0;
496 unsigned long flags;
497
498 dbg("%s - port %d", __FUNCTION__, port->number);
499
500 spin_lock_irqsave(&priv->lock, flags);
501 chars = pl2303_buf_data_avail(priv->buf);
502 spin_unlock_irqrestore(&priv->lock, flags);
503
504 dbg("%s - returns %d", __FUNCTION__, chars);
505 return chars;
506}
507
Thiago Galesi372db8a2006-07-31 15:39:27 -0300508static void pl2303_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800509 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 struct usb_serial *serial = port->serial;
512 struct pl2303_private *priv = usb_get_serial_port_data(port);
513 unsigned long flags;
514 unsigned int cflag;
515 unsigned char *buf;
516 int baud;
517 int i;
518 u8 control;
519
520 dbg("%s - port %d", __FUNCTION__, port->number);
521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 spin_lock_irqsave(&priv->lock, flags);
523 if (!priv->termios_initialized) {
524 *(port->tty->termios) = tty_std_termios;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300525 port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
526 HUPCL | CLOCAL;
Alan Coxdf64c472007-10-15 20:54:47 +0100527 port->tty->termios->c_ispeed = 9600;
528 port->tty->termios->c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 priv->termios_initialized = 1;
530 }
531 spin_unlock_irqrestore(&priv->lock, flags);
532
Alan Coxbf5e5832008-01-08 14:55:51 +0000533 /* The PL2303 is reported to lose bytes if you change
534 serial settings even to the same values as before. Thus
535 we actually need to filter in this specific case */
536
537 if (!tty_termios_hw_change(port->tty->termios, old_termios))
538 return;
539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 cflag = port->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Thiago Galesi372db8a2006-07-31 15:39:27 -0300542 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (!buf) {
544 dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
545 return;
546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Thiago Galesi372db8a2006-07-31 15:39:27 -0300548 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
549 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
550 0, 0, buf, 7, 100);
551 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
552 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 if (cflag & CSIZE) {
555 switch (cflag & CSIZE) {
556 case CS5: buf[6] = 5; break;
557 case CS6: buf[6] = 6; break;
558 case CS7: buf[6] = 7; break;
559 default:
560 case CS8: buf[6] = 8; break;
561 }
562 dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
563 }
564
Alan Coxe0c79f52007-07-09 12:03:10 -0700565 baud = tty_get_baud_rate(port->tty);;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 dbg("%s - baud = %d", __FUNCTION__, baud);
567 if (baud) {
568 buf[0] = baud & 0xff;
569 buf[1] = (baud >> 8) & 0xff;
570 buf[2] = (baud >> 16) & 0xff;
571 buf[3] = (baud >> 24) & 0xff;
572 }
573
574 /* For reference buf[4]=0 is 1 stop bits */
575 /* For reference buf[4]=1 is 1.5 stop bits */
576 /* For reference buf[4]=2 is 2 stop bits */
577 if (cflag & CSTOPB) {
578 buf[4] = 2;
579 dbg("%s - stop bits = 2", __FUNCTION__);
580 } else {
581 buf[4] = 0;
582 dbg("%s - stop bits = 1", __FUNCTION__);
583 }
584
585 if (cflag & PARENB) {
586 /* For reference buf[5]=0 is none parity */
587 /* For reference buf[5]=1 is odd parity */
588 /* For reference buf[5]=2 is even parity */
589 /* For reference buf[5]=3 is mark parity */
590 /* For reference buf[5]=4 is space parity */
591 if (cflag & PARODD) {
592 buf[5] = 1;
593 dbg("%s - parity = odd", __FUNCTION__);
594 } else {
595 buf[5] = 2;
596 dbg("%s - parity = even", __FUNCTION__);
597 }
598 } else {
599 buf[5] = 0;
600 dbg("%s - parity = none", __FUNCTION__);
601 }
602
Thiago Galesi372db8a2006-07-31 15:39:27 -0300603 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
604 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
605 0, 0, buf, 7, 100);
606 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 /* change control lines if we are switching to or from B0 */
609 spin_lock_irqsave(&priv->lock, flags);
610 control = priv->line_control;
611 if ((cflag & CBAUD) == B0)
612 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
613 else
614 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
615 if (control != priv->line_control) {
616 control = priv->line_control;
617 spin_unlock_irqrestore(&priv->lock, flags);
618 set_control_lines(serial->dev, control);
619 } else {
620 spin_unlock_irqrestore(&priv->lock, flags);
621 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
624
Thiago Galesi372db8a2006-07-31 15:39:27 -0300625 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
626 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
627 0, 0, buf, 7, 100);
628 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
630
631 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800633 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800635 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200636 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800637 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 }
639
Alan Coxdf64c472007-10-15 20:54:47 +0100640 /* FIXME: Need to read back resulting baud rate */
641 if (baud)
642 tty_encode_baud_rate(port->tty, baud, baud);
643
Thiago Galesi372db8a2006-07-31 15:39:27 -0300644 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645}
646
Thiago Galesi572d3132006-07-29 10:46:37 -0300647static void pl2303_close(struct usb_serial_port *port, struct file *filp)
648{
649 struct pl2303_private *priv = usb_get_serial_port_data(port);
650 unsigned long flags;
651 unsigned int c_cflag;
652 int bps;
653 long timeout;
654 wait_queue_t wait;
655
656 dbg("%s - port %d", __FUNCTION__, port->number);
657
658 /* wait for data to drain from the buffer */
659 spin_lock_irqsave(&priv->lock, flags);
660 timeout = PL2303_CLOSING_WAIT;
661 init_waitqueue_entry(&wait, current);
662 add_wait_queue(&port->tty->write_wait, &wait);
663 for (;;) {
664 set_current_state(TASK_INTERRUPTIBLE);
665 if (pl2303_buf_data_avail(priv->buf) == 0 ||
666 timeout == 0 || signal_pending(current) ||
667 !usb_get_intfdata(port->serial->interface)) /* disconnect */
668 break;
669 spin_unlock_irqrestore(&priv->lock, flags);
670 timeout = schedule_timeout(timeout);
671 spin_lock_irqsave(&priv->lock, flags);
672 }
673 set_current_state(TASK_RUNNING);
674 remove_wait_queue(&port->tty->write_wait, &wait);
675 /* clear out any remaining data in the buffer */
676 pl2303_buf_clear(priv->buf);
677 spin_unlock_irqrestore(&priv->lock, flags);
678
679 /* wait for characters to drain from the device */
680 /* (this is long enough for the entire 256 byte */
681 /* pl2303 hardware buffer to drain with no flow */
682 /* control for data rates of 1200 bps or more, */
683 /* for lower rates we should really know how much */
684 /* data is in the buffer to compute a delay */
685 /* that is not unnecessarily long) */
686 bps = tty_get_baud_rate(port->tty);
687 if (bps > 1200)
688 timeout = max((HZ*2560)/bps,HZ/10);
689 else
690 timeout = 2*HZ;
691 schedule_timeout_interruptible(timeout);
692
693 /* shutdown our urbs */
694 dbg("%s - shutting down urbs", __FUNCTION__);
695 usb_kill_urb(port->write_urb);
696 usb_kill_urb(port->read_urb);
697 usb_kill_urb(port->interrupt_in_urb);
698
699 if (port->tty) {
700 c_cflag = port->tty->termios->c_cflag;
701 if (c_cflag & HUPCL) {
702 /* drop DTR and RTS */
703 spin_lock_irqsave(&priv->lock, flags);
704 priv->line_control = 0;
705 spin_unlock_irqrestore(&priv->lock, flags);
706 set_control_lines(port->serial->dev, 0);
707 }
708 }
709}
710
Thiago Galesi372db8a2006-07-31 15:39:27 -0300711static int pl2303_open(struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712{
Alan Cox606d0992006-12-08 02:38:45 -0800713 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 struct usb_serial *serial = port->serial;
715 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 int result;
717
718 dbg("%s - port %d", __FUNCTION__, port->number);
719
Dariusz M16948992005-07-28 18:06:13 +0200720 if (priv->type != HX) {
721 usb_clear_halt(serial->dev, port->write_urb->pipe);
722 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800723 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800725 pl2303_vendor_write(8, 0, serial);
726 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 }
728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 /* Setup termios */
730 if (port->tty) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300731 pl2303_set_termios(port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 }
733
734 //FIXME: need to assert RTS and DTR if CRTSCTS off
735
736 dbg("%s - submitting read urb", __FUNCTION__);
737 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300738 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300740 dev_err(&port->dev, "%s - failed submitting read urb,"
741 " error %d\n", __FUNCTION__, result);
742 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return -EPROTO;
744 }
745
746 dbg("%s - submitting interrupt urb", __FUNCTION__);
747 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300748 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300750 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
751 " error %d\n", __FUNCTION__, result);
752 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return -EPROTO;
754 }
755 return 0;
756}
757
Thiago Galesi372db8a2006-07-31 15:39:27 -0300758static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
759 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
761 struct pl2303_private *priv = usb_get_serial_port_data(port);
762 unsigned long flags;
763 u8 control;
764
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700765 if (!usb_get_intfdata(port->serial->interface))
766 return -ENODEV;
767
Thiago Galesi372db8a2006-07-31 15:39:27 -0300768 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 if (set & TIOCM_RTS)
770 priv->line_control |= CONTROL_RTS;
771 if (set & TIOCM_DTR)
772 priv->line_control |= CONTROL_DTR;
773 if (clear & TIOCM_RTS)
774 priv->line_control &= ~CONTROL_RTS;
775 if (clear & TIOCM_DTR)
776 priv->line_control &= ~CONTROL_DTR;
777 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300778 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Thiago Galesi372db8a2006-07-31 15:39:27 -0300780 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781}
782
Thiago Galesi372db8a2006-07-31 15:39:27 -0300783static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784{
785 struct pl2303_private *priv = usb_get_serial_port_data(port);
786 unsigned long flags;
787 unsigned int mcr;
788 unsigned int status;
789 unsigned int result;
790
791 dbg("%s (%d)", __FUNCTION__, port->number);
792
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700793 if (!usb_get_intfdata(port->serial->interface))
794 return -ENODEV;
795
Thiago Galesi372db8a2006-07-31 15:39:27 -0300796 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 mcr = priv->line_control;
798 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300799 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
802 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
803 | ((status & UART_CTS) ? TIOCM_CTS : 0)
804 | ((status & UART_DSR) ? TIOCM_DSR : 0)
805 | ((status & UART_RING) ? TIOCM_RI : 0)
806 | ((status & UART_DCD) ? TIOCM_CD : 0);
807
808 dbg("%s - result = %x", __FUNCTION__, result);
809
810 return result;
811}
812
813static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
814{
815 struct pl2303_private *priv = usb_get_serial_port_data(port);
816 unsigned long flags;
817 unsigned int prevstatus;
818 unsigned int status;
819 unsigned int changed;
820
Thiago Galesi372db8a2006-07-31 15:39:27 -0300821 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300823 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 while (1) {
826 interruptible_sleep_on(&priv->delta_msr_wait);
827 /* see if a signal did it */
828 if (signal_pending(current))
829 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300830
831 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300833 spin_unlock_irqrestore(&priv->lock, flags);
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 changed=prevstatus^status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
838 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
839 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
840 ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
841 return 0;
842 }
843 prevstatus = status;
844 }
845 /* NOTREACHED */
846 return 0;
847}
848
Thiago Galesi372db8a2006-07-31 15:39:27 -0300849static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
850 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851{
852 dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
853
854 switch (cmd) {
855 case TIOCMIWAIT:
856 dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
857 return wait_modem_info(port, arg);
858
859 default:
860 dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
861 break;
862 }
863
864 return -ENOIOCTLCMD;
865}
866
Thiago Galesi372db8a2006-07-31 15:39:27 -0300867static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
869 struct usb_serial *serial = port->serial;
870 u16 state;
871 int result;
872
873 dbg("%s - port %d", __FUNCTION__, port->number);
874
875 if (break_state == 0)
876 state = BREAK_OFF;
877 else
878 state = BREAK_ON;
879 dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
880
Thiago Galesi372db8a2006-07-31 15:39:27 -0300881 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
882 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
883 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 if (result)
885 dbg("%s - error sending break = %d", __FUNCTION__, result);
886}
887
Thiago Galesi372db8a2006-07-31 15:39:27 -0300888static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889{
890 int i;
891 struct pl2303_private *priv;
892
893 dbg("%s", __FUNCTION__);
894
895 for (i = 0; i < serial->num_ports; ++i) {
896 priv = usb_get_serial_port_data(serial->port[i]);
897 if (priv) {
898 pl2303_buf_free(priv->buf);
899 kfree(priv);
900 usb_set_serial_port_data(serial->port[i], NULL);
901 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903}
904
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700905static void pl2303_update_line_status(struct usb_serial_port *port,
906 unsigned char *data,
907 unsigned int actual_length)
908{
909
910 struct pl2303_private *priv = usb_get_serial_port_data(port);
911 unsigned long flags;
912 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200913 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300914 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700915
Thiago Galesi9c537612006-07-29 10:47:12 -0300916 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
917 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
918
919
920 if (idv == SIEMENS_VENDOR_ID) {
921 if (idp == SIEMENS_PRODUCT_ID_X65 ||
922 idp == SIEMENS_PRODUCT_ID_SX1 ||
923 idp == SIEMENS_PRODUCT_ID_X75) {
924
925 length = 1;
926 status_idx = 0;
927 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700928 }
929
930 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300931 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700932
933 /* Save off the uart status for others to look at */
934 spin_lock_irqsave(&priv->lock, flags);
935 priv->line_status = data[status_idx];
936 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300937 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700938}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
David Howells7d12e782006-10-05 14:55:46 +0100940static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
942 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700944 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700945 int status = urb->status;
946 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 dbg("%s (%d)", __FUNCTION__, port->number);
949
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700950 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 case 0:
952 /* success */
953 break;
954 case -ECONNRESET:
955 case -ENOENT:
956 case -ESHUTDOWN:
957 /* this urb is terminated, clean up */
Thiago Galesi372db8a2006-07-31 15:39:27 -0300958 dbg("%s - urb shutting down with status: %d", __FUNCTION__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700959 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 return;
961 default:
Thiago Galesi372db8a2006-07-31 15:39:27 -0300962 dbg("%s - nonzero urb status received: %d", __FUNCTION__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700963 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 goto exit;
965 }
966
Thiago Galesi372db8a2006-07-31 15:39:27 -0300967 usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
968 urb->actual_length, urb->transfer_buffer);
969
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700970 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700973 retval = usb_submit_urb(urb, GFP_ATOMIC);
974 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300975 dev_err(&urb->dev->dev,
976 "%s - usb_submit_urb failed with result %d\n",
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700977 __FUNCTION__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978}
979
David Howells7d12e782006-10-05 14:55:46 +0100980static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981{
982 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
983 struct pl2303_private *priv = usb_get_serial_port_data(port);
984 struct tty_struct *tty;
985 unsigned char *data = urb->transfer_buffer;
986 unsigned long flags;
987 int i;
988 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700989 int status = urb->status;
990 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 char tty_flag;
992
993 dbg("%s - port %d", __FUNCTION__, port->number);
994
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700995 if (status) {
996 dbg("%s - urb status = %d", __FUNCTION__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 if (!port->open_count) {
998 dbg("%s - port is closed, exiting.", __FUNCTION__);
999 return;
1000 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001001 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001002 /* PL2303 mysteriously fails with -EPROTO reschedule
1003 * the read */
1004 dbg("%s - caught -EPROTO, resubmitting the urb",
1005 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 urb->dev = port->serial->dev;
1007 result = usb_submit_urb(urb, GFP_ATOMIC);
1008 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001009 dev_err(&urb->dev->dev, "%s - failed"
1010 " resubmitting read urb, error %d\n",
1011 __FUNCTION__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return;
1013 }
1014 dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
1015 return;
1016 }
1017
Thiago Galesi372db8a2006-07-31 15:39:27 -03001018 usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
1019 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
1021 /* get tty_flag from status */
1022 tty_flag = TTY_NORMAL;
1023
1024 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001025 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1027 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001028 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030 /* break takes precedence over parity, */
1031 /* which takes precedence over framing errors */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001032 if (line_status & UART_BREAK_ERROR )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001034 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001036 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 tty_flag = TTY_FRAME;
1038 dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
1039
1040 tty = port->tty;
1041 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001042 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001044 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001046 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001047 tty_insert_flip_char(tty, data[i], tty_flag);
1048 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 }
1050
1051 /* Schedule the next read _if_ we are still open */
1052 if (port->open_count) {
1053 urb->dev = port->serial->dev;
1054 result = usb_submit_urb(urb, GFP_ATOMIC);
1055 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001056 dev_err(&urb->dev->dev, "%s - failed resubmitting"
1057 " read urb, error %d\n", __FUNCTION__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
1059
1060 return;
1061}
1062
David Howells7d12e782006-10-05 14:55:46 +01001063static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
1065 struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
1066 struct pl2303_private *priv = usb_get_serial_port_data(port);
1067 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001068 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070 dbg("%s - port %d", __FUNCTION__, port->number);
1071
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001072 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 case 0:
1074 /* success */
1075 break;
1076 case -ECONNRESET:
1077 case -ENOENT:
1078 case -ESHUTDOWN:
1079 /* this urb is terminated, clean up */
Thiago Galesi372db8a2006-07-31 15:39:27 -03001080 dbg("%s - urb shutting down with status: %d", __FUNCTION__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001081 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 priv->write_urb_in_use = 0;
1083 return;
1084 default:
1085 /* error in the urb, so we have to resubmit it */
1086 dbg("%s - Overflow in write", __FUNCTION__);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001087 dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001088 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 port->write_urb->transfer_buffer_length = 1;
1090 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001091 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001093 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
1094 " urb, error %d\n", __FUNCTION__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 else
1096 return;
1097 }
1098
1099 priv->write_urb_in_use = 0;
1100
1101 /* send any buffered data */
1102 pl2303_send(port);
1103}
1104
Thiago Galesi572d3132006-07-29 10:46:37 -03001105/* All of the device info needed for the PL2303 SIO serial converter */
1106static struct usb_serial_driver pl2303_device = {
1107 .driver = {
1108 .owner = THIS_MODULE,
1109 .name = "pl2303",
1110 },
1111 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001112 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001113 .num_interrupt_in = NUM_DONT_CARE,
1114 .num_bulk_in = 1,
1115 .num_bulk_out = 1,
1116 .num_ports = 1,
1117 .open = pl2303_open,
1118 .close = pl2303_close,
1119 .write = pl2303_write,
1120 .ioctl = pl2303_ioctl,
1121 .break_ctl = pl2303_break_ctl,
1122 .set_termios = pl2303_set_termios,
1123 .tiocmget = pl2303_tiocmget,
1124 .tiocmset = pl2303_tiocmset,
1125 .read_bulk_callback = pl2303_read_bulk_callback,
1126 .read_int_callback = pl2303_read_int_callback,
1127 .write_bulk_callback = pl2303_write_bulk_callback,
1128 .write_room = pl2303_write_room,
1129 .chars_in_buffer = pl2303_chars_in_buffer,
1130 .attach = pl2303_startup,
1131 .shutdown = pl2303_shutdown,
1132};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
Thiago Galesi372db8a2006-07-31 15:39:27 -03001134static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
1136 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 retval = usb_serial_register(&pl2303_device);
1139 if (retval)
1140 goto failed_usb_serial_register;
1141 retval = usb_register(&pl2303_driver);
1142 if (retval)
1143 goto failed_usb_register;
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001144 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 return 0;
1146failed_usb_register:
1147 usb_serial_deregister(&pl2303_device);
1148failed_usb_serial_register:
1149 return retval;
1150}
1151
Thiago Galesi372db8a2006-07-31 15:39:27 -03001152static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001154 usb_deregister(&pl2303_driver);
1155 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156}
1157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158module_init(pl2303_init);
1159module_exit(pl2303_exit);
1160
1161MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162MODULE_LICENSE("GPL");
1163
1164module_param(debug, bool, S_IRUGO | S_IWUSR);
1165MODULE_PARM_DESC(debug, "Debug enabled or not");
1166