blob: 234c5eea95a2c6c48f76332d0779c5c5a3009e7a [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) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070058 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090060 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
62 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
63 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
64 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
65 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080066 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
68 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
69 { 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,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800102 .suspend = usb_serial_suspend,
103 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800104 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800105 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106};
107
108#define SET_LINE_REQUEST_TYPE 0x21
109#define SET_LINE_REQUEST 0x20
110
111#define SET_CONTROL_REQUEST_TYPE 0x21
112#define SET_CONTROL_REQUEST 0x22
113#define CONTROL_DTR 0x01
114#define CONTROL_RTS 0x02
115
116#define BREAK_REQUEST_TYPE 0x21
117#define BREAK_REQUEST 0x23
118#define BREAK_ON 0xffff
119#define BREAK_OFF 0x0000
120
121#define GET_LINE_REQUEST_TYPE 0xa1
122#define GET_LINE_REQUEST 0x21
123
124#define VENDOR_WRITE_REQUEST_TYPE 0x40
125#define VENDOR_WRITE_REQUEST 0x01
126
127#define VENDOR_READ_REQUEST_TYPE 0xc0
128#define VENDOR_READ_REQUEST 0x01
129
130#define UART_STATE 0x08
131#define UART_STATE_TRANSIENT_MASK 0x74
132#define UART_DCD 0x01
133#define UART_DSR 0x02
134#define UART_BREAK_ERROR 0x04
135#define UART_RING 0x08
136#define UART_FRAME_ERROR 0x10
137#define UART_PARITY_ERROR 0x20
138#define UART_OVERRUN_ERROR 0x40
139#define UART_CTS 0x80
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142enum pl2303_type {
143 type_0, /* don't know the difference between type 0 and */
144 type_1, /* type 1, until someone from prolific tells us... */
145 HX, /* HX version of the pl2303 chip */
146};
147
148struct pl2303_private {
149 spinlock_t lock;
150 struct pl2303_buf *buf;
151 int write_urb_in_use;
152 wait_queue_head_t delta_msr_wait;
153 u8 line_control;
154 u8 line_status;
155 u8 termios_initialized;
156 enum pl2303_type type;
157};
158
Thiago Galesi572d3132006-07-29 10:46:37 -0300159/*
160 * pl2303_buf_alloc
161 *
162 * Allocate a circular buffer and all associated memory.
163 */
164static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
165{
166 struct pl2303_buf *pb;
167
168 if (size == 0)
169 return NULL;
170
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800171 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300172 if (pb == NULL)
173 return NULL;
174
175 pb->buf_buf = kmalloc(size, GFP_KERNEL);
176 if (pb->buf_buf == NULL) {
177 kfree(pb);
178 return NULL;
179 }
180
181 pb->buf_size = size;
182 pb->buf_get = pb->buf_put = pb->buf_buf;
183
184 return pb;
185}
186
187/*
188 * pl2303_buf_free
189 *
190 * Free the buffer and all associated memory.
191 */
192static void pl2303_buf_free(struct pl2303_buf *pb)
193{
194 if (pb) {
195 kfree(pb->buf_buf);
196 kfree(pb);
197 }
198}
199
200/*
201 * pl2303_buf_clear
202 *
203 * Clear out all data in the circular buffer.
204 */
205static void pl2303_buf_clear(struct pl2303_buf *pb)
206{
207 if (pb != NULL)
208 pb->buf_get = pb->buf_put;
209 /* equivalent to a get of all data available */
210}
211
212/*
213 * pl2303_buf_data_avail
214 *
215 * Return the number of bytes of data available in the circular
216 * buffer.
217 */
218static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
219{
220 if (pb == NULL)
221 return 0;
222
223 return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
224}
225
226/*
227 * pl2303_buf_space_avail
228 *
229 * Return the number of bytes of space available in the circular
230 * buffer.
231 */
232static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
233{
234 if (pb == NULL)
235 return 0;
236
237 return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
238}
239
240/*
241 * pl2303_buf_put
242 *
243 * Copy data data from a user buffer and put it into the circular buffer.
244 * Restrict to the amount of space available.
245 *
246 * Return the number of bytes copied.
247 */
248static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
249 unsigned int count)
250{
251 unsigned int len;
252
253 if (pb == NULL)
254 return 0;
255
256 len = pl2303_buf_space_avail(pb);
257 if (count > len)
258 count = len;
259
260 if (count == 0)
261 return 0;
262
263 len = pb->buf_buf + pb->buf_size - pb->buf_put;
264 if (count > len) {
265 memcpy(pb->buf_put, buf, len);
266 memcpy(pb->buf_buf, buf+len, count - len);
267 pb->buf_put = pb->buf_buf + count - len;
268 } else {
269 memcpy(pb->buf_put, buf, count);
270 if (count < len)
271 pb->buf_put += count;
272 else /* count == len */
273 pb->buf_put = pb->buf_buf;
274 }
275
276 return count;
277}
278
279/*
280 * pl2303_buf_get
281 *
282 * Get data from the circular buffer and copy to the given buffer.
283 * Restrict to the amount of data available.
284 *
285 * Return the number of bytes copied.
286 */
287static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
288 unsigned int count)
289{
290 unsigned int len;
291
292 if (pb == NULL)
293 return 0;
294
295 len = pl2303_buf_data_avail(pb);
296 if (count > len)
297 count = len;
298
299 if (count == 0)
300 return 0;
301
302 len = pb->buf_buf + pb->buf_size - pb->buf_get;
303 if (count > len) {
304 memcpy(buf, pb->buf_get, len);
305 memcpy(buf+len, pb->buf_buf, count - len);
306 pb->buf_get = pb->buf_buf + count - len;
307 } else {
308 memcpy(buf, pb->buf_get, count);
309 if (count < len)
310 pb->buf_get += count;
311 else /* count == len */
312 pb->buf_get = pb->buf_buf;
313 }
314
315 return count;
316}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Sarah Sharpeb44da02007-12-14 14:08:00 -0800318static int pl2303_vendor_read(__u16 value, __u16 index,
319 struct usb_serial *serial, unsigned char *buf)
320{
321 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
322 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
323 value, index, buf, 1, 100);
324 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
325 VENDOR_READ_REQUEST, value, index, res, buf[0]);
326 return res;
327}
328
329static int pl2303_vendor_write(__u16 value, __u16 index,
330 struct usb_serial *serial)
331{
332 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
333 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
334 value, index, NULL, 0, 100);
335 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
336 VENDOR_WRITE_REQUEST, value, index, res);
337 return res;
338}
339
Thiago Galesi372db8a2006-07-31 15:39:27 -0300340static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 struct pl2303_private *priv;
343 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800344 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 int i;
346
Sarah Sharp3e152502007-12-14 14:08:35 -0800347 buf = kmalloc(10, GFP_KERNEL);
348 if (buf == NULL)
349 return -ENOMEM;
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if (serial->dev->descriptor.bDeviceClass == 0x02)
352 type = type_0;
353 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
354 type = HX;
355 else if (serial->dev->descriptor.bDeviceClass == 0x00)
356 type = type_1;
357 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
358 type = type_1;
359 dbg("device type: %d", type);
360
361 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100362 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 if (!priv)
364 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 spin_lock_init(&priv->lock);
366 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
367 if (priv->buf == NULL) {
368 kfree(priv);
369 goto cleanup;
370 }
371 init_waitqueue_head(&priv->delta_msr_wait);
372 priv->type = type;
373 usb_set_serial_port_data(serial->port[i], priv);
374 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800375
376 pl2303_vendor_read(0x8484, 0, serial, buf);
377 pl2303_vendor_write(0x0404, 0, serial);
378 pl2303_vendor_read(0x8484, 0, serial, buf);
379 pl2303_vendor_read(0x8383, 0, serial, buf);
380 pl2303_vendor_read(0x8484, 0, serial, buf);
381 pl2303_vendor_write(0x0404, 1, serial);
382 pl2303_vendor_read(0x8484, 0, serial, buf);
383 pl2303_vendor_read(0x8383, 0, serial, buf);
384 pl2303_vendor_write(0, 1, serial);
385 pl2303_vendor_write(1, 0, serial);
386 if (type == HX)
387 pl2303_vendor_write(2, 0x44, serial);
388 else
389 pl2303_vendor_write(2, 0x24, serial);
390
391 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 return 0;
393
394cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800395 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 for (--i; i>=0; --i) {
397 priv = usb_get_serial_port_data(serial->port[i]);
398 pl2303_buf_free(priv->buf);
399 kfree(priv);
400 usb_set_serial_port_data(serial->port[i], NULL);
401 }
402 return -ENOMEM;
403}
404
Thiago Galesi372db8a2006-07-31 15:39:27 -0300405static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
407 int retval;
408
Thiago Galesi372db8a2006-07-31 15:39:27 -0300409 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
410 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
411 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800412 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 return retval;
414}
415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416static void pl2303_send(struct usb_serial_port *port)
417{
418 int count, result;
419 struct pl2303_private *priv = usb_get_serial_port_data(port);
420 unsigned long flags;
421
Harvey Harrison441b62c2008-03-03 16:08:34 -0800422 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 spin_lock_irqsave(&priv->lock, flags);
425
426 if (priv->write_urb_in_use) {
427 spin_unlock_irqrestore(&priv->lock, flags);
428 return;
429 }
430
431 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300432 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
434 if (count == 0) {
435 spin_unlock_irqrestore(&priv->lock, flags);
436 return;
437 }
438
439 priv->write_urb_in_use = 1;
440
441 spin_unlock_irqrestore(&priv->lock, flags);
442
Harvey Harrison441b62c2008-03-03 16:08:34 -0800443 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300444 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446 port->write_urb->transfer_buffer_length = count;
447 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300448 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300450 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800451 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 priv->write_urb_in_use = 0;
453 // TODO: reschedule pl2303_send
454 }
455
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700456 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
Thiago Galesi572d3132006-07-29 10:46:37 -0300459static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
460 int count)
461{
462 struct pl2303_private *priv = usb_get_serial_port_data(port);
463 unsigned long flags;
464
Harvey Harrison441b62c2008-03-03 16:08:34 -0800465 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300466
467 if (!count)
468 return count;
469
470 spin_lock_irqsave(&priv->lock, flags);
471 count = pl2303_buf_put(priv->buf, buf, count);
472 spin_unlock_irqrestore(&priv->lock, flags);
473
474 pl2303_send(port);
475
476 return count;
477}
478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479static int pl2303_write_room(struct usb_serial_port *port)
480{
481 struct pl2303_private *priv = usb_get_serial_port_data(port);
482 int room = 0;
483 unsigned long flags;
484
Harvey Harrison441b62c2008-03-03 16:08:34 -0800485 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487 spin_lock_irqsave(&priv->lock, flags);
488 room = pl2303_buf_space_avail(priv->buf);
489 spin_unlock_irqrestore(&priv->lock, flags);
490
Harvey Harrison441b62c2008-03-03 16:08:34 -0800491 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 return room;
493}
494
495static int pl2303_chars_in_buffer(struct usb_serial_port *port)
496{
497 struct pl2303_private *priv = usb_get_serial_port_data(port);
498 int chars = 0;
499 unsigned long flags;
500
Harvey Harrison441b62c2008-03-03 16:08:34 -0800501 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 spin_lock_irqsave(&priv->lock, flags);
504 chars = pl2303_buf_data_avail(priv->buf);
505 spin_unlock_irqrestore(&priv->lock, flags);
506
Harvey Harrison441b62c2008-03-03 16:08:34 -0800507 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 return chars;
509}
510
Thiago Galesi372db8a2006-07-31 15:39:27 -0300511static void pl2303_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800512 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 struct usb_serial *serial = port->serial;
515 struct pl2303_private *priv = usb_get_serial_port_data(port);
516 unsigned long flags;
517 unsigned int cflag;
518 unsigned char *buf;
519 int baud;
520 int i;
521 u8 control;
522
Harvey Harrison441b62c2008-03-03 16:08:34 -0800523 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 spin_lock_irqsave(&priv->lock, flags);
526 if (!priv->termios_initialized) {
527 *(port->tty->termios) = tty_std_termios;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300528 port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
529 HUPCL | CLOCAL;
Alan Coxdf64c472007-10-15 20:54:47 +0100530 port->tty->termios->c_ispeed = 9600;
531 port->tty->termios->c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 priv->termios_initialized = 1;
533 }
534 spin_unlock_irqrestore(&priv->lock, flags);
535
Alan Coxbf5e5832008-01-08 14:55:51 +0000536 /* The PL2303 is reported to lose bytes if you change
537 serial settings even to the same values as before. Thus
538 we actually need to filter in this specific case */
539
540 if (!tty_termios_hw_change(port->tty->termios, old_termios))
541 return;
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 cflag = port->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Thiago Galesi372db8a2006-07-31 15:39:27 -0300545 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800547 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100548 /* Report back no change occurred */
549 *port->tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 return;
551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Thiago Galesi372db8a2006-07-31 15:39:27 -0300553 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
554 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
555 0, 0, buf, 7, 100);
556 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
557 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
559 if (cflag & CSIZE) {
560 switch (cflag & CSIZE) {
561 case CS5: buf[6] = 5; break;
562 case CS6: buf[6] = 6; break;
563 case CS7: buf[6] = 7; break;
564 default:
565 case CS8: buf[6] = 8; break;
566 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800567 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 }
569
Alan Coxe0c79f52007-07-09 12:03:10 -0700570 baud = tty_get_baud_rate(port->tty);;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800571 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 if (baud) {
573 buf[0] = baud & 0xff;
574 buf[1] = (baud >> 8) & 0xff;
575 buf[2] = (baud >> 16) & 0xff;
576 buf[3] = (baud >> 24) & 0xff;
577 }
578
579 /* For reference buf[4]=0 is 1 stop bits */
580 /* For reference buf[4]=1 is 1.5 stop bits */
581 /* For reference buf[4]=2 is 2 stop bits */
582 if (cflag & CSTOPB) {
583 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800584 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 } else {
586 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800587 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 }
589
590 if (cflag & PARENB) {
591 /* For reference buf[5]=0 is none parity */
592 /* For reference buf[5]=1 is odd parity */
593 /* For reference buf[5]=2 is even parity */
594 /* For reference buf[5]=3 is mark parity */
595 /* For reference buf[5]=4 is space parity */
596 if (cflag & PARODD) {
597 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800598 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 } else {
600 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800601 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 }
603 } else {
604 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800605 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 }
607
Thiago Galesi372db8a2006-07-31 15:39:27 -0300608 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
609 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
610 0, 0, buf, 7, 100);
611 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 /* change control lines if we are switching to or from B0 */
614 spin_lock_irqsave(&priv->lock, flags);
615 control = priv->line_control;
616 if ((cflag & CBAUD) == B0)
617 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
618 else
619 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
620 if (control != priv->line_control) {
621 control = priv->line_control;
622 spin_unlock_irqrestore(&priv->lock, flags);
623 set_control_lines(serial->dev, control);
624 } else {
625 spin_unlock_irqrestore(&priv->lock, flags);
626 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
629
Thiago Galesi372db8a2006-07-31 15:39:27 -0300630 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
631 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
632 0, 0, buf, 7, 100);
633 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
635
636 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800638 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800640 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200641 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800642 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644
Alan Coxdf64c472007-10-15 20:54:47 +0100645 /* FIXME: Need to read back resulting baud rate */
646 if (baud)
647 tty_encode_baud_rate(port->tty, baud, baud);
648
Thiago Galesi372db8a2006-07-31 15:39:27 -0300649 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651
Thiago Galesi572d3132006-07-29 10:46:37 -0300652static void pl2303_close(struct usb_serial_port *port, struct file *filp)
653{
654 struct pl2303_private *priv = usb_get_serial_port_data(port);
655 unsigned long flags;
656 unsigned int c_cflag;
657 int bps;
658 long timeout;
659 wait_queue_t wait;
660
Harvey Harrison441b62c2008-03-03 16:08:34 -0800661 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300662
663 /* wait for data to drain from the buffer */
664 spin_lock_irqsave(&priv->lock, flags);
665 timeout = PL2303_CLOSING_WAIT;
666 init_waitqueue_entry(&wait, current);
667 add_wait_queue(&port->tty->write_wait, &wait);
668 for (;;) {
669 set_current_state(TASK_INTERRUPTIBLE);
670 if (pl2303_buf_data_avail(priv->buf) == 0 ||
671 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100672 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300673 break;
674 spin_unlock_irqrestore(&priv->lock, flags);
675 timeout = schedule_timeout(timeout);
676 spin_lock_irqsave(&priv->lock, flags);
677 }
678 set_current_state(TASK_RUNNING);
679 remove_wait_queue(&port->tty->write_wait, &wait);
680 /* clear out any remaining data in the buffer */
681 pl2303_buf_clear(priv->buf);
682 spin_unlock_irqrestore(&priv->lock, flags);
683
684 /* wait for characters to drain from the device */
685 /* (this is long enough for the entire 256 byte */
686 /* pl2303 hardware buffer to drain with no flow */
687 /* control for data rates of 1200 bps or more, */
688 /* for lower rates we should really know how much */
689 /* data is in the buffer to compute a delay */
690 /* that is not unnecessarily long) */
691 bps = tty_get_baud_rate(port->tty);
692 if (bps > 1200)
693 timeout = max((HZ*2560)/bps,HZ/10);
694 else
695 timeout = 2*HZ;
696 schedule_timeout_interruptible(timeout);
697
698 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800699 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300700 usb_kill_urb(port->write_urb);
701 usb_kill_urb(port->read_urb);
702 usb_kill_urb(port->interrupt_in_urb);
703
704 if (port->tty) {
705 c_cflag = port->tty->termios->c_cflag;
706 if (c_cflag & HUPCL) {
707 /* drop DTR and RTS */
708 spin_lock_irqsave(&priv->lock, flags);
709 priv->line_control = 0;
710 spin_unlock_irqrestore(&priv->lock, flags);
711 set_control_lines(port->serial->dev, 0);
712 }
713 }
714}
715
Thiago Galesi372db8a2006-07-31 15:39:27 -0300716static int pl2303_open(struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
Alan Cox606d0992006-12-08 02:38:45 -0800718 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 struct usb_serial *serial = port->serial;
720 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 int result;
722
Harvey Harrison441b62c2008-03-03 16:08:34 -0800723 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Dariusz M16948992005-07-28 18:06:13 +0200725 if (priv->type != HX) {
726 usb_clear_halt(serial->dev, port->write_urb->pipe);
727 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800728 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800730 pl2303_vendor_write(8, 0, serial);
731 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 }
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /* Setup termios */
735 if (port->tty) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300736 pl2303_set_termios(port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 }
738
739 //FIXME: need to assert RTS and DTR if CRTSCTS off
740
Harvey Harrison441b62c2008-03-03 16:08:34 -0800741 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300743 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300745 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800746 " error %d\n", __func__, result);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300747 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return -EPROTO;
749 }
750
Harvey Harrison441b62c2008-03-03 16:08:34 -0800751 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300753 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300755 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800756 " error %d\n", __func__, result);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300757 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return -EPROTO;
759 }
760 return 0;
761}
762
Thiago Galesi372db8a2006-07-31 15:39:27 -0300763static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
764 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
766 struct pl2303_private *priv = usb_get_serial_port_data(port);
767 unsigned long flags;
768 u8 control;
769
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700770 if (!usb_get_intfdata(port->serial->interface))
771 return -ENODEV;
772
Thiago Galesi372db8a2006-07-31 15:39:27 -0300773 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 if (set & TIOCM_RTS)
775 priv->line_control |= CONTROL_RTS;
776 if (set & TIOCM_DTR)
777 priv->line_control |= CONTROL_DTR;
778 if (clear & TIOCM_RTS)
779 priv->line_control &= ~CONTROL_RTS;
780 if (clear & TIOCM_DTR)
781 priv->line_control &= ~CONTROL_DTR;
782 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300783 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Thiago Galesi372db8a2006-07-31 15:39:27 -0300785 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786}
787
Thiago Galesi372db8a2006-07-31 15:39:27 -0300788static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
790 struct pl2303_private *priv = usb_get_serial_port_data(port);
791 unsigned long flags;
792 unsigned int mcr;
793 unsigned int status;
794 unsigned int result;
795
Harvey Harrison441b62c2008-03-03 16:08:34 -0800796 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700798 if (!usb_get_intfdata(port->serial->interface))
799 return -ENODEV;
800
Thiago Galesi372db8a2006-07-31 15:39:27 -0300801 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 mcr = priv->line_control;
803 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300804 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
806 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
807 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
808 | ((status & UART_CTS) ? TIOCM_CTS : 0)
809 | ((status & UART_DSR) ? TIOCM_DSR : 0)
810 | ((status & UART_RING) ? TIOCM_RI : 0)
811 | ((status & UART_DCD) ? TIOCM_CD : 0);
812
Harvey Harrison441b62c2008-03-03 16:08:34 -0800813 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
815 return result;
816}
817
818static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
819{
820 struct pl2303_private *priv = usb_get_serial_port_data(port);
821 unsigned long flags;
822 unsigned int prevstatus;
823 unsigned int status;
824 unsigned int changed;
825
Thiago Galesi372db8a2006-07-31 15:39:27 -0300826 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300828 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 while (1) {
831 interruptible_sleep_on(&priv->delta_msr_wait);
832 /* see if a signal did it */
833 if (signal_pending(current))
834 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300835
836 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300838 spin_unlock_irqrestore(&priv->lock, flags);
839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 changed=prevstatus^status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
843 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
844 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
845 ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
846 return 0;
847 }
848 prevstatus = status;
849 }
850 /* NOTREACHED */
851 return 0;
852}
853
Thiago Galesi372db8a2006-07-31 15:39:27 -0300854static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
855 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856{
Harvey Harrison441b62c2008-03-03 16:08:34 -0800857 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
859 switch (cmd) {
860 case TIOCMIWAIT:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800861 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 return wait_modem_info(port, arg);
863
864 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800865 dbg("%s not supported = 0x%04x", __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 break;
867 }
868
869 return -ENOIOCTLCMD;
870}
871
Thiago Galesi372db8a2006-07-31 15:39:27 -0300872static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
874 struct usb_serial *serial = port->serial;
875 u16 state;
876 int result;
877
Harvey Harrison441b62c2008-03-03 16:08:34 -0800878 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880 if (break_state == 0)
881 state = BREAK_OFF;
882 else
883 state = BREAK_ON;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800884 dbg("%s - turning break %s", __func__, state==BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
Thiago Galesi372db8a2006-07-31 15:39:27 -0300886 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
887 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
888 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800890 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891}
892
Thiago Galesi372db8a2006-07-31 15:39:27 -0300893static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
895 int i;
896 struct pl2303_private *priv;
897
Harvey Harrison441b62c2008-03-03 16:08:34 -0800898 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 for (i = 0; i < serial->num_ports; ++i) {
901 priv = usb_get_serial_port_data(serial->port[i]);
902 if (priv) {
903 pl2303_buf_free(priv->buf);
904 kfree(priv);
905 usb_set_serial_port_data(serial->port[i], NULL);
906 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300907 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908}
909
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700910static void pl2303_update_line_status(struct usb_serial_port *port,
911 unsigned char *data,
912 unsigned int actual_length)
913{
914
915 struct pl2303_private *priv = usb_get_serial_port_data(port);
916 unsigned long flags;
917 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200918 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300919 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700920
Thiago Galesi9c537612006-07-29 10:47:12 -0300921 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
922 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
923
924
925 if (idv == SIEMENS_VENDOR_ID) {
926 if (idp == SIEMENS_PRODUCT_ID_X65 ||
927 idp == SIEMENS_PRODUCT_ID_SX1 ||
928 idp == SIEMENS_PRODUCT_ID_X75) {
929
930 length = 1;
931 status_idx = 0;
932 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700933 }
934
935 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300936 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700937
938 /* Save off the uart status for others to look at */
939 spin_lock_irqsave(&priv->lock, flags);
940 priv->line_status = data[status_idx];
941 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300942 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700943}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
David Howells7d12e782006-10-05 14:55:46 +0100945static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
Ming Leicdc97792008-02-24 18:41:47 +0800947 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700949 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700950 int status = urb->status;
951 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Harvey Harrison441b62c2008-03-03 16:08:34 -0800953 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700955 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 case 0:
957 /* success */
958 break;
959 case -ECONNRESET:
960 case -ENOENT:
961 case -ESHUTDOWN:
962 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800963 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700964 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 return;
966 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800967 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700968 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 goto exit;
970 }
971
Harvey Harrison441b62c2008-03-03 16:08:34 -0800972 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300973 urb->actual_length, urb->transfer_buffer);
974
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700975 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700978 retval = usb_submit_urb(urb, GFP_ATOMIC);
979 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300980 dev_err(&urb->dev->dev,
981 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800982 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
984
David Howells7d12e782006-10-05 14:55:46 +0100985static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
Ming Leicdc97792008-02-24 18:41:47 +0800987 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 struct pl2303_private *priv = usb_get_serial_port_data(port);
989 struct tty_struct *tty;
990 unsigned char *data = urb->transfer_buffer;
991 unsigned long flags;
992 int i;
993 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700994 int status = urb->status;
995 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 char tty_flag;
997
Harvey Harrison441b62c2008-03-03 16:08:34 -0800998 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001000 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001001 dbg("%s - urb status = %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (!port->open_count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001003 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 return;
1005 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001006 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001007 /* PL2303 mysteriously fails with -EPROTO reschedule
1008 * the read */
1009 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001010 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 urb->dev = port->serial->dev;
1012 result = usb_submit_urb(urb, GFP_ATOMIC);
1013 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001014 dev_err(&urb->dev->dev, "%s - failed"
1015 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001016 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 return;
1018 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001019 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return;
1021 }
1022
Harvey Harrison441b62c2008-03-03 16:08:34 -08001023 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001024 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 /* get tty_flag from status */
1027 tty_flag = TTY_NORMAL;
1028
1029 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001030 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1032 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001033 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
1035 /* break takes precedence over parity, */
1036 /* which takes precedence over framing errors */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001037 if (line_status & UART_BREAK_ERROR )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001039 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001041 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001043 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 tty = port->tty;
1046 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001047 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001049 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001051 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001052 tty_insert_flip_char(tty, data[i], tty_flag);
1053 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
1055
1056 /* Schedule the next read _if_ we are still open */
1057 if (port->open_count) {
1058 urb->dev = port->serial->dev;
1059 result = usb_submit_urb(urb, GFP_ATOMIC);
1060 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001061 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001062 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
1064
1065 return;
1066}
1067
David Howells7d12e782006-10-05 14:55:46 +01001068static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
Ming Leicdc97792008-02-24 18:41:47 +08001070 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 struct pl2303_private *priv = usb_get_serial_port_data(port);
1072 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001073 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Harvey Harrison441b62c2008-03-03 16:08:34 -08001075 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001077 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 case 0:
1079 /* success */
1080 break;
1081 case -ECONNRESET:
1082 case -ENOENT:
1083 case -ESHUTDOWN:
1084 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001085 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001086 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 priv->write_urb_in_use = 0;
1088 return;
1089 default:
1090 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001091 dbg("%s - Overflow in write", __func__);
1092 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001093 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 port->write_urb->transfer_buffer_length = 1;
1095 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001096 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001098 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001099 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 else
1101 return;
1102 }
1103
1104 priv->write_urb_in_use = 0;
1105
1106 /* send any buffered data */
1107 pl2303_send(port);
1108}
1109
Thiago Galesi572d3132006-07-29 10:46:37 -03001110/* All of the device info needed for the PL2303 SIO serial converter */
1111static struct usb_serial_driver pl2303_device = {
1112 .driver = {
1113 .owner = THIS_MODULE,
1114 .name = "pl2303",
1115 },
1116 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001117 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001118 .num_ports = 1,
1119 .open = pl2303_open,
1120 .close = pl2303_close,
1121 .write = pl2303_write,
1122 .ioctl = pl2303_ioctl,
1123 .break_ctl = pl2303_break_ctl,
1124 .set_termios = pl2303_set_termios,
1125 .tiocmget = pl2303_tiocmget,
1126 .tiocmset = pl2303_tiocmset,
1127 .read_bulk_callback = pl2303_read_bulk_callback,
1128 .read_int_callback = pl2303_read_int_callback,
1129 .write_bulk_callback = pl2303_write_bulk_callback,
1130 .write_room = pl2303_write_room,
1131 .chars_in_buffer = pl2303_chars_in_buffer,
1132 .attach = pl2303_startup,
1133 .shutdown = pl2303_shutdown,
1134};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Thiago Galesi372db8a2006-07-31 15:39:27 -03001136static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137{
1138 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 retval = usb_serial_register(&pl2303_device);
1141 if (retval)
1142 goto failed_usb_serial_register;
1143 retval = usb_register(&pl2303_driver);
1144 if (retval)
1145 goto failed_usb_register;
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001146 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 return 0;
1148failed_usb_register:
1149 usb_serial_deregister(&pl2303_device);
1150failed_usb_serial_register:
1151 return retval;
1152}
1153
Thiago Galesi372db8a2006-07-31 15:39:27 -03001154static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001156 usb_deregister(&pl2303_driver);
1157 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158}
1159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160module_init(pl2303_init);
1161module_exit(pl2303_exit);
1162
1163MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164MODULE_LICENSE("GPL");
1165
1166module_param(debug, bool, S_IRUGO | S_IWUSR);
1167MODULE_PARM_DESC(debug, "Debug enabled or not");
1168