blob: 751a533a4347e7324725afb8948b75fcb2437bbd [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 *
Alan Cox3a0f43e2008-07-22 11:14:49 +010013 * See Documentation/usb/usb-serial.txt for more information on using this
14 * driver
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/kernel.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22#include <linux/tty.h>
23#include <linux/tty_driver.h>
24#include <linux/tty_flip.h>
25#include <linux/serial.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/spinlock.h>
Alan Cox3a0f43e2008-07-22 11:14:49 +010029#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070031#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "pl2303.h"
33
34/*
35 * Version Information
36 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
38
39static int debug;
40
41#define PL2303_CLOSING_WAIT (30*HZ)
42
43#define PL2303_BUF_SIZE 1024
44#define PL2303_TMP_BUF_SIZE 1024
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046struct pl2303_buf {
47 unsigned int buf_size;
48 char *buf_buf;
49 char *buf_get;
50 char *buf_put;
51};
52
53static struct usb_device_id id_table [] = {
54 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
55 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100056 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
58 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070059 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053060 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050061 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090063 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
65 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
66 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
67 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
68 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080069 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
71 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
72 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
73 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
74 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
75 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
76 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
77 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080078 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080080 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020081 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Alan Cox912299f2009-04-06 17:35:12 +010082 { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070083 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010084 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
85 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010086 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010087 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080088 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040089 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100090 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020091 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090092 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090093 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050094 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Matthew Arnold7c992002008-12-13 22:42:53 +110095 { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
Mike Provencheraf4b8512008-12-16 14:30:14 -060096 { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 { } /* Terminating entry */
98};
99
Thiago Galesi372db8a2006-07-31 15:39:27 -0300100MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 .name = "pl2303",
104 .probe = usb_serial_probe,
105 .disconnect = usb_serial_disconnect,
106 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800107 .suspend = usb_serial_suspend,
108 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800109 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800110 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
113#define SET_LINE_REQUEST_TYPE 0x21
114#define SET_LINE_REQUEST 0x20
115
116#define SET_CONTROL_REQUEST_TYPE 0x21
117#define SET_CONTROL_REQUEST 0x22
118#define CONTROL_DTR 0x01
119#define CONTROL_RTS 0x02
120
121#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100122#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define BREAK_ON 0xffff
124#define BREAK_OFF 0x0000
125
126#define GET_LINE_REQUEST_TYPE 0xa1
127#define GET_LINE_REQUEST 0x21
128
129#define VENDOR_WRITE_REQUEST_TYPE 0x40
130#define VENDOR_WRITE_REQUEST 0x01
131
132#define VENDOR_READ_REQUEST_TYPE 0xc0
133#define VENDOR_READ_REQUEST 0x01
134
135#define UART_STATE 0x08
136#define UART_STATE_TRANSIENT_MASK 0x74
137#define UART_DCD 0x01
138#define UART_DSR 0x02
139#define UART_BREAK_ERROR 0x04
140#define UART_RING 0x08
141#define UART_FRAME_ERROR 0x10
142#define UART_PARITY_ERROR 0x20
143#define UART_OVERRUN_ERROR 0x40
144#define UART_CTS 0x80
145
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
147enum pl2303_type {
148 type_0, /* don't know the difference between type 0 and */
149 type_1, /* type 1, until someone from prolific tells us... */
150 HX, /* HX version of the pl2303 chip */
151};
152
153struct pl2303_private {
154 spinlock_t lock;
155 struct pl2303_buf *buf;
156 int write_urb_in_use;
157 wait_queue_head_t delta_msr_wait;
158 u8 line_control;
159 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 enum pl2303_type type;
161};
162
Thiago Galesi572d3132006-07-29 10:46:37 -0300163/*
164 * pl2303_buf_alloc
165 *
166 * Allocate a circular buffer and all associated memory.
167 */
168static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
169{
170 struct pl2303_buf *pb;
171
172 if (size == 0)
173 return NULL;
174
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800175 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300176 if (pb == NULL)
177 return NULL;
178
179 pb->buf_buf = kmalloc(size, GFP_KERNEL);
180 if (pb->buf_buf == NULL) {
181 kfree(pb);
182 return NULL;
183 }
184
185 pb->buf_size = size;
186 pb->buf_get = pb->buf_put = pb->buf_buf;
187
188 return pb;
189}
190
191/*
192 * pl2303_buf_free
193 *
194 * Free the buffer and all associated memory.
195 */
196static void pl2303_buf_free(struct pl2303_buf *pb)
197{
198 if (pb) {
199 kfree(pb->buf_buf);
200 kfree(pb);
201 }
202}
203
204/*
205 * pl2303_buf_clear
206 *
207 * Clear out all data in the circular buffer.
208 */
209static void pl2303_buf_clear(struct pl2303_buf *pb)
210{
211 if (pb != NULL)
212 pb->buf_get = pb->buf_put;
213 /* equivalent to a get of all data available */
214}
215
216/*
217 * pl2303_buf_data_avail
218 *
219 * Return the number of bytes of data available in the circular
220 * buffer.
221 */
222static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
223{
224 if (pb == NULL)
225 return 0;
226
Alan Cox3a0f43e2008-07-22 11:14:49 +0100227 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300228}
229
230/*
231 * pl2303_buf_space_avail
232 *
233 * Return the number of bytes of space available in the circular
234 * buffer.
235 */
236static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
237{
238 if (pb == NULL)
239 return 0;
240
Alan Cox3a0f43e2008-07-22 11:14:49 +0100241 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300242}
243
244/*
245 * pl2303_buf_put
246 *
247 * Copy data data from a user buffer and put it into the circular buffer.
248 * Restrict to the amount of space available.
249 *
250 * Return the number of bytes copied.
251 */
252static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
253 unsigned int count)
254{
255 unsigned int len;
256
257 if (pb == NULL)
258 return 0;
259
260 len = pl2303_buf_space_avail(pb);
261 if (count > len)
262 count = len;
263
264 if (count == 0)
265 return 0;
266
267 len = pb->buf_buf + pb->buf_size - pb->buf_put;
268 if (count > len) {
269 memcpy(pb->buf_put, buf, len);
270 memcpy(pb->buf_buf, buf+len, count - len);
271 pb->buf_put = pb->buf_buf + count - len;
272 } else {
273 memcpy(pb->buf_put, buf, count);
274 if (count < len)
275 pb->buf_put += count;
276 else /* count == len */
277 pb->buf_put = pb->buf_buf;
278 }
279
280 return count;
281}
282
283/*
284 * pl2303_buf_get
285 *
286 * Get data from the circular buffer and copy to the given buffer.
287 * Restrict to the amount of data available.
288 *
289 * Return the number of bytes copied.
290 */
291static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
292 unsigned int count)
293{
294 unsigned int len;
295
296 if (pb == NULL)
297 return 0;
298
299 len = pl2303_buf_data_avail(pb);
300 if (count > len)
301 count = len;
302
303 if (count == 0)
304 return 0;
305
306 len = pb->buf_buf + pb->buf_size - pb->buf_get;
307 if (count > len) {
308 memcpy(buf, pb->buf_get, len);
309 memcpy(buf+len, pb->buf_buf, count - len);
310 pb->buf_get = pb->buf_buf + count - len;
311 } else {
312 memcpy(buf, pb->buf_get, count);
313 if (count < len)
314 pb->buf_get += count;
315 else /* count == len */
316 pb->buf_get = pb->buf_buf;
317 }
318
319 return count;
320}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Sarah Sharpeb44da02007-12-14 14:08:00 -0800322static int pl2303_vendor_read(__u16 value, __u16 index,
323 struct usb_serial *serial, unsigned char *buf)
324{
325 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
326 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
327 value, index, buf, 1, 100);
328 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
329 VENDOR_READ_REQUEST, value, index, res, buf[0]);
330 return res;
331}
332
333static int pl2303_vendor_write(__u16 value, __u16 index,
334 struct usb_serial *serial)
335{
336 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
337 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
338 value, index, NULL, 0, 100);
339 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
340 VENDOR_WRITE_REQUEST, value, index, res);
341 return res;
342}
343
Thiago Galesi372db8a2006-07-31 15:39:27 -0300344static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 struct pl2303_private *priv;
347 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800348 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 int i;
350
Sarah Sharp3e152502007-12-14 14:08:35 -0800351 buf = kmalloc(10, GFP_KERNEL);
352 if (buf == NULL)
353 return -ENOMEM;
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 if (serial->dev->descriptor.bDeviceClass == 0x02)
356 type = type_0;
357 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
358 type = HX;
359 else if (serial->dev->descriptor.bDeviceClass == 0x00)
360 type = type_1;
361 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
362 type = type_1;
363 dbg("device type: %d", type);
364
365 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100366 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 if (!priv)
368 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 spin_lock_init(&priv->lock);
370 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
371 if (priv->buf == NULL) {
372 kfree(priv);
373 goto cleanup;
374 }
375 init_waitqueue_head(&priv->delta_msr_wait);
376 priv->type = type;
377 usb_set_serial_port_data(serial->port[i], priv);
378 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800379
380 pl2303_vendor_read(0x8484, 0, serial, buf);
381 pl2303_vendor_write(0x0404, 0, serial);
382 pl2303_vendor_read(0x8484, 0, serial, buf);
383 pl2303_vendor_read(0x8383, 0, serial, buf);
384 pl2303_vendor_read(0x8484, 0, serial, buf);
385 pl2303_vendor_write(0x0404, 1, serial);
386 pl2303_vendor_read(0x8484, 0, serial, buf);
387 pl2303_vendor_read(0x8383, 0, serial, buf);
388 pl2303_vendor_write(0, 1, serial);
389 pl2303_vendor_write(1, 0, serial);
390 if (type == HX)
391 pl2303_vendor_write(2, 0x44, serial);
392 else
393 pl2303_vendor_write(2, 0x24, serial);
394
395 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 return 0;
397
398cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800399 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100400 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 priv = usb_get_serial_port_data(serial->port[i]);
402 pl2303_buf_free(priv->buf);
403 kfree(priv);
404 usb_set_serial_port_data(serial->port[i], NULL);
405 }
406 return -ENOMEM;
407}
408
Thiago Galesi372db8a2006-07-31 15:39:27 -0300409static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
411 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100412
Thiago Galesi372db8a2006-07-31 15:39:27 -0300413 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
414 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
415 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800416 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 return retval;
418}
419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420static void pl2303_send(struct usb_serial_port *port)
421{
422 int count, result;
423 struct pl2303_private *priv = usb_get_serial_port_data(port);
424 unsigned long flags;
425
Harvey Harrison441b62c2008-03-03 16:08:34 -0800426 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 spin_lock_irqsave(&priv->lock, flags);
429
430 if (priv->write_urb_in_use) {
431 spin_unlock_irqrestore(&priv->lock, flags);
432 return;
433 }
434
435 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300436 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 if (count == 0) {
439 spin_unlock_irqrestore(&priv->lock, flags);
440 return;
441 }
442
443 priv->write_urb_in_use = 1;
444
445 spin_unlock_irqrestore(&priv->lock, flags);
446
Harvey Harrison441b62c2008-03-03 16:08:34 -0800447 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300448 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450 port->write_urb->transfer_buffer_length = count;
451 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300452 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300454 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800455 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100457 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 }
459
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700460 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461}
462
Alan Cox95da3102008-07-22 11:09:07 +0100463static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
464 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300465{
466 struct pl2303_private *priv = usb_get_serial_port_data(port);
467 unsigned long flags;
468
Harvey Harrison441b62c2008-03-03 16:08:34 -0800469 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300470
471 if (!count)
472 return count;
473
474 spin_lock_irqsave(&priv->lock, flags);
475 count = pl2303_buf_put(priv->buf, buf, count);
476 spin_unlock_irqrestore(&priv->lock, flags);
477
478 pl2303_send(port);
479
480 return count;
481}
482
Alan Cox95da3102008-07-22 11:09:07 +0100483static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
Alan Cox95da3102008-07-22 11:09:07 +0100485 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 struct pl2303_private *priv = usb_get_serial_port_data(port);
487 int room = 0;
488 unsigned long flags;
489
Harvey Harrison441b62c2008-03-03 16:08:34 -0800490 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492 spin_lock_irqsave(&priv->lock, flags);
493 room = pl2303_buf_space_avail(priv->buf);
494 spin_unlock_irqrestore(&priv->lock, flags);
495
Harvey Harrison441b62c2008-03-03 16:08:34 -0800496 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 return room;
498}
499
Alan Cox95da3102008-07-22 11:09:07 +0100500static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
Alan Cox95da3102008-07-22 11:09:07 +0100502 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 struct pl2303_private *priv = usb_get_serial_port_data(port);
504 int chars = 0;
505 unsigned long flags;
506
Harvey Harrison441b62c2008-03-03 16:08:34 -0800507 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 spin_lock_irqsave(&priv->lock, flags);
510 chars = pl2303_buf_data_avail(priv->buf);
511 spin_unlock_irqrestore(&priv->lock, flags);
512
Harvey Harrison441b62c2008-03-03 16:08:34 -0800513 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 return chars;
515}
516
Alan Cox95da3102008-07-22 11:09:07 +0100517static void pl2303_set_termios(struct tty_struct *tty,
518 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
520 struct usb_serial *serial = port->serial;
521 struct pl2303_private *priv = usb_get_serial_port_data(port);
522 unsigned long flags;
523 unsigned int cflag;
524 unsigned char *buf;
525 int baud;
526 int i;
527 u8 control;
528
Harvey Harrison441b62c2008-03-03 16:08:34 -0800529 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Alan Coxbf5e5832008-01-08 14:55:51 +0000531 /* The PL2303 is reported to lose bytes if you change
532 serial settings even to the same values as before. Thus
533 we actually need to filter in this specific case */
534
Alan Cox95da3102008-07-22 11:09:07 +0100535 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000536 return;
537
Alan Cox95da3102008-07-22 11:09:07 +0100538 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Thiago Galesi372db8a2006-07-31 15:39:27 -0300540 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800542 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100543 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100544 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 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) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100556 case CS5:
557 buf[6] = 5;
558 break;
559 case CS6:
560 buf[6] = 6;
561 break;
562 case CS7:
563 buf[6] = 7;
564 break;
565 default:
566 case CS8:
567 buf[6] = 8;
568 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800570 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
572
Alan Cox95da3102008-07-22 11:09:07 +0100573 baud = tty_get_baud_rate(tty);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800574 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 if (baud) {
576 buf[0] = baud & 0xff;
577 buf[1] = (baud >> 8) & 0xff;
578 buf[2] = (baud >> 16) & 0xff;
579 buf[3] = (baud >> 24) & 0xff;
580 }
581
582 /* For reference buf[4]=0 is 1 stop bits */
583 /* For reference buf[4]=1 is 1.5 stop bits */
584 /* For reference buf[4]=2 is 2 stop bits */
585 if (cflag & CSTOPB) {
586 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800587 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 } else {
589 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800590 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
592
593 if (cflag & PARENB) {
594 /* For reference buf[5]=0 is none parity */
595 /* For reference buf[5]=1 is odd parity */
596 /* For reference buf[5]=2 is even parity */
597 /* For reference buf[5]=3 is mark parity */
598 /* For reference buf[5]=4 is space parity */
599 if (cflag & PARODD) {
600 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800601 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 } else {
603 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800604 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
606 } else {
607 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800608 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610
Thiago Galesi372db8a2006-07-31 15:39:27 -0300611 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
612 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
613 0, 0, buf, 7, 100);
614 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 /* change control lines if we are switching to or from B0 */
617 spin_lock_irqsave(&priv->lock, flags);
618 control = priv->line_control;
619 if ((cflag & CBAUD) == B0)
620 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
621 else
622 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
623 if (control != priv->line_control) {
624 control = priv->line_control;
625 spin_unlock_irqrestore(&priv->lock, flags);
626 set_control_lines(serial->dev, control);
627 } else {
628 spin_unlock_irqrestore(&priv->lock, flags);
629 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
632
Thiago Galesi372db8a2006-07-31 15:39:27 -0300633 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
634 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
635 0, 0, buf, 7, 100);
636 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
638
639 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800641 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800643 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200644 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800645 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
647
Alan Coxdf64c472007-10-15 20:54:47 +0100648 /* FIXME: Need to read back resulting baud rate */
649 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100650 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100651
Thiago Galesi372db8a2006-07-31 15:39:27 -0300652 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
654
Alan Cox95da3102008-07-22 11:09:07 +0100655static void pl2303_close(struct tty_struct *tty,
656 struct usb_serial_port *port, struct file *filp)
Thiago Galesi572d3132006-07-29 10:46:37 -0300657{
658 struct pl2303_private *priv = usb_get_serial_port_data(port);
659 unsigned long flags;
660 unsigned int c_cflag;
661 int bps;
662 long timeout;
663 wait_queue_t wait;
664
Harvey Harrison441b62c2008-03-03 16:08:34 -0800665 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300666
667 /* wait for data to drain from the buffer */
668 spin_lock_irqsave(&priv->lock, flags);
669 timeout = PL2303_CLOSING_WAIT;
670 init_waitqueue_entry(&wait, current);
Alan Cox95da3102008-07-22 11:09:07 +0100671 add_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300672 for (;;) {
673 set_current_state(TASK_INTERRUPTIBLE);
674 if (pl2303_buf_data_avail(priv->buf) == 0 ||
675 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100676 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300677 break;
678 spin_unlock_irqrestore(&priv->lock, flags);
679 timeout = schedule_timeout(timeout);
680 spin_lock_irqsave(&priv->lock, flags);
681 }
682 set_current_state(TASK_RUNNING);
Alan Cox95da3102008-07-22 11:09:07 +0100683 remove_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300684 /* clear out any remaining data in the buffer */
685 pl2303_buf_clear(priv->buf);
686 spin_unlock_irqrestore(&priv->lock, flags);
687
688 /* wait for characters to drain from the device */
689 /* (this is long enough for the entire 256 byte */
690 /* pl2303 hardware buffer to drain with no flow */
691 /* control for data rates of 1200 bps or more, */
692 /* for lower rates we should really know how much */
693 /* data is in the buffer to compute a delay */
694 /* that is not unnecessarily long) */
Alan Cox95da3102008-07-22 11:09:07 +0100695 bps = tty_get_baud_rate(tty);
Thiago Galesi572d3132006-07-29 10:46:37 -0300696 if (bps > 1200)
Alan Cox3a0f43e2008-07-22 11:14:49 +0100697 timeout = max((HZ*2560)/bps, HZ/10);
Thiago Galesi572d3132006-07-29 10:46:37 -0300698 else
699 timeout = 2*HZ;
700 schedule_timeout_interruptible(timeout);
701
702 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800703 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300704 usb_kill_urb(port->write_urb);
705 usb_kill_urb(port->read_urb);
706 usb_kill_urb(port->interrupt_in_urb);
707
Alan Cox95da3102008-07-22 11:09:07 +0100708 if (tty) {
709 c_cflag = tty->termios->c_cflag;
Thiago Galesi572d3132006-07-29 10:46:37 -0300710 if (c_cflag & HUPCL) {
711 /* drop DTR and RTS */
712 spin_lock_irqsave(&priv->lock, flags);
713 priv->line_control = 0;
714 spin_unlock_irqrestore(&priv->lock, flags);
715 set_control_lines(port->serial->dev, 0);
716 }
717 }
718}
719
Alan Cox95da3102008-07-22 11:09:07 +0100720static int pl2303_open(struct tty_struct *tty,
721 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Alan Cox606d0992006-12-08 02:38:45 -0800723 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 struct usb_serial *serial = port->serial;
725 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 int result;
727
Harvey Harrison441b62c2008-03-03 16:08:34 -0800728 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Dariusz M16948992005-07-28 18:06:13 +0200730 if (priv->type != HX) {
731 usb_clear_halt(serial->dev, port->write_urb->pipe);
732 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800733 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800735 pl2303_vendor_write(8, 0, serial);
736 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 }
738
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100740 if (tty)
741 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Alan Cox3a0f43e2008-07-22 11:14:49 +0100743 /* FIXME: need to assert RTS and DTR if CRTSCTS off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Harvey Harrison441b62c2008-03-03 16:08:34 -0800745 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300747 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300749 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800750 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100751 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return -EPROTO;
753 }
754
Harvey Harrison441b62c2008-03-03 16:08:34 -0800755 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300757 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300759 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800760 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100761 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return -EPROTO;
763 }
764 return 0;
765}
766
Alan Cox95da3102008-07-22 11:09:07 +0100767static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300768 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
Alan Cox95da3102008-07-22 11:09:07 +0100770 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 struct pl2303_private *priv = usb_get_serial_port_data(port);
772 unsigned long flags;
773 u8 control;
774
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700775 if (!usb_get_intfdata(port->serial->interface))
776 return -ENODEV;
777
Thiago Galesi372db8a2006-07-31 15:39:27 -0300778 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (set & TIOCM_RTS)
780 priv->line_control |= CONTROL_RTS;
781 if (set & TIOCM_DTR)
782 priv->line_control |= CONTROL_DTR;
783 if (clear & TIOCM_RTS)
784 priv->line_control &= ~CONTROL_RTS;
785 if (clear & TIOCM_DTR)
786 priv->line_control &= ~CONTROL_DTR;
787 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300788 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Thiago Galesi372db8a2006-07-31 15:39:27 -0300790 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
Alan Cox95da3102008-07-22 11:09:07 +0100793static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
Alan Cox95da3102008-07-22 11:09:07 +0100795 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 struct pl2303_private *priv = usb_get_serial_port_data(port);
797 unsigned long flags;
798 unsigned int mcr;
799 unsigned int status;
800 unsigned int result;
801
Harvey Harrison441b62c2008-03-03 16:08:34 -0800802 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700804 if (!usb_get_intfdata(port->serial->interface))
805 return -ENODEV;
806
Thiago Galesi372db8a2006-07-31 15:39:27 -0300807 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 mcr = priv->line_control;
809 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300810 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
813 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
814 | ((status & UART_CTS) ? TIOCM_CTS : 0)
815 | ((status & UART_DSR) ? TIOCM_DSR : 0)
816 | ((status & UART_RING) ? TIOCM_RI : 0)
817 | ((status & UART_DCD) ? TIOCM_CD : 0);
818
Harvey Harrison441b62c2008-03-03 16:08:34 -0800819 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 return result;
822}
823
824static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
825{
826 struct pl2303_private *priv = usb_get_serial_port_data(port);
827 unsigned long flags;
828 unsigned int prevstatus;
829 unsigned int status;
830 unsigned int changed;
831
Thiago Galesi372db8a2006-07-31 15:39:27 -0300832 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300834 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 while (1) {
837 interruptible_sleep_on(&priv->delta_msr_wait);
838 /* see if a signal did it */
839 if (signal_pending(current))
840 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300841
842 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300844 spin_unlock_irqrestore(&priv->lock, flags);
845
Alan Cox3a0f43e2008-07-22 11:14:49 +0100846 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
849 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
850 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100851 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 return 0;
853 }
854 prevstatus = status;
855 }
856 /* NOTREACHED */
857 return 0;
858}
859
Alan Cox95da3102008-07-22 11:09:07 +0100860static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300861 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
Alan Cox95da3102008-07-22 11:09:07 +0100863 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800864 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100867 case TIOCMIWAIT:
868 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
869 return wait_modem_info(port, arg);
870 default:
871 dbg("%s not supported = 0x%04x", __func__, cmd);
872 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return -ENOIOCTLCMD;
875}
876
Alan Cox95da3102008-07-22 11:09:07 +0100877static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
Alan Cox95da3102008-07-22 11:09:07 +0100879 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 struct usb_serial *serial = port->serial;
881 u16 state;
882 int result;
883
Harvey Harrison441b62c2008-03-03 16:08:34 -0800884 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886 if (break_state == 0)
887 state = BREAK_OFF;
888 else
889 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100890 dbg("%s - turning break %s", __func__,
891 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
Thiago Galesi372db8a2006-07-31 15:39:27 -0300893 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
894 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
895 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800897 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898}
899
Thiago Galesi372db8a2006-07-31 15:39:27 -0300900static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 int i;
903 struct pl2303_private *priv;
904
Harvey Harrison441b62c2008-03-03 16:08:34 -0800905 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
907 for (i = 0; i < serial->num_ports; ++i) {
908 priv = usb_get_serial_port_data(serial->port[i]);
909 if (priv) {
910 pl2303_buf_free(priv->buf);
911 kfree(priv);
912 usb_set_serial_port_data(serial->port[i], NULL);
913 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915}
916
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700917static void pl2303_update_line_status(struct usb_serial_port *port,
918 unsigned char *data,
919 unsigned int actual_length)
920{
921
922 struct pl2303_private *priv = usb_get_serial_port_data(port);
923 unsigned long flags;
924 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200925 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300926 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700927
Thiago Galesi9c537612006-07-29 10:47:12 -0300928 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
929 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
930
931
932 if (idv == SIEMENS_VENDOR_ID) {
933 if (idp == SIEMENS_PRODUCT_ID_X65 ||
934 idp == SIEMENS_PRODUCT_ID_SX1 ||
935 idp == SIEMENS_PRODUCT_ID_X75) {
936
937 length = 1;
938 status_idx = 0;
939 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700940 }
941
942 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300943 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700944
Alan Cox3a0f43e2008-07-22 11:14:49 +0100945 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700946 spin_lock_irqsave(&priv->lock, flags);
947 priv->line_status = data[status_idx];
948 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300949 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700950}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
David Howells7d12e782006-10-05 14:55:46 +0100952static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
Ming Leicdc97792008-02-24 18:41:47 +0800954 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700956 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700957 int status = urb->status;
958 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Harvey Harrison441b62c2008-03-03 16:08:34 -0800960 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700962 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 case 0:
964 /* success */
965 break;
966 case -ECONNRESET:
967 case -ENOENT:
968 case -ESHUTDOWN:
969 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800970 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700971 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 return;
973 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800974 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700975 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 goto exit;
977 }
978
Harvey Harrison441b62c2008-03-03 16:08:34 -0800979 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300980 urb->actual_length, urb->transfer_buffer);
981
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700982 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700985 retval = usb_submit_urb(urb, GFP_ATOMIC);
986 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300987 dev_err(&urb->dev->dev,
988 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800989 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990}
991
David Howells7d12e782006-10-05 14:55:46 +0100992static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993{
Ming Leicdc97792008-02-24 18:41:47 +0800994 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 struct pl2303_private *priv = usb_get_serial_port_data(port);
996 struct tty_struct *tty;
997 unsigned char *data = urb->transfer_buffer;
998 unsigned long flags;
999 int i;
1000 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001001 int status = urb->status;
1002 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 char tty_flag;
1004
Harvey Harrison441b62c2008-03-03 16:08:34 -08001005 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001007 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001008 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001009 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001010 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return;
1012 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001013 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001014 /* PL2303 mysteriously fails with -EPROTO reschedule
1015 * the read */
1016 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001017 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 urb->dev = port->serial->dev;
1019 result = usb_submit_urb(urb, GFP_ATOMIC);
1020 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001021 dev_err(&urb->dev->dev, "%s - failed"
1022 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001023 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return;
1025 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001026 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return;
1028 }
1029
Harvey Harrison441b62c2008-03-03 16:08:34 -08001030 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001031 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 /* get tty_flag from status */
1034 tty_flag = TTY_NORMAL;
1035
1036 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001037 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1039 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001040 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 /* break takes precedence over parity, */
1043 /* which takes precedence over framing errors */
Alan Cox3a0f43e2008-07-22 11:14:49 +01001044 if (line_status & UART_BREAK_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001046 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001048 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001050 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Alan Cox4a90f092008-10-13 10:39:46 +01001052 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001054 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001056 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001058 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001059 tty_insert_flip_char(tty, data[i], tty_flag);
1060 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 }
Alan Cox4a90f092008-10-13 10:39:46 +01001062 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001064 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 urb->dev = port->serial->dev;
1066 result = usb_submit_urb(urb, GFP_ATOMIC);
1067 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001068 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001069 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
1071
1072 return;
1073}
1074
David Howells7d12e782006-10-05 14:55:46 +01001075static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
Ming Leicdc97792008-02-24 18:41:47 +08001077 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 struct pl2303_private *priv = usb_get_serial_port_data(port);
1079 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001080 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Harvey Harrison441b62c2008-03-03 16:08:34 -08001082 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001084 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 case 0:
1086 /* success */
1087 break;
1088 case -ECONNRESET:
1089 case -ENOENT:
1090 case -ESHUTDOWN:
1091 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001092 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001093 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 priv->write_urb_in_use = 0;
1095 return;
1096 default:
1097 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001098 dbg("%s - Overflow in write", __func__);
1099 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001100 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 port->write_urb->transfer_buffer_length = 1;
1102 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001103 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001105 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001106 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 else
1108 return;
1109 }
1110
1111 priv->write_urb_in_use = 0;
1112
1113 /* send any buffered data */
1114 pl2303_send(port);
1115}
1116
Thiago Galesi572d3132006-07-29 10:46:37 -03001117/* All of the device info needed for the PL2303 SIO serial converter */
1118static struct usb_serial_driver pl2303_device = {
1119 .driver = {
1120 .owner = THIS_MODULE,
1121 .name = "pl2303",
1122 },
1123 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001124 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001125 .num_ports = 1,
1126 .open = pl2303_open,
1127 .close = pl2303_close,
1128 .write = pl2303_write,
1129 .ioctl = pl2303_ioctl,
1130 .break_ctl = pl2303_break_ctl,
1131 .set_termios = pl2303_set_termios,
1132 .tiocmget = pl2303_tiocmget,
1133 .tiocmset = pl2303_tiocmset,
1134 .read_bulk_callback = pl2303_read_bulk_callback,
1135 .read_int_callback = pl2303_read_int_callback,
1136 .write_bulk_callback = pl2303_write_bulk_callback,
1137 .write_room = pl2303_write_room,
1138 .chars_in_buffer = pl2303_chars_in_buffer,
1139 .attach = pl2303_startup,
1140 .shutdown = pl2303_shutdown,
1141};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Thiago Galesi372db8a2006-07-31 15:39:27 -03001143static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144{
1145 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 retval = usb_serial_register(&pl2303_device);
1148 if (retval)
1149 goto failed_usb_serial_register;
1150 retval = usb_register(&pl2303_driver);
1151 if (retval)
1152 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001153 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 return 0;
1155failed_usb_register:
1156 usb_serial_deregister(&pl2303_device);
1157failed_usb_serial_register:
1158 return retval;
1159}
1160
Thiago Galesi372db8a2006-07-31 15:39:27 -03001161static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001163 usb_deregister(&pl2303_driver);
1164 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165}
1166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167module_init(pl2303_init);
1168module_exit(pl2303_exit);
1169
1170MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171MODULE_LICENSE("GPL");
1172
1173module_param(debug, bool, S_IRUGO | S_IWUSR);
1174MODULE_PARM_DESC(debug, "Debug enabled or not");
1175