blob: 908437847165b4a34d26468891a273f26bf62ab2 [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) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070082 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010083 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
84 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010085 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010086 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080087 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040088 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100089 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020090 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090091 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090092 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050093 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 { } /* Terminating entry */
95};
96
Thiago Galesi372db8a2006-07-31 15:39:27 -030097MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 .name = "pl2303",
101 .probe = usb_serial_probe,
102 .disconnect = usb_serial_disconnect,
103 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800104 .suspend = usb_serial_suspend,
105 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800106 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800107 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110#define SET_LINE_REQUEST_TYPE 0x21
111#define SET_LINE_REQUEST 0x20
112
113#define SET_CONTROL_REQUEST_TYPE 0x21
114#define SET_CONTROL_REQUEST 0x22
115#define CONTROL_DTR 0x01
116#define CONTROL_RTS 0x02
117
118#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100119#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#define BREAK_ON 0xffff
121#define BREAK_OFF 0x0000
122
123#define GET_LINE_REQUEST_TYPE 0xa1
124#define GET_LINE_REQUEST 0x21
125
126#define VENDOR_WRITE_REQUEST_TYPE 0x40
127#define VENDOR_WRITE_REQUEST 0x01
128
129#define VENDOR_READ_REQUEST_TYPE 0xc0
130#define VENDOR_READ_REQUEST 0x01
131
132#define UART_STATE 0x08
133#define UART_STATE_TRANSIENT_MASK 0x74
134#define UART_DCD 0x01
135#define UART_DSR 0x02
136#define UART_BREAK_ERROR 0x04
137#define UART_RING 0x08
138#define UART_FRAME_ERROR 0x10
139#define UART_PARITY_ERROR 0x20
140#define UART_OVERRUN_ERROR 0x40
141#define UART_CTS 0x80
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144enum pl2303_type {
145 type_0, /* don't know the difference between type 0 and */
146 type_1, /* type 1, until someone from prolific tells us... */
147 HX, /* HX version of the pl2303 chip */
148};
149
150struct pl2303_private {
151 spinlock_t lock;
152 struct pl2303_buf *buf;
153 int write_urb_in_use;
154 wait_queue_head_t delta_msr_wait;
155 u8 line_control;
156 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 enum pl2303_type type;
158};
159
Thiago Galesi572d3132006-07-29 10:46:37 -0300160/*
161 * pl2303_buf_alloc
162 *
163 * Allocate a circular buffer and all associated memory.
164 */
165static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
166{
167 struct pl2303_buf *pb;
168
169 if (size == 0)
170 return NULL;
171
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800172 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300173 if (pb == NULL)
174 return NULL;
175
176 pb->buf_buf = kmalloc(size, GFP_KERNEL);
177 if (pb->buf_buf == NULL) {
178 kfree(pb);
179 return NULL;
180 }
181
182 pb->buf_size = size;
183 pb->buf_get = pb->buf_put = pb->buf_buf;
184
185 return pb;
186}
187
188/*
189 * pl2303_buf_free
190 *
191 * Free the buffer and all associated memory.
192 */
193static void pl2303_buf_free(struct pl2303_buf *pb)
194{
195 if (pb) {
196 kfree(pb->buf_buf);
197 kfree(pb);
198 }
199}
200
201/*
202 * pl2303_buf_clear
203 *
204 * Clear out all data in the circular buffer.
205 */
206static void pl2303_buf_clear(struct pl2303_buf *pb)
207{
208 if (pb != NULL)
209 pb->buf_get = pb->buf_put;
210 /* equivalent to a get of all data available */
211}
212
213/*
214 * pl2303_buf_data_avail
215 *
216 * Return the number of bytes of data available in the circular
217 * buffer.
218 */
219static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
220{
221 if (pb == NULL)
222 return 0;
223
Alan Cox3a0f43e2008-07-22 11:14:49 +0100224 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300225}
226
227/*
228 * pl2303_buf_space_avail
229 *
230 * Return the number of bytes of space available in the circular
231 * buffer.
232 */
233static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
234{
235 if (pb == NULL)
236 return 0;
237
Alan Cox3a0f43e2008-07-22 11:14:49 +0100238 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300239}
240
241/*
242 * pl2303_buf_put
243 *
244 * Copy data data from a user buffer and put it into the circular buffer.
245 * Restrict to the amount of space available.
246 *
247 * Return the number of bytes copied.
248 */
249static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
250 unsigned int count)
251{
252 unsigned int len;
253
254 if (pb == NULL)
255 return 0;
256
257 len = pl2303_buf_space_avail(pb);
258 if (count > len)
259 count = len;
260
261 if (count == 0)
262 return 0;
263
264 len = pb->buf_buf + pb->buf_size - pb->buf_put;
265 if (count > len) {
266 memcpy(pb->buf_put, buf, len);
267 memcpy(pb->buf_buf, buf+len, count - len);
268 pb->buf_put = pb->buf_buf + count - len;
269 } else {
270 memcpy(pb->buf_put, buf, count);
271 if (count < len)
272 pb->buf_put += count;
273 else /* count == len */
274 pb->buf_put = pb->buf_buf;
275 }
276
277 return count;
278}
279
280/*
281 * pl2303_buf_get
282 *
283 * Get data from the circular buffer and copy to the given buffer.
284 * Restrict to the amount of data available.
285 *
286 * Return the number of bytes copied.
287 */
288static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
289 unsigned int count)
290{
291 unsigned int len;
292
293 if (pb == NULL)
294 return 0;
295
296 len = pl2303_buf_data_avail(pb);
297 if (count > len)
298 count = len;
299
300 if (count == 0)
301 return 0;
302
303 len = pb->buf_buf + pb->buf_size - pb->buf_get;
304 if (count > len) {
305 memcpy(buf, pb->buf_get, len);
306 memcpy(buf+len, pb->buf_buf, count - len);
307 pb->buf_get = pb->buf_buf + count - len;
308 } else {
309 memcpy(buf, pb->buf_get, count);
310 if (count < len)
311 pb->buf_get += count;
312 else /* count == len */
313 pb->buf_get = pb->buf_buf;
314 }
315
316 return count;
317}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Sarah Sharpeb44da02007-12-14 14:08:00 -0800319static int pl2303_vendor_read(__u16 value, __u16 index,
320 struct usb_serial *serial, unsigned char *buf)
321{
322 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
323 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
324 value, index, buf, 1, 100);
325 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
326 VENDOR_READ_REQUEST, value, index, res, buf[0]);
327 return res;
328}
329
330static int pl2303_vendor_write(__u16 value, __u16 index,
331 struct usb_serial *serial)
332{
333 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
334 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
335 value, index, NULL, 0, 100);
336 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
337 VENDOR_WRITE_REQUEST, value, index, res);
338 return res;
339}
340
Thiago Galesi372db8a2006-07-31 15:39:27 -0300341static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
343 struct pl2303_private *priv;
344 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800345 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 int i;
347
Sarah Sharp3e152502007-12-14 14:08:35 -0800348 buf = kmalloc(10, GFP_KERNEL);
349 if (buf == NULL)
350 return -ENOMEM;
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (serial->dev->descriptor.bDeviceClass == 0x02)
353 type = type_0;
354 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
355 type = HX;
356 else if (serial->dev->descriptor.bDeviceClass == 0x00)
357 type = type_1;
358 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
359 type = type_1;
360 dbg("device type: %d", type);
361
362 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100363 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 if (!priv)
365 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 spin_lock_init(&priv->lock);
367 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
368 if (priv->buf == NULL) {
369 kfree(priv);
370 goto cleanup;
371 }
372 init_waitqueue_head(&priv->delta_msr_wait);
373 priv->type = type;
374 usb_set_serial_port_data(serial->port[i], priv);
375 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800376
377 pl2303_vendor_read(0x8484, 0, serial, buf);
378 pl2303_vendor_write(0x0404, 0, serial);
379 pl2303_vendor_read(0x8484, 0, serial, buf);
380 pl2303_vendor_read(0x8383, 0, serial, buf);
381 pl2303_vendor_read(0x8484, 0, serial, buf);
382 pl2303_vendor_write(0x0404, 1, serial);
383 pl2303_vendor_read(0x8484, 0, serial, buf);
384 pl2303_vendor_read(0x8383, 0, serial, buf);
385 pl2303_vendor_write(0, 1, serial);
386 pl2303_vendor_write(1, 0, serial);
387 if (type == HX)
388 pl2303_vendor_write(2, 0x44, serial);
389 else
390 pl2303_vendor_write(2, 0x24, serial);
391
392 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 return 0;
394
395cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800396 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100397 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 priv = usb_get_serial_port_data(serial->port[i]);
399 pl2303_buf_free(priv->buf);
400 kfree(priv);
401 usb_set_serial_port_data(serial->port[i], NULL);
402 }
403 return -ENOMEM;
404}
405
Thiago Galesi372db8a2006-07-31 15:39:27 -0300406static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
408 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100409
Thiago Galesi372db8a2006-07-31 15:39:27 -0300410 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
411 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
412 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800413 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 return retval;
415}
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static void pl2303_send(struct usb_serial_port *port)
418{
419 int count, result;
420 struct pl2303_private *priv = usb_get_serial_port_data(port);
421 unsigned long flags;
422
Harvey Harrison441b62c2008-03-03 16:08:34 -0800423 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 spin_lock_irqsave(&priv->lock, flags);
426
427 if (priv->write_urb_in_use) {
428 spin_unlock_irqrestore(&priv->lock, flags);
429 return;
430 }
431
432 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300433 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 if (count == 0) {
436 spin_unlock_irqrestore(&priv->lock, flags);
437 return;
438 }
439
440 priv->write_urb_in_use = 1;
441
442 spin_unlock_irqrestore(&priv->lock, flags);
443
Harvey Harrison441b62c2008-03-03 16:08:34 -0800444 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300445 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 port->write_urb->transfer_buffer_length = count;
448 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300449 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300451 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800452 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100454 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 }
456
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700457 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
Alan Cox95da3102008-07-22 11:09:07 +0100460static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
461 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300462{
463 struct pl2303_private *priv = usb_get_serial_port_data(port);
464 unsigned long flags;
465
Harvey Harrison441b62c2008-03-03 16:08:34 -0800466 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300467
468 if (!count)
469 return count;
470
471 spin_lock_irqsave(&priv->lock, flags);
472 count = pl2303_buf_put(priv->buf, buf, count);
473 spin_unlock_irqrestore(&priv->lock, flags);
474
475 pl2303_send(port);
476
477 return count;
478}
479
Alan Cox95da3102008-07-22 11:09:07 +0100480static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
Alan Cox95da3102008-07-22 11:09:07 +0100482 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 struct pl2303_private *priv = usb_get_serial_port_data(port);
484 int room = 0;
485 unsigned long flags;
486
Harvey Harrison441b62c2008-03-03 16:08:34 -0800487 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 spin_lock_irqsave(&priv->lock, flags);
490 room = pl2303_buf_space_avail(priv->buf);
491 spin_unlock_irqrestore(&priv->lock, flags);
492
Harvey Harrison441b62c2008-03-03 16:08:34 -0800493 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 return room;
495}
496
Alan Cox95da3102008-07-22 11:09:07 +0100497static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
Alan Cox95da3102008-07-22 11:09:07 +0100499 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 struct pl2303_private *priv = usb_get_serial_port_data(port);
501 int chars = 0;
502 unsigned long flags;
503
Harvey Harrison441b62c2008-03-03 16:08:34 -0800504 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
506 spin_lock_irqsave(&priv->lock, flags);
507 chars = pl2303_buf_data_avail(priv->buf);
508 spin_unlock_irqrestore(&priv->lock, flags);
509
Harvey Harrison441b62c2008-03-03 16:08:34 -0800510 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 return chars;
512}
513
Alan Cox95da3102008-07-22 11:09:07 +0100514static void pl2303_set_termios(struct tty_struct *tty,
515 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
517 struct usb_serial *serial = port->serial;
518 struct pl2303_private *priv = usb_get_serial_port_data(port);
519 unsigned long flags;
520 unsigned int cflag;
521 unsigned char *buf;
522 int baud;
523 int i;
524 u8 control;
525
Harvey Harrison441b62c2008-03-03 16:08:34 -0800526 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Alan Coxbf5e5832008-01-08 14:55:51 +0000528 /* The PL2303 is reported to lose bytes if you change
529 serial settings even to the same values as before. Thus
530 we actually need to filter in this specific case */
531
Alan Cox95da3102008-07-22 11:09:07 +0100532 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000533 return;
534
Alan Cox95da3102008-07-22 11:09:07 +0100535 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Thiago Galesi372db8a2006-07-31 15:39:27 -0300537 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800539 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100540 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100541 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 return;
543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Thiago Galesi372db8a2006-07-31 15:39:27 -0300545 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
546 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
547 0, 0, buf, 7, 100);
548 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
549 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 if (cflag & CSIZE) {
552 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100553 case CS5:
554 buf[6] = 5;
555 break;
556 case CS6:
557 buf[6] = 6;
558 break;
559 case CS7:
560 buf[6] = 7;
561 break;
562 default:
563 case CS8:
564 buf[6] = 8;
565 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 }
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 Cox95da3102008-07-22 11:09:07 +0100570 baud = tty_get_baud_rate(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)
Alan Cox95da3102008-07-22 11:09:07 +0100647 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100648
Thiago Galesi372db8a2006-07-31 15:39:27 -0300649 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651
Alan Cox95da3102008-07-22 11:09:07 +0100652static void pl2303_close(struct tty_struct *tty,
653 struct usb_serial_port *port, struct file *filp)
Thiago Galesi572d3132006-07-29 10:46:37 -0300654{
655 struct pl2303_private *priv = usb_get_serial_port_data(port);
656 unsigned long flags;
657 unsigned int c_cflag;
658 int bps;
659 long timeout;
660 wait_queue_t wait;
661
Harvey Harrison441b62c2008-03-03 16:08:34 -0800662 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300663
664 /* wait for data to drain from the buffer */
665 spin_lock_irqsave(&priv->lock, flags);
666 timeout = PL2303_CLOSING_WAIT;
667 init_waitqueue_entry(&wait, current);
Alan Cox95da3102008-07-22 11:09:07 +0100668 add_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300669 for (;;) {
670 set_current_state(TASK_INTERRUPTIBLE);
671 if (pl2303_buf_data_avail(priv->buf) == 0 ||
672 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100673 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300674 break;
675 spin_unlock_irqrestore(&priv->lock, flags);
676 timeout = schedule_timeout(timeout);
677 spin_lock_irqsave(&priv->lock, flags);
678 }
679 set_current_state(TASK_RUNNING);
Alan Cox95da3102008-07-22 11:09:07 +0100680 remove_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300681 /* clear out any remaining data in the buffer */
682 pl2303_buf_clear(priv->buf);
683 spin_unlock_irqrestore(&priv->lock, flags);
684
685 /* wait for characters to drain from the device */
686 /* (this is long enough for the entire 256 byte */
687 /* pl2303 hardware buffer to drain with no flow */
688 /* control for data rates of 1200 bps or more, */
689 /* for lower rates we should really know how much */
690 /* data is in the buffer to compute a delay */
691 /* that is not unnecessarily long) */
Alan Cox95da3102008-07-22 11:09:07 +0100692 bps = tty_get_baud_rate(tty);
Thiago Galesi572d3132006-07-29 10:46:37 -0300693 if (bps > 1200)
Alan Cox3a0f43e2008-07-22 11:14:49 +0100694 timeout = max((HZ*2560)/bps, HZ/10);
Thiago Galesi572d3132006-07-29 10:46:37 -0300695 else
696 timeout = 2*HZ;
697 schedule_timeout_interruptible(timeout);
698
699 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800700 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300701 usb_kill_urb(port->write_urb);
702 usb_kill_urb(port->read_urb);
703 usb_kill_urb(port->interrupt_in_urb);
704
Alan Cox95da3102008-07-22 11:09:07 +0100705 if (tty) {
706 c_cflag = tty->termios->c_cflag;
Thiago Galesi572d3132006-07-29 10:46:37 -0300707 if (c_cflag & HUPCL) {
708 /* drop DTR and RTS */
709 spin_lock_irqsave(&priv->lock, flags);
710 priv->line_control = 0;
711 spin_unlock_irqrestore(&priv->lock, flags);
712 set_control_lines(port->serial->dev, 0);
713 }
714 }
715}
716
Alan Cox95da3102008-07-22 11:09:07 +0100717static int pl2303_open(struct tty_struct *tty,
718 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
Alan Cox606d0992006-12-08 02:38:45 -0800720 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 struct usb_serial *serial = port->serial;
722 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 int result;
724
Harvey Harrison441b62c2008-03-03 16:08:34 -0800725 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Dariusz M16948992005-07-28 18:06:13 +0200727 if (priv->type != HX) {
728 usb_clear_halt(serial->dev, port->write_urb->pipe);
729 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800730 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800732 pl2303_vendor_write(8, 0, serial);
733 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100737 if (tty)
738 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Alan Cox3a0f43e2008-07-22 11:14:49 +0100740 /* FIXME: need to assert RTS and DTR if CRTSCTS off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Harvey Harrison441b62c2008-03-03 16:08:34 -0800742 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300744 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300746 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800747 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100748 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 return -EPROTO;
750 }
751
Harvey Harrison441b62c2008-03-03 16:08:34 -0800752 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300754 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300756 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800757 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100758 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return -EPROTO;
760 }
761 return 0;
762}
763
Alan Cox95da3102008-07-22 11:09:07 +0100764static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300765 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Alan Cox95da3102008-07-22 11:09:07 +0100767 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 struct pl2303_private *priv = usb_get_serial_port_data(port);
769 unsigned long flags;
770 u8 control;
771
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700772 if (!usb_get_intfdata(port->serial->interface))
773 return -ENODEV;
774
Thiago Galesi372db8a2006-07-31 15:39:27 -0300775 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 if (set & TIOCM_RTS)
777 priv->line_control |= CONTROL_RTS;
778 if (set & TIOCM_DTR)
779 priv->line_control |= CONTROL_DTR;
780 if (clear & TIOCM_RTS)
781 priv->line_control &= ~CONTROL_RTS;
782 if (clear & TIOCM_DTR)
783 priv->line_control &= ~CONTROL_DTR;
784 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300785 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Thiago Galesi372db8a2006-07-31 15:39:27 -0300787 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788}
789
Alan Cox95da3102008-07-22 11:09:07 +0100790static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
Alan Cox95da3102008-07-22 11:09:07 +0100792 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 struct pl2303_private *priv = usb_get_serial_port_data(port);
794 unsigned long flags;
795 unsigned int mcr;
796 unsigned int status;
797 unsigned int result;
798
Harvey Harrison441b62c2008-03-03 16:08:34 -0800799 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700801 if (!usb_get_intfdata(port->serial->interface))
802 return -ENODEV;
803
Thiago Galesi372db8a2006-07-31 15:39:27 -0300804 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 mcr = priv->line_control;
806 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300807 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
809 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
810 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
811 | ((status & UART_CTS) ? TIOCM_CTS : 0)
812 | ((status & UART_DSR) ? TIOCM_DSR : 0)
813 | ((status & UART_RING) ? TIOCM_RI : 0)
814 | ((status & UART_DCD) ? TIOCM_CD : 0);
815
Harvey Harrison441b62c2008-03-03 16:08:34 -0800816 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 return result;
819}
820
821static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
822{
823 struct pl2303_private *priv = usb_get_serial_port_data(port);
824 unsigned long flags;
825 unsigned int prevstatus;
826 unsigned int status;
827 unsigned int changed;
828
Thiago Galesi372db8a2006-07-31 15:39:27 -0300829 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300831 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 while (1) {
834 interruptible_sleep_on(&priv->delta_msr_wait);
835 /* see if a signal did it */
836 if (signal_pending(current))
837 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300838
839 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300841 spin_unlock_irqrestore(&priv->lock, flags);
842
Alan Cox3a0f43e2008-07-22 11:14:49 +0100843 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
846 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
847 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100848 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 return 0;
850 }
851 prevstatus = status;
852 }
853 /* NOTREACHED */
854 return 0;
855}
856
Alan Cox95da3102008-07-22 11:09:07 +0100857static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300858 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859{
Alan Cox95da3102008-07-22 11:09:07 +0100860 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800861 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
863 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100864 case TIOCMIWAIT:
865 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
866 return wait_modem_info(port, arg);
867 default:
868 dbg("%s not supported = 0x%04x", __func__, cmd);
869 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return -ENOIOCTLCMD;
872}
873
Alan Cox95da3102008-07-22 11:09:07 +0100874static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
Alan Cox95da3102008-07-22 11:09:07 +0100876 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 struct usb_serial *serial = port->serial;
878 u16 state;
879 int result;
880
Harvey Harrison441b62c2008-03-03 16:08:34 -0800881 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 if (break_state == 0)
884 state = BREAK_OFF;
885 else
886 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100887 dbg("%s - turning break %s", __func__,
888 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
Thiago Galesi372db8a2006-07-31 15:39:27 -0300890 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
891 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
892 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800894 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895}
896
Thiago Galesi372db8a2006-07-31 15:39:27 -0300897static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898{
899 int i;
900 struct pl2303_private *priv;
901
Harvey Harrison441b62c2008-03-03 16:08:34 -0800902 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
904 for (i = 0; i < serial->num_ports; ++i) {
905 priv = usb_get_serial_port_data(serial->port[i]);
906 if (priv) {
907 pl2303_buf_free(priv->buf);
908 kfree(priv);
909 usb_set_serial_port_data(serial->port[i], NULL);
910 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912}
913
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700914static void pl2303_update_line_status(struct usb_serial_port *port,
915 unsigned char *data,
916 unsigned int actual_length)
917{
918
919 struct pl2303_private *priv = usb_get_serial_port_data(port);
920 unsigned long flags;
921 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200922 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300923 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700924
Thiago Galesi9c537612006-07-29 10:47:12 -0300925 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
926 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
927
928
929 if (idv == SIEMENS_VENDOR_ID) {
930 if (idp == SIEMENS_PRODUCT_ID_X65 ||
931 idp == SIEMENS_PRODUCT_ID_SX1 ||
932 idp == SIEMENS_PRODUCT_ID_X75) {
933
934 length = 1;
935 status_idx = 0;
936 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700937 }
938
939 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300940 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700941
Alan Cox3a0f43e2008-07-22 11:14:49 +0100942 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700943 spin_lock_irqsave(&priv->lock, flags);
944 priv->line_status = data[status_idx];
945 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300946 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700947}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
David Howells7d12e782006-10-05 14:55:46 +0100949static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950{
Ming Leicdc97792008-02-24 18:41:47 +0800951 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700953 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700954 int status = urb->status;
955 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Harvey Harrison441b62c2008-03-03 16:08:34 -0800957 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700959 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 case 0:
961 /* success */
962 break;
963 case -ECONNRESET:
964 case -ENOENT:
965 case -ESHUTDOWN:
966 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800967 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700968 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 return;
970 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800971 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700972 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 goto exit;
974 }
975
Harvey Harrison441b62c2008-03-03 16:08:34 -0800976 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300977 urb->actual_length, urb->transfer_buffer);
978
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700979 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700982 retval = usb_submit_urb(urb, GFP_ATOMIC);
983 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300984 dev_err(&urb->dev->dev,
985 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800986 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987}
988
David Howells7d12e782006-10-05 14:55:46 +0100989static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
Ming Leicdc97792008-02-24 18:41:47 +0800991 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 struct pl2303_private *priv = usb_get_serial_port_data(port);
993 struct tty_struct *tty;
994 unsigned char *data = urb->transfer_buffer;
995 unsigned long flags;
996 int i;
997 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700998 int status = urb->status;
999 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 char tty_flag;
1001
Harvey Harrison441b62c2008-03-03 16:08:34 -08001002 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001004 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001005 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001006 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001007 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return;
1009 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001010 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001011 /* PL2303 mysteriously fails with -EPROTO reschedule
1012 * the read */
1013 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001014 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 urb->dev = port->serial->dev;
1016 result = usb_submit_urb(urb, GFP_ATOMIC);
1017 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001018 dev_err(&urb->dev->dev, "%s - failed"
1019 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001020 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return;
1022 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001023 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return;
1025 }
1026
Harvey Harrison441b62c2008-03-03 16:08:34 -08001027 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001028 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030 /* get tty_flag from status */
1031 tty_flag = TTY_NORMAL;
1032
1033 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001034 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1036 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001037 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039 /* break takes precedence over parity, */
1040 /* which takes precedence over framing errors */
Alan Cox3a0f43e2008-07-22 11:14:49 +01001041 if (line_status & UART_BREAK_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001043 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001045 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001047 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
Alan Cox4a90f092008-10-13 10:39:46 +01001049 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001051 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001053 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001055 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001056 tty_insert_flip_char(tty, data[i], tty_flag);
1057 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
Alan Cox4a90f092008-10-13 10:39:46 +01001059 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001061 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 urb->dev = port->serial->dev;
1063 result = usb_submit_urb(urb, GFP_ATOMIC);
1064 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001065 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001066 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 }
1068
1069 return;
1070}
1071
David Howells7d12e782006-10-05 14:55:46 +01001072static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073{
Ming Leicdc97792008-02-24 18:41:47 +08001074 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 struct pl2303_private *priv = usb_get_serial_port_data(port);
1076 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001077 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Harvey Harrison441b62c2008-03-03 16:08:34 -08001079 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001081 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 case 0:
1083 /* success */
1084 break;
1085 case -ECONNRESET:
1086 case -ENOENT:
1087 case -ESHUTDOWN:
1088 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001089 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001090 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 priv->write_urb_in_use = 0;
1092 return;
1093 default:
1094 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001095 dbg("%s - Overflow in write", __func__);
1096 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001097 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 port->write_urb->transfer_buffer_length = 1;
1099 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001100 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001102 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001103 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 else
1105 return;
1106 }
1107
1108 priv->write_urb_in_use = 0;
1109
1110 /* send any buffered data */
1111 pl2303_send(port);
1112}
1113
Thiago Galesi572d3132006-07-29 10:46:37 -03001114/* All of the device info needed for the PL2303 SIO serial converter */
1115static struct usb_serial_driver pl2303_device = {
1116 .driver = {
1117 .owner = THIS_MODULE,
1118 .name = "pl2303",
1119 },
1120 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001121 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001122 .num_ports = 1,
1123 .open = pl2303_open,
1124 .close = pl2303_close,
1125 .write = pl2303_write,
1126 .ioctl = pl2303_ioctl,
1127 .break_ctl = pl2303_break_ctl,
1128 .set_termios = pl2303_set_termios,
1129 .tiocmget = pl2303_tiocmget,
1130 .tiocmset = pl2303_tiocmset,
1131 .read_bulk_callback = pl2303_read_bulk_callback,
1132 .read_int_callback = pl2303_read_int_callback,
1133 .write_bulk_callback = pl2303_write_bulk_callback,
1134 .write_room = pl2303_write_room,
1135 .chars_in_buffer = pl2303_chars_in_buffer,
1136 .attach = pl2303_startup,
1137 .shutdown = pl2303_shutdown,
1138};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
Thiago Galesi372db8a2006-07-31 15:39:27 -03001140static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
1142 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 retval = usb_serial_register(&pl2303_device);
1145 if (retval)
1146 goto failed_usb_serial_register;
1147 retval = usb_register(&pl2303_driver);
1148 if (retval)
1149 goto failed_usb_register;
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001150 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 return 0;
1152failed_usb_register:
1153 usb_serial_deregister(&pl2303_device);
1154failed_usb_serial_register:
1155 return retval;
1156}
1157
Thiago Galesi372db8a2006-07-31 15:39:27 -03001158static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001160 usb_deregister(&pl2303_driver);
1161 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162}
1163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164module_init(pl2303_init);
1165module_exit(pl2303_exit);
1166
1167MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168MODULE_LICENSE("GPL");
1169
1170module_param(debug, bool, S_IRUGO | S_IWUSR);
1171MODULE_PARM_DESC(debug, "Debug enabled or not");
1172