blob: 7d15bfa7c2dbfeb1c19768a2499ee2178d14efe0 [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) },
Gianpaolo Cugola8540d662009-06-05 22:57:52 +020097 { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 { } /* Terminating entry */
99};
100
Thiago Galesi372db8a2006-07-31 15:39:27 -0300101MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 .name = "pl2303",
105 .probe = usb_serial_probe,
106 .disconnect = usb_serial_disconnect,
107 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800108 .suspend = usb_serial_suspend,
109 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800110 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800111 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112};
113
114#define SET_LINE_REQUEST_TYPE 0x21
115#define SET_LINE_REQUEST 0x20
116
117#define SET_CONTROL_REQUEST_TYPE 0x21
118#define SET_CONTROL_REQUEST 0x22
119#define CONTROL_DTR 0x01
120#define CONTROL_RTS 0x02
121
122#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100123#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124#define BREAK_ON 0xffff
125#define BREAK_OFF 0x0000
126
127#define GET_LINE_REQUEST_TYPE 0xa1
128#define GET_LINE_REQUEST 0x21
129
130#define VENDOR_WRITE_REQUEST_TYPE 0x40
131#define VENDOR_WRITE_REQUEST 0x01
132
133#define VENDOR_READ_REQUEST_TYPE 0xc0
134#define VENDOR_READ_REQUEST 0x01
135
136#define UART_STATE 0x08
137#define UART_STATE_TRANSIENT_MASK 0x74
138#define UART_DCD 0x01
139#define UART_DSR 0x02
140#define UART_BREAK_ERROR 0x04
141#define UART_RING 0x08
142#define UART_FRAME_ERROR 0x10
143#define UART_PARITY_ERROR 0x20
144#define UART_OVERRUN_ERROR 0x40
145#define UART_CTS 0x80
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148enum pl2303_type {
149 type_0, /* don't know the difference between type 0 and */
150 type_1, /* type 1, until someone from prolific tells us... */
151 HX, /* HX version of the pl2303 chip */
152};
153
154struct pl2303_private {
155 spinlock_t lock;
156 struct pl2303_buf *buf;
157 int write_urb_in_use;
158 wait_queue_head_t delta_msr_wait;
159 u8 line_control;
160 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 enum pl2303_type type;
162};
163
Thiago Galesi572d3132006-07-29 10:46:37 -0300164/*
165 * pl2303_buf_alloc
166 *
167 * Allocate a circular buffer and all associated memory.
168 */
169static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
170{
171 struct pl2303_buf *pb;
172
173 if (size == 0)
174 return NULL;
175
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800176 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300177 if (pb == NULL)
178 return NULL;
179
180 pb->buf_buf = kmalloc(size, GFP_KERNEL);
181 if (pb->buf_buf == NULL) {
182 kfree(pb);
183 return NULL;
184 }
185
186 pb->buf_size = size;
187 pb->buf_get = pb->buf_put = pb->buf_buf;
188
189 return pb;
190}
191
192/*
193 * pl2303_buf_free
194 *
195 * Free the buffer and all associated memory.
196 */
197static void pl2303_buf_free(struct pl2303_buf *pb)
198{
199 if (pb) {
200 kfree(pb->buf_buf);
201 kfree(pb);
202 }
203}
204
205/*
206 * pl2303_buf_clear
207 *
208 * Clear out all data in the circular buffer.
209 */
210static void pl2303_buf_clear(struct pl2303_buf *pb)
211{
212 if (pb != NULL)
213 pb->buf_get = pb->buf_put;
214 /* equivalent to a get of all data available */
215}
216
217/*
218 * pl2303_buf_data_avail
219 *
220 * Return the number of bytes of data available in the circular
221 * buffer.
222 */
223static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
224{
225 if (pb == NULL)
226 return 0;
227
Alan Cox3a0f43e2008-07-22 11:14:49 +0100228 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300229}
230
231/*
232 * pl2303_buf_space_avail
233 *
234 * Return the number of bytes of space available in the circular
235 * buffer.
236 */
237static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
238{
239 if (pb == NULL)
240 return 0;
241
Alan Cox3a0f43e2008-07-22 11:14:49 +0100242 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300243}
244
245/*
246 * pl2303_buf_put
247 *
248 * Copy data data from a user buffer and put it into the circular buffer.
249 * Restrict to the amount of space available.
250 *
251 * Return the number of bytes copied.
252 */
253static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
254 unsigned int count)
255{
256 unsigned int len;
257
258 if (pb == NULL)
259 return 0;
260
261 len = pl2303_buf_space_avail(pb);
262 if (count > len)
263 count = len;
264
265 if (count == 0)
266 return 0;
267
268 len = pb->buf_buf + pb->buf_size - pb->buf_put;
269 if (count > len) {
270 memcpy(pb->buf_put, buf, len);
271 memcpy(pb->buf_buf, buf+len, count - len);
272 pb->buf_put = pb->buf_buf + count - len;
273 } else {
274 memcpy(pb->buf_put, buf, count);
275 if (count < len)
276 pb->buf_put += count;
277 else /* count == len */
278 pb->buf_put = pb->buf_buf;
279 }
280
281 return count;
282}
283
284/*
285 * pl2303_buf_get
286 *
287 * Get data from the circular buffer and copy to the given buffer.
288 * Restrict to the amount of data available.
289 *
290 * Return the number of bytes copied.
291 */
292static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
293 unsigned int count)
294{
295 unsigned int len;
296
297 if (pb == NULL)
298 return 0;
299
300 len = pl2303_buf_data_avail(pb);
301 if (count > len)
302 count = len;
303
304 if (count == 0)
305 return 0;
306
307 len = pb->buf_buf + pb->buf_size - pb->buf_get;
308 if (count > len) {
309 memcpy(buf, pb->buf_get, len);
310 memcpy(buf+len, pb->buf_buf, count - len);
311 pb->buf_get = pb->buf_buf + count - len;
312 } else {
313 memcpy(buf, pb->buf_get, count);
314 if (count < len)
315 pb->buf_get += count;
316 else /* count == len */
317 pb->buf_get = pb->buf_buf;
318 }
319
320 return count;
321}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Sarah Sharpeb44da02007-12-14 14:08:00 -0800323static int pl2303_vendor_read(__u16 value, __u16 index,
324 struct usb_serial *serial, unsigned char *buf)
325{
326 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
327 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
328 value, index, buf, 1, 100);
329 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
330 VENDOR_READ_REQUEST, value, index, res, buf[0]);
331 return res;
332}
333
334static int pl2303_vendor_write(__u16 value, __u16 index,
335 struct usb_serial *serial)
336{
337 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
338 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
339 value, index, NULL, 0, 100);
340 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
341 VENDOR_WRITE_REQUEST, value, index, res);
342 return res;
343}
344
Thiago Galesi372db8a2006-07-31 15:39:27 -0300345static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
347 struct pl2303_private *priv;
348 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800349 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 int i;
351
Sarah Sharp3e152502007-12-14 14:08:35 -0800352 buf = kmalloc(10, GFP_KERNEL);
353 if (buf == NULL)
354 return -ENOMEM;
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 if (serial->dev->descriptor.bDeviceClass == 0x02)
357 type = type_0;
358 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
359 type = HX;
360 else if (serial->dev->descriptor.bDeviceClass == 0x00)
361 type = type_1;
362 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
363 type = type_1;
364 dbg("device type: %d", type);
365
366 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100367 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 if (!priv)
369 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 spin_lock_init(&priv->lock);
371 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
372 if (priv->buf == NULL) {
373 kfree(priv);
374 goto cleanup;
375 }
376 init_waitqueue_head(&priv->delta_msr_wait);
377 priv->type = type;
378 usb_set_serial_port_data(serial->port[i], priv);
379 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800380
381 pl2303_vendor_read(0x8484, 0, serial, buf);
382 pl2303_vendor_write(0x0404, 0, serial);
383 pl2303_vendor_read(0x8484, 0, serial, buf);
384 pl2303_vendor_read(0x8383, 0, serial, buf);
385 pl2303_vendor_read(0x8484, 0, serial, buf);
386 pl2303_vendor_write(0x0404, 1, serial);
387 pl2303_vendor_read(0x8484, 0, serial, buf);
388 pl2303_vendor_read(0x8383, 0, serial, buf);
389 pl2303_vendor_write(0, 1, serial);
390 pl2303_vendor_write(1, 0, serial);
391 if (type == HX)
392 pl2303_vendor_write(2, 0x44, serial);
393 else
394 pl2303_vendor_write(2, 0x24, serial);
395
396 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return 0;
398
399cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800400 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100401 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 priv = usb_get_serial_port_data(serial->port[i]);
403 pl2303_buf_free(priv->buf);
404 kfree(priv);
405 usb_set_serial_port_data(serial->port[i], NULL);
406 }
407 return -ENOMEM;
408}
409
Thiago Galesi372db8a2006-07-31 15:39:27 -0300410static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100413
Thiago Galesi372db8a2006-07-31 15:39:27 -0300414 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
415 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
416 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800417 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 return retval;
419}
420
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421static void pl2303_send(struct usb_serial_port *port)
422{
423 int count, result;
424 struct pl2303_private *priv = usb_get_serial_port_data(port);
425 unsigned long flags;
426
Harvey Harrison441b62c2008-03-03 16:08:34 -0800427 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 spin_lock_irqsave(&priv->lock, flags);
430
431 if (priv->write_urb_in_use) {
432 spin_unlock_irqrestore(&priv->lock, flags);
433 return;
434 }
435
436 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300437 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
439 if (count == 0) {
440 spin_unlock_irqrestore(&priv->lock, flags);
441 return;
442 }
443
444 priv->write_urb_in_use = 1;
445
446 spin_unlock_irqrestore(&priv->lock, flags);
447
Harvey Harrison441b62c2008-03-03 16:08:34 -0800448 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300449 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 port->write_urb->transfer_buffer_length = count;
452 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300453 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300455 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800456 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100458 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 }
460
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700461 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462}
463
Alan Cox95da3102008-07-22 11:09:07 +0100464static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
465 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300466{
467 struct pl2303_private *priv = usb_get_serial_port_data(port);
468 unsigned long flags;
469
Harvey Harrison441b62c2008-03-03 16:08:34 -0800470 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300471
472 if (!count)
473 return count;
474
475 spin_lock_irqsave(&priv->lock, flags);
476 count = pl2303_buf_put(priv->buf, buf, count);
477 spin_unlock_irqrestore(&priv->lock, flags);
478
479 pl2303_send(port);
480
481 return count;
482}
483
Alan Cox95da3102008-07-22 11:09:07 +0100484static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
Alan Cox95da3102008-07-22 11:09:07 +0100486 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 struct pl2303_private *priv = usb_get_serial_port_data(port);
488 int room = 0;
489 unsigned long flags;
490
Harvey Harrison441b62c2008-03-03 16:08:34 -0800491 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 spin_lock_irqsave(&priv->lock, flags);
494 room = pl2303_buf_space_avail(priv->buf);
495 spin_unlock_irqrestore(&priv->lock, flags);
496
Harvey Harrison441b62c2008-03-03 16:08:34 -0800497 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return room;
499}
500
Alan Cox95da3102008-07-22 11:09:07 +0100501static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
Alan Cox95da3102008-07-22 11:09:07 +0100503 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 struct pl2303_private *priv = usb_get_serial_port_data(port);
505 int chars = 0;
506 unsigned long flags;
507
Harvey Harrison441b62c2008-03-03 16:08:34 -0800508 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 spin_lock_irqsave(&priv->lock, flags);
511 chars = pl2303_buf_data_avail(priv->buf);
512 spin_unlock_irqrestore(&priv->lock, flags);
513
Harvey Harrison441b62c2008-03-03 16:08:34 -0800514 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 return chars;
516}
517
Alan Cox95da3102008-07-22 11:09:07 +0100518static void pl2303_set_termios(struct tty_struct *tty,
519 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
521 struct usb_serial *serial = port->serial;
522 struct pl2303_private *priv = usb_get_serial_port_data(port);
523 unsigned long flags;
524 unsigned int cflag;
525 unsigned char *buf;
526 int baud;
527 int i;
528 u8 control;
529
Harvey Harrison441b62c2008-03-03 16:08:34 -0800530 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Alan Coxbf5e5832008-01-08 14:55:51 +0000532 /* The PL2303 is reported to lose bytes if you change
533 serial settings even to the same values as before. Thus
534 we actually need to filter in this specific case */
535
Alan Cox95da3102008-07-22 11:09:07 +0100536 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000537 return;
538
Alan Cox95da3102008-07-22 11:09:07 +0100539 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Thiago Galesi372db8a2006-07-31 15:39:27 -0300541 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800543 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100544 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100545 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 return;
547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Thiago Galesi372db8a2006-07-31 15:39:27 -0300549 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
550 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
551 0, 0, buf, 7, 100);
552 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
553 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 if (cflag & CSIZE) {
556 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100557 case CS5:
558 buf[6] = 5;
559 break;
560 case CS6:
561 buf[6] = 6;
562 break;
563 case CS7:
564 buf[6] = 7;
565 break;
566 default:
567 case CS8:
568 buf[6] = 8;
569 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800571 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 }
573
Alan Cox95da3102008-07-22 11:09:07 +0100574 baud = tty_get_baud_rate(tty);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800575 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 if (baud) {
577 buf[0] = baud & 0xff;
578 buf[1] = (baud >> 8) & 0xff;
579 buf[2] = (baud >> 16) & 0xff;
580 buf[3] = (baud >> 24) & 0xff;
581 }
582
583 /* For reference buf[4]=0 is 1 stop bits */
584 /* For reference buf[4]=1 is 1.5 stop bits */
585 /* For reference buf[4]=2 is 2 stop bits */
586 if (cflag & CSTOPB) {
587 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800588 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 } else {
590 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800591 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 }
593
594 if (cflag & PARENB) {
595 /* For reference buf[5]=0 is none parity */
596 /* For reference buf[5]=1 is odd parity */
597 /* For reference buf[5]=2 is even parity */
598 /* For reference buf[5]=3 is mark parity */
599 /* For reference buf[5]=4 is space parity */
600 if (cflag & PARODD) {
601 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800602 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 } else {
604 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800605 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 }
607 } else {
608 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800609 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 }
611
Thiago Galesi372db8a2006-07-31 15:39:27 -0300612 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
613 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
614 0, 0, buf, 7, 100);
615 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 /* change control lines if we are switching to or from B0 */
618 spin_lock_irqsave(&priv->lock, flags);
619 control = priv->line_control;
620 if ((cflag & CBAUD) == B0)
621 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
622 else
623 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
624 if (control != priv->line_control) {
625 control = priv->line_control;
626 spin_unlock_irqrestore(&priv->lock, flags);
627 set_control_lines(serial->dev, control);
628 } else {
629 spin_unlock_irqrestore(&priv->lock, flags);
630 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
633
Thiago Galesi372db8a2006-07-31 15:39:27 -0300634 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
635 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
636 0, 0, buf, 7, 100);
637 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
639
640 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800642 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800644 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200645 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800646 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 }
648
Alan Coxdf64c472007-10-15 20:54:47 +0100649 /* FIXME: Need to read back resulting baud rate */
650 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100651 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100652
Thiago Galesi372db8a2006-07-31 15:39:27 -0300653 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654}
655
Alan Cox335f8512009-06-11 12:26:29 +0100656static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
Thiago Galesi572d3132006-07-29 10:46:37 -0300657{
658 struct pl2303_private *priv = usb_get_serial_port_data(port);
659 unsigned long flags;
Alan Cox335f8512009-06-11 12:26:29 +0100660 u8 control;
661
662 spin_lock_irqsave(&priv->lock, flags);
663 /* Change DTR and RTS */
664 if (on)
665 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
666 else
667 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
668 control = priv->line_control;
669 spin_unlock_irqrestore(&priv->lock, flags);
670 set_control_lines(port->serial->dev, control);
671}
672
673static void pl2303_close(struct usb_serial_port *port)
674{
675 struct pl2303_private *priv = usb_get_serial_port_data(port);
676 unsigned long flags;
Thiago Galesi572d3132006-07-29 10:46:37 -0300677
Harvey Harrison441b62c2008-03-03 16:08:34 -0800678 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300679
Thiago Galesi572d3132006-07-29 10:46:37 -0300680 spin_lock_irqsave(&priv->lock, flags);
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
Thiago Galesi572d3132006-07-29 10:46:37 -0300685 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800686 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300687 usb_kill_urb(port->write_urb);
688 usb_kill_urb(port->read_urb);
689 usb_kill_urb(port->interrupt_in_urb);
690
Thiago Galesi572d3132006-07-29 10:46:37 -0300691}
692
Alan Cox95da3102008-07-22 11:09:07 +0100693static int pl2303_open(struct tty_struct *tty,
694 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Alan Cox606d0992006-12-08 02:38:45 -0800696 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 struct usb_serial *serial = port->serial;
698 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 int result;
700
Harvey Harrison441b62c2008-03-03 16:08:34 -0800701 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Dariusz M16948992005-07-28 18:06:13 +0200703 if (priv->type != HX) {
704 usb_clear_halt(serial->dev, port->write_urb->pipe);
705 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800706 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800708 pl2303_vendor_write(8, 0, serial);
709 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 }
711
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100713 if (tty)
714 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Alan Cox3a0f43e2008-07-22 11:14:49 +0100716 /* FIXME: need to assert RTS and DTR if CRTSCTS off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
Harvey Harrison441b62c2008-03-03 16:08:34 -0800718 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300720 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300722 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800723 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100724 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return -EPROTO;
726 }
727
Harvey Harrison441b62c2008-03-03 16:08:34 -0800728 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300730 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300732 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800733 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100734 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return -EPROTO;
736 }
Alan Cox335f8512009-06-11 12:26:29 +0100737 port->port.drain_delay = 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return 0;
739}
740
Alan Cox95da3102008-07-22 11:09:07 +0100741static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300742 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
Alan Cox95da3102008-07-22 11:09:07 +0100744 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 struct pl2303_private *priv = usb_get_serial_port_data(port);
746 unsigned long flags;
747 u8 control;
748
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700749 if (!usb_get_intfdata(port->serial->interface))
750 return -ENODEV;
751
Thiago Galesi372db8a2006-07-31 15:39:27 -0300752 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if (set & TIOCM_RTS)
754 priv->line_control |= CONTROL_RTS;
755 if (set & TIOCM_DTR)
756 priv->line_control |= CONTROL_DTR;
757 if (clear & TIOCM_RTS)
758 priv->line_control &= ~CONTROL_RTS;
759 if (clear & TIOCM_DTR)
760 priv->line_control &= ~CONTROL_DTR;
761 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300762 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Thiago Galesi372db8a2006-07-31 15:39:27 -0300764 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765}
766
Alan Cox95da3102008-07-22 11:09:07 +0100767static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
Alan Cox95da3102008-07-22 11:09:07 +0100769 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 struct pl2303_private *priv = usb_get_serial_port_data(port);
771 unsigned long flags;
772 unsigned int mcr;
773 unsigned int status;
774 unsigned int result;
775
Harvey Harrison441b62c2008-03-03 16:08:34 -0800776 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700778 if (!usb_get_intfdata(port->serial->interface))
779 return -ENODEV;
780
Thiago Galesi372db8a2006-07-31 15:39:27 -0300781 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 mcr = priv->line_control;
783 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300784 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
786 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
787 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
788 | ((status & UART_CTS) ? TIOCM_CTS : 0)
789 | ((status & UART_DSR) ? TIOCM_DSR : 0)
790 | ((status & UART_RING) ? TIOCM_RI : 0)
791 | ((status & UART_DCD) ? TIOCM_CD : 0);
792
Harvey Harrison441b62c2008-03-03 16:08:34 -0800793 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 return result;
796}
797
Alan Cox335f8512009-06-11 12:26:29 +0100798static int pl2303_carrier_raised(struct usb_serial_port *port)
799{
800 struct pl2303_private *priv = usb_get_serial_port_data(port);
801 if (priv->line_status & UART_DCD)
802 return 1;
803 return 0;
804}
805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
807{
808 struct pl2303_private *priv = usb_get_serial_port_data(port);
809 unsigned long flags;
810 unsigned int prevstatus;
811 unsigned int status;
812 unsigned int changed;
813
Thiago Galesi372db8a2006-07-31 15:39:27 -0300814 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300816 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 while (1) {
819 interruptible_sleep_on(&priv->delta_msr_wait);
820 /* see if a signal did it */
821 if (signal_pending(current))
822 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300823
824 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300826 spin_unlock_irqrestore(&priv->lock, flags);
827
Alan Cox3a0f43e2008-07-22 11:14:49 +0100828 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
831 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
832 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100833 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 return 0;
835 }
836 prevstatus = status;
837 }
838 /* NOTREACHED */
839 return 0;
840}
841
Alan Cox95da3102008-07-22 11:09:07 +0100842static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300843 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844{
Alan Cox95da3102008-07-22 11:09:07 +0100845 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800846 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100849 case TIOCMIWAIT:
850 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
851 return wait_modem_info(port, arg);
852 default:
853 dbg("%s not supported = 0x%04x", __func__, cmd);
854 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return -ENOIOCTLCMD;
857}
858
Alan Cox95da3102008-07-22 11:09:07 +0100859static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
Alan Cox95da3102008-07-22 11:09:07 +0100861 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 struct usb_serial *serial = port->serial;
863 u16 state;
864 int result;
865
Harvey Harrison441b62c2008-03-03 16:08:34 -0800866 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 if (break_state == 0)
869 state = BREAK_OFF;
870 else
871 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100872 dbg("%s - turning break %s", __func__,
873 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Thiago Galesi372db8a2006-07-31 15:39:27 -0300875 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
876 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
877 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800879 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880}
881
Alan Sternf9c99bb2009-06-02 11:53:55 -0400882static void pl2303_release(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 int i;
885 struct pl2303_private *priv;
886
Harvey Harrison441b62c2008-03-03 16:08:34 -0800887 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
889 for (i = 0; i < serial->num_ports; ++i) {
890 priv = usb_get_serial_port_data(serial->port[i]);
891 if (priv) {
892 pl2303_buf_free(priv->buf);
893 kfree(priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700898static void pl2303_update_line_status(struct usb_serial_port *port,
899 unsigned char *data,
900 unsigned int actual_length)
901{
902
903 struct pl2303_private *priv = usb_get_serial_port_data(port);
904 unsigned long flags;
905 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200906 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300907 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700908
Thiago Galesi9c537612006-07-29 10:47:12 -0300909 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
910 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
911
912
913 if (idv == SIEMENS_VENDOR_ID) {
914 if (idp == SIEMENS_PRODUCT_ID_X65 ||
915 idp == SIEMENS_PRODUCT_ID_SX1 ||
916 idp == SIEMENS_PRODUCT_ID_X75) {
917
918 length = 1;
919 status_idx = 0;
920 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700921 }
922
923 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300924 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700925
Alan Cox3a0f43e2008-07-22 11:14:49 +0100926 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700927 spin_lock_irqsave(&priv->lock, flags);
928 priv->line_status = data[status_idx];
929 spin_unlock_irqrestore(&priv->lock, flags);
Jason Wessel430eb0d2009-05-29 13:34:16 -0500930 if (priv->line_status & UART_BREAK_ERROR)
931 usb_serial_handle_break(port);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300932 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700933}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
David Howells7d12e782006-10-05 14:55:46 +0100935static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936{
Ming Leicdc97792008-02-24 18:41:47 +0800937 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700939 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700940 int status = urb->status;
941 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Harvey Harrison441b62c2008-03-03 16:08:34 -0800943 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700945 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 case 0:
947 /* success */
948 break;
949 case -ECONNRESET:
950 case -ENOENT:
951 case -ESHUTDOWN:
952 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800953 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700954 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 return;
956 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800957 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700958 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 goto exit;
960 }
961
Harvey Harrison441b62c2008-03-03 16:08:34 -0800962 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300963 urb->actual_length, urb->transfer_buffer);
964
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700965 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700968 retval = usb_submit_urb(urb, GFP_ATOMIC);
969 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300970 dev_err(&urb->dev->dev,
971 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800972 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973}
974
Alan Coxd4fc4a72009-07-09 13:36:58 +0100975static void pl2303_push_data(struct tty_struct *tty,
976 struct usb_serial_port *port, struct urb *urb,
977 u8 line_status)
978{
979 unsigned char *data = urb->transfer_buffer;
980 /* get tty_flag from status */
981 char tty_flag = TTY_NORMAL;
982 /* break takes precedence over parity, */
983 /* which takes precedence over framing errors */
984 if (line_status & UART_BREAK_ERROR)
985 tty_flag = TTY_BREAK;
986 else if (line_status & UART_PARITY_ERROR)
987 tty_flag = TTY_PARITY;
988 else if (line_status & UART_FRAME_ERROR)
989 tty_flag = TTY_FRAME;
990 dbg("%s - tty_flag = %d", __func__, tty_flag);
991
992 tty_buffer_request_room(tty, urb->actual_length + 1);
993 /* overrun is special, not associated with a char */
994 if (line_status & UART_OVERRUN_ERROR)
995 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
996 if (port->console && port->sysrq) {
997 int i;
998 for (i = 0; i < urb->actual_length; ++i)
999 if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
1000 tty_insert_flip_char(tty, data[i], tty_flag);
1001 } else
1002 tty_insert_flip_string(tty, data, urb->actual_length);
1003 tty_flip_buffer_push(tty);
1004}
1005
David Howells7d12e782006-10-05 14:55:46 +01001006static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007{
Ming Leicdc97792008-02-24 18:41:47 +08001008 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 struct pl2303_private *priv = usb_get_serial_port_data(port);
1010 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001013 int status = urb->status;
1014 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Harvey Harrison441b62c2008-03-03 16:08:34 -08001016 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001018 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001019 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001020 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001021 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 return;
1023 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001024 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001025 /* PL2303 mysteriously fails with -EPROTO reschedule
1026 * the read */
1027 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001028 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 urb->dev = port->serial->dev;
1030 result = usb_submit_urb(urb, GFP_ATOMIC);
1031 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001032 dev_err(&urb->dev->dev, "%s - failed"
1033 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001034 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return;
1036 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001037 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return;
1039 }
1040
Harvey Harrison441b62c2008-03-03 16:08:34 -08001041 usb_serial_debug_data(debug, &port->dev, __func__,
Alan Coxd4fc4a72009-07-09 13:36:58 +01001042 urb->actual_length, urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001045 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1047 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001048 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Alan Cox4a90f092008-10-13 10:39:46 +01001050 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 if (tty && urb->actual_length) {
Alan Coxd4fc4a72009-07-09 13:36:58 +01001052 pl2303_push_data(tty, port, urb, line_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
Alan Cox4a90f092008-10-13 10:39:46 +01001054 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001056 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 urb->dev = port->serial->dev;
1058 result = usb_submit_urb(urb, GFP_ATOMIC);
1059 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001060 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001061 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
1063
1064 return;
1065}
1066
David Howells7d12e782006-10-05 14:55:46 +01001067static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
Ming Leicdc97792008-02-24 18:41:47 +08001069 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 struct pl2303_private *priv = usb_get_serial_port_data(port);
1071 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001072 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Harvey Harrison441b62c2008-03-03 16:08:34 -08001074 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001076 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 case 0:
1078 /* success */
1079 break;
1080 case -ECONNRESET:
1081 case -ENOENT:
1082 case -ESHUTDOWN:
1083 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001084 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001085 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 priv->write_urb_in_use = 0;
1087 return;
1088 default:
1089 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001090 dbg("%s - Overflow in write", __func__);
1091 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001092 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 port->write_urb->transfer_buffer_length = 1;
1094 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001095 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001097 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001098 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 else
1100 return;
1101 }
1102
1103 priv->write_urb_in_use = 0;
1104
1105 /* send any buffered data */
1106 pl2303_send(port);
1107}
1108
Thiago Galesi572d3132006-07-29 10:46:37 -03001109/* All of the device info needed for the PL2303 SIO serial converter */
1110static struct usb_serial_driver pl2303_device = {
1111 .driver = {
1112 .owner = THIS_MODULE,
1113 .name = "pl2303",
1114 },
1115 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001116 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001117 .num_ports = 1,
1118 .open = pl2303_open,
1119 .close = pl2303_close,
Alan Cox335f8512009-06-11 12:26:29 +01001120 .dtr_rts = pl2303_dtr_rts,
1121 .carrier_raised = pl2303_carrier_raised,
Thiago Galesi572d3132006-07-29 10:46:37 -03001122 .write = pl2303_write,
1123 .ioctl = pl2303_ioctl,
1124 .break_ctl = pl2303_break_ctl,
1125 .set_termios = pl2303_set_termios,
1126 .tiocmget = pl2303_tiocmget,
1127 .tiocmset = pl2303_tiocmset,
1128 .read_bulk_callback = pl2303_read_bulk_callback,
1129 .read_int_callback = pl2303_read_int_callback,
1130 .write_bulk_callback = pl2303_write_bulk_callback,
1131 .write_room = pl2303_write_room,
1132 .chars_in_buffer = pl2303_chars_in_buffer,
1133 .attach = pl2303_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -04001134 .release = pl2303_release,
Thiago Galesi572d3132006-07-29 10:46:37 -03001135};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Thiago Galesi372db8a2006-07-31 15:39:27 -03001137static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
1139 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 retval = usb_serial_register(&pl2303_device);
1142 if (retval)
1143 goto failed_usb_serial_register;
1144 retval = usb_register(&pl2303_driver);
1145 if (retval)
1146 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001147 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return 0;
1149failed_usb_register:
1150 usb_serial_deregister(&pl2303_device);
1151failed_usb_serial_register:
1152 return retval;
1153}
1154
Thiago Galesi372db8a2006-07-31 15:39:27 -03001155static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001157 usb_deregister(&pl2303_driver);
1158 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159}
1160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161module_init(pl2303_init);
1162module_exit(pl2303_exit);
1163
1164MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165MODULE_LICENSE("GPL");
1166
1167module_param(debug, bool, S_IRUGO | S_IWUSR);
1168MODULE_PARM_DESC(debug, "Debug enabled or not");
1169