blob: 2a0dd1b50dc43b8dc884f0964c4f6624bfac1921 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Prolific PL2303 USB to serial adaptor driver
3 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07004 * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2003 IBM Corp.
6 *
7 * Original driver for 2.2.x by anonymous
8 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07009 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 *
13 * See Documentation/usb/usb-serial.txt for more information on using this driver
14 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 */
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/tty.h>
22#include <linux/tty_driver.h>
23#include <linux/tty_flip.h>
24#include <linux/serial.h>
25#include <linux/module.h>
26#include <linux/moduleparam.h>
27#include <linux/spinlock.h>
28#include <asm/uaccess.h>
29#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070030#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include "pl2303.h"
32
33/*
34 * Version Information
35 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
37
38static int debug;
39
40#define PL2303_CLOSING_WAIT (30*HZ)
41
42#define PL2303_BUF_SIZE 1024
43#define PL2303_TMP_BUF_SIZE 1024
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045struct pl2303_buf {
46 unsigned int buf_size;
47 char *buf_buf;
48 char *buf_get;
49 char *buf_put;
50};
51
52static struct usb_device_id id_table [] = {
53 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
54 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100055 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
57 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070058 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053059 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050060 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090062 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
64 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
65 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
66 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
67 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080068 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
70 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
71 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
72 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
73 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
74 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
75 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
76 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080077 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020080 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070081 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010082 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
83 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010084 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010085 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080086 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040087 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100088 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020089 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090090 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090091 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Piotr Roszatycki002e8f22008-01-02 11:16:57 +010092 { USB_DEVICE(HL340_VENDOR_ID, HL340_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
119#define BREAK_REQUEST 0x23
120#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;
157 u8 termios_initialized;
158 enum pl2303_type type;
159};
160
Thiago Galesi572d3132006-07-29 10:46:37 -0300161/*
162 * pl2303_buf_alloc
163 *
164 * Allocate a circular buffer and all associated memory.
165 */
166static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
167{
168 struct pl2303_buf *pb;
169
170 if (size == 0)
171 return NULL;
172
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800173 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300174 if (pb == NULL)
175 return NULL;
176
177 pb->buf_buf = kmalloc(size, GFP_KERNEL);
178 if (pb->buf_buf == NULL) {
179 kfree(pb);
180 return NULL;
181 }
182
183 pb->buf_size = size;
184 pb->buf_get = pb->buf_put = pb->buf_buf;
185
186 return pb;
187}
188
189/*
190 * pl2303_buf_free
191 *
192 * Free the buffer and all associated memory.
193 */
194static void pl2303_buf_free(struct pl2303_buf *pb)
195{
196 if (pb) {
197 kfree(pb->buf_buf);
198 kfree(pb);
199 }
200}
201
202/*
203 * pl2303_buf_clear
204 *
205 * Clear out all data in the circular buffer.
206 */
207static void pl2303_buf_clear(struct pl2303_buf *pb)
208{
209 if (pb != NULL)
210 pb->buf_get = pb->buf_put;
211 /* equivalent to a get of all data available */
212}
213
214/*
215 * pl2303_buf_data_avail
216 *
217 * Return the number of bytes of data available in the circular
218 * buffer.
219 */
220static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
221{
222 if (pb == NULL)
223 return 0;
224
225 return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
226}
227
228/*
229 * pl2303_buf_space_avail
230 *
231 * Return the number of bytes of space available in the circular
232 * buffer.
233 */
234static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
235{
236 if (pb == NULL)
237 return 0;
238
239 return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
240}
241
242/*
243 * pl2303_buf_put
244 *
245 * Copy data data from a user buffer and put it into the circular buffer.
246 * Restrict to the amount of space available.
247 *
248 * Return the number of bytes copied.
249 */
250static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
251 unsigned int count)
252{
253 unsigned int len;
254
255 if (pb == NULL)
256 return 0;
257
258 len = pl2303_buf_space_avail(pb);
259 if (count > len)
260 count = len;
261
262 if (count == 0)
263 return 0;
264
265 len = pb->buf_buf + pb->buf_size - pb->buf_put;
266 if (count > len) {
267 memcpy(pb->buf_put, buf, len);
268 memcpy(pb->buf_buf, buf+len, count - len);
269 pb->buf_put = pb->buf_buf + count - len;
270 } else {
271 memcpy(pb->buf_put, buf, count);
272 if (count < len)
273 pb->buf_put += count;
274 else /* count == len */
275 pb->buf_put = pb->buf_buf;
276 }
277
278 return count;
279}
280
281/*
282 * pl2303_buf_get
283 *
284 * Get data from the circular buffer and copy to the given buffer.
285 * Restrict to the amount of data available.
286 *
287 * Return the number of bytes copied.
288 */
289static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
290 unsigned int count)
291{
292 unsigned int len;
293
294 if (pb == NULL)
295 return 0;
296
297 len = pl2303_buf_data_avail(pb);
298 if (count > len)
299 count = len;
300
301 if (count == 0)
302 return 0;
303
304 len = pb->buf_buf + pb->buf_size - pb->buf_get;
305 if (count > len) {
306 memcpy(buf, pb->buf_get, len);
307 memcpy(buf+len, pb->buf_buf, count - len);
308 pb->buf_get = pb->buf_buf + count - len;
309 } else {
310 memcpy(buf, pb->buf_get, count);
311 if (count < len)
312 pb->buf_get += count;
313 else /* count == len */
314 pb->buf_get = pb->buf_buf;
315 }
316
317 return count;
318}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Sarah Sharpeb44da02007-12-14 14:08:00 -0800320static int pl2303_vendor_read(__u16 value, __u16 index,
321 struct usb_serial *serial, unsigned char *buf)
322{
323 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
324 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
325 value, index, buf, 1, 100);
326 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
327 VENDOR_READ_REQUEST, value, index, res, buf[0]);
328 return res;
329}
330
331static int pl2303_vendor_write(__u16 value, __u16 index,
332 struct usb_serial *serial)
333{
334 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
335 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
336 value, index, NULL, 0, 100);
337 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
338 VENDOR_WRITE_REQUEST, value, index, res);
339 return res;
340}
341
Thiago Galesi372db8a2006-07-31 15:39:27 -0300342static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
344 struct pl2303_private *priv;
345 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800346 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 int i;
348
Sarah Sharp3e152502007-12-14 14:08:35 -0800349 buf = kmalloc(10, GFP_KERNEL);
350 if (buf == NULL)
351 return -ENOMEM;
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if (serial->dev->descriptor.bDeviceClass == 0x02)
354 type = type_0;
355 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
356 type = HX;
357 else if (serial->dev->descriptor.bDeviceClass == 0x00)
358 type = type_1;
359 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
360 type = type_1;
361 dbg("device type: %d", type);
362
363 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100364 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (!priv)
366 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 spin_lock_init(&priv->lock);
368 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
369 if (priv->buf == NULL) {
370 kfree(priv);
371 goto cleanup;
372 }
373 init_waitqueue_head(&priv->delta_msr_wait);
374 priv->type = type;
375 usb_set_serial_port_data(serial->port[i], priv);
376 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800377
378 pl2303_vendor_read(0x8484, 0, serial, buf);
379 pl2303_vendor_write(0x0404, 0, serial);
380 pl2303_vendor_read(0x8484, 0, serial, buf);
381 pl2303_vendor_read(0x8383, 0, serial, buf);
382 pl2303_vendor_read(0x8484, 0, serial, buf);
383 pl2303_vendor_write(0x0404, 1, serial);
384 pl2303_vendor_read(0x8484, 0, serial, buf);
385 pl2303_vendor_read(0x8383, 0, serial, buf);
386 pl2303_vendor_write(0, 1, serial);
387 pl2303_vendor_write(1, 0, serial);
388 if (type == HX)
389 pl2303_vendor_write(2, 0x44, serial);
390 else
391 pl2303_vendor_write(2, 0x24, serial);
392
393 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return 0;
395
396cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800397 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 for (--i; i>=0; --i) {
399 priv = usb_get_serial_port_data(serial->port[i]);
400 pl2303_buf_free(priv->buf);
401 kfree(priv);
402 usb_set_serial_port_data(serial->port[i], NULL);
403 }
404 return -ENOMEM;
405}
406
Thiago Galesi372db8a2006-07-31 15:39:27 -0300407static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 int retval;
410
Thiago Galesi372db8a2006-07-31 15:39:27 -0300411 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
412 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
413 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800414 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return retval;
416}
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static void pl2303_send(struct usb_serial_port *port)
419{
420 int count, result;
421 struct pl2303_private *priv = usb_get_serial_port_data(port);
422 unsigned long flags;
423
Harvey Harrison441b62c2008-03-03 16:08:34 -0800424 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 spin_lock_irqsave(&priv->lock, flags);
427
428 if (priv->write_urb_in_use) {
429 spin_unlock_irqrestore(&priv->lock, flags);
430 return;
431 }
432
433 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300434 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 if (count == 0) {
437 spin_unlock_irqrestore(&priv->lock, flags);
438 return;
439 }
440
441 priv->write_urb_in_use = 1;
442
443 spin_unlock_irqrestore(&priv->lock, flags);
444
Harvey Harrison441b62c2008-03-03 16:08:34 -0800445 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300446 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448 port->write_urb->transfer_buffer_length = count;
449 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300450 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300452 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800453 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 priv->write_urb_in_use = 0;
455 // TODO: reschedule pl2303_send
456 }
457
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700458 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
Thiago Galesi572d3132006-07-29 10:46:37 -0300461static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
462 int count)
463{
464 struct pl2303_private *priv = usb_get_serial_port_data(port);
465 unsigned long flags;
466
Harvey Harrison441b62c2008-03-03 16:08:34 -0800467 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300468
469 if (!count)
470 return count;
471
472 spin_lock_irqsave(&priv->lock, flags);
473 count = pl2303_buf_put(priv->buf, buf, count);
474 spin_unlock_irqrestore(&priv->lock, flags);
475
476 pl2303_send(port);
477
478 return count;
479}
480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481static int pl2303_write_room(struct usb_serial_port *port)
482{
483 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
497static int pl2303_chars_in_buffer(struct usb_serial_port *port)
498{
499 struct pl2303_private *priv = usb_get_serial_port_data(port);
500 int chars = 0;
501 unsigned long flags;
502
Harvey Harrison441b62c2008-03-03 16:08:34 -0800503 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 spin_lock_irqsave(&priv->lock, flags);
506 chars = pl2303_buf_data_avail(priv->buf);
507 spin_unlock_irqrestore(&priv->lock, flags);
508
Harvey Harrison441b62c2008-03-03 16:08:34 -0800509 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 return chars;
511}
512
Thiago Galesi372db8a2006-07-31 15:39:27 -0300513static void pl2303_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800514 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 struct usb_serial *serial = port->serial;
517 struct pl2303_private *priv = usb_get_serial_port_data(port);
518 unsigned long flags;
519 unsigned int cflag;
520 unsigned char *buf;
521 int baud;
522 int i;
523 u8 control;
524
Harvey Harrison441b62c2008-03-03 16:08:34 -0800525 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 spin_lock_irqsave(&priv->lock, flags);
528 if (!priv->termios_initialized) {
529 *(port->tty->termios) = tty_std_termios;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300530 port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
531 HUPCL | CLOCAL;
Alan Coxdf64c472007-10-15 20:54:47 +0100532 port->tty->termios->c_ispeed = 9600;
533 port->tty->termios->c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 priv->termios_initialized = 1;
535 }
536 spin_unlock_irqrestore(&priv->lock, flags);
537
Alan Coxbf5e5832008-01-08 14:55:51 +0000538 /* The PL2303 is reported to lose bytes if you change
539 serial settings even to the same values as before. Thus
540 we actually need to filter in this specific case */
541
542 if (!tty_termios_hw_change(port->tty->termios, old_termios))
543 return;
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 cflag = port->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Thiago Galesi372db8a2006-07-31 15:39:27 -0300547 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800549 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100550 /* Report back no change occurred */
551 *port->tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 return;
553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Thiago Galesi372db8a2006-07-31 15:39:27 -0300555 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
556 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
557 0, 0, buf, 7, 100);
558 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
559 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
561 if (cflag & CSIZE) {
562 switch (cflag & CSIZE) {
563 case CS5: buf[6] = 5; break;
564 case CS6: buf[6] = 6; break;
565 case CS7: buf[6] = 7; break;
566 default:
567 case CS8: buf[6] = 8; break;
568 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800569 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
571
Alan Coxe0c79f52007-07-09 12:03:10 -0700572 baud = tty_get_baud_rate(port->tty);;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800573 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 if (baud) {
575 buf[0] = baud & 0xff;
576 buf[1] = (baud >> 8) & 0xff;
577 buf[2] = (baud >> 16) & 0xff;
578 buf[3] = (baud >> 24) & 0xff;
579 }
580
581 /* For reference buf[4]=0 is 1 stop bits */
582 /* For reference buf[4]=1 is 1.5 stop bits */
583 /* For reference buf[4]=2 is 2 stop bits */
584 if (cflag & CSTOPB) {
585 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800586 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 } else {
588 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800589 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
591
592 if (cflag & PARENB) {
593 /* For reference buf[5]=0 is none parity */
594 /* For reference buf[5]=1 is odd parity */
595 /* For reference buf[5]=2 is even parity */
596 /* For reference buf[5]=3 is mark parity */
597 /* For reference buf[5]=4 is space parity */
598 if (cflag & PARODD) {
599 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800600 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 } else {
602 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800603 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 }
605 } else {
606 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800607 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
609
Thiago Galesi372db8a2006-07-31 15:39:27 -0300610 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
611 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
612 0, 0, buf, 7, 100);
613 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 /* change control lines if we are switching to or from B0 */
616 spin_lock_irqsave(&priv->lock, flags);
617 control = priv->line_control;
618 if ((cflag & CBAUD) == B0)
619 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
620 else
621 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
622 if (control != priv->line_control) {
623 control = priv->line_control;
624 spin_unlock_irqrestore(&priv->lock, flags);
625 set_control_lines(serial->dev, control);
626 } else {
627 spin_unlock_irqrestore(&priv->lock, flags);
628 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
631
Thiago Galesi372db8a2006-07-31 15:39:27 -0300632 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
633 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
634 0, 0, buf, 7, 100);
635 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
637
638 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800640 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800642 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200643 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800644 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
646
Alan Coxdf64c472007-10-15 20:54:47 +0100647 /* FIXME: Need to read back resulting baud rate */
648 if (baud)
649 tty_encode_baud_rate(port->tty, baud, baud);
650
Thiago Galesi372db8a2006-07-31 15:39:27 -0300651 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652}
653
Thiago Galesi572d3132006-07-29 10:46:37 -0300654static void pl2303_close(struct usb_serial_port *port, struct file *filp)
655{
656 struct pl2303_private *priv = usb_get_serial_port_data(port);
657 unsigned long flags;
658 unsigned int c_cflag;
659 int bps;
660 long timeout;
661 wait_queue_t wait;
662
Harvey Harrison441b62c2008-03-03 16:08:34 -0800663 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300664
665 /* wait for data to drain from the buffer */
666 spin_lock_irqsave(&priv->lock, flags);
667 timeout = PL2303_CLOSING_WAIT;
668 init_waitqueue_entry(&wait, current);
669 add_wait_queue(&port->tty->write_wait, &wait);
670 for (;;) {
671 set_current_state(TASK_INTERRUPTIBLE);
672 if (pl2303_buf_data_avail(priv->buf) == 0 ||
673 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100674 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300675 break;
676 spin_unlock_irqrestore(&priv->lock, flags);
677 timeout = schedule_timeout(timeout);
678 spin_lock_irqsave(&priv->lock, flags);
679 }
680 set_current_state(TASK_RUNNING);
681 remove_wait_queue(&port->tty->write_wait, &wait);
682 /* clear out any remaining data in the buffer */
683 pl2303_buf_clear(priv->buf);
684 spin_unlock_irqrestore(&priv->lock, flags);
685
686 /* wait for characters to drain from the device */
687 /* (this is long enough for the entire 256 byte */
688 /* pl2303 hardware buffer to drain with no flow */
689 /* control for data rates of 1200 bps or more, */
690 /* for lower rates we should really know how much */
691 /* data is in the buffer to compute a delay */
692 /* that is not unnecessarily long) */
693 bps = tty_get_baud_rate(port->tty);
694 if (bps > 1200)
695 timeout = max((HZ*2560)/bps,HZ/10);
696 else
697 timeout = 2*HZ;
698 schedule_timeout_interruptible(timeout);
699
700 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800701 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300702 usb_kill_urb(port->write_urb);
703 usb_kill_urb(port->read_urb);
704 usb_kill_urb(port->interrupt_in_urb);
705
706 if (port->tty) {
707 c_cflag = port->tty->termios->c_cflag;
708 if (c_cflag & HUPCL) {
709 /* drop DTR and RTS */
710 spin_lock_irqsave(&priv->lock, flags);
711 priv->line_control = 0;
712 spin_unlock_irqrestore(&priv->lock, flags);
713 set_control_lines(port->serial->dev, 0);
714 }
715 }
716}
717
Thiago Galesi372db8a2006-07-31 15:39:27 -0300718static int pl2303_open(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 */
737 if (port->tty) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300738 pl2303_set_termios(port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
740
741 //FIXME: need to assert RTS and DTR if CRTSCTS off
742
Harvey Harrison441b62c2008-03-03 16:08:34 -0800743 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300745 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300747 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800748 " error %d\n", __func__, result);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300749 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 return -EPROTO;
751 }
752
Harvey Harrison441b62c2008-03-03 16:08:34 -0800753 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300755 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300757 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800758 " error %d\n", __func__, result);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300759 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return -EPROTO;
761 }
762 return 0;
763}
764
Thiago Galesi372db8a2006-07-31 15:39:27 -0300765static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
766 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
768 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
Thiago Galesi372db8a2006-07-31 15:39:27 -0300790static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
792 struct pl2303_private *priv = usb_get_serial_port_data(port);
793 unsigned long flags;
794 unsigned int mcr;
795 unsigned int status;
796 unsigned int result;
797
Harvey Harrison441b62c2008-03-03 16:08:34 -0800798 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700800 if (!usb_get_intfdata(port->serial->interface))
801 return -ENODEV;
802
Thiago Galesi372db8a2006-07-31 15:39:27 -0300803 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 mcr = priv->line_control;
805 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300806 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
809 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
810 | ((status & UART_CTS) ? TIOCM_CTS : 0)
811 | ((status & UART_DSR) ? TIOCM_DSR : 0)
812 | ((status & UART_RING) ? TIOCM_RI : 0)
813 | ((status & UART_DCD) ? TIOCM_CD : 0);
814
Harvey Harrison441b62c2008-03-03 16:08:34 -0800815 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 return result;
818}
819
820static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
821{
822 struct pl2303_private *priv = usb_get_serial_port_data(port);
823 unsigned long flags;
824 unsigned int prevstatus;
825 unsigned int status;
826 unsigned int changed;
827
Thiago Galesi372db8a2006-07-31 15:39:27 -0300828 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300830 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 while (1) {
833 interruptible_sleep_on(&priv->delta_msr_wait);
834 /* see if a signal did it */
835 if (signal_pending(current))
836 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300837
838 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300840 spin_unlock_irqrestore(&priv->lock, flags);
841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 changed=prevstatus^status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300843
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
845 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
846 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
847 ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
848 return 0;
849 }
850 prevstatus = status;
851 }
852 /* NOTREACHED */
853 return 0;
854}
855
Thiago Galesi372db8a2006-07-31 15:39:27 -0300856static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
857 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858{
Harvey Harrison441b62c2008-03-03 16:08:34 -0800859 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
861 switch (cmd) {
862 case TIOCMIWAIT:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800863 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return wait_modem_info(port, arg);
865
866 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800867 dbg("%s not supported = 0x%04x", __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 break;
869 }
870
871 return -ENOIOCTLCMD;
872}
873
Thiago Galesi372db8a2006-07-31 15:39:27 -0300874static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 struct usb_serial *serial = port->serial;
877 u16 state;
878 int result;
879
Harvey Harrison441b62c2008-03-03 16:08:34 -0800880 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 if (break_state == 0)
883 state = BREAK_OFF;
884 else
885 state = BREAK_ON;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800886 dbg("%s - turning break %s", __func__, state==BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
Thiago Galesi372db8a2006-07-31 15:39:27 -0300888 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
889 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
890 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800892 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
Thiago Galesi372db8a2006-07-31 15:39:27 -0300895static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
897 int i;
898 struct pl2303_private *priv;
899
Harvey Harrison441b62c2008-03-03 16:08:34 -0800900 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902 for (i = 0; i < serial->num_ports; ++i) {
903 priv = usb_get_serial_port_data(serial->port[i]);
904 if (priv) {
905 pl2303_buf_free(priv->buf);
906 kfree(priv);
907 usb_set_serial_port_data(serial->port[i], NULL);
908 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910}
911
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700912static void pl2303_update_line_status(struct usb_serial_port *port,
913 unsigned char *data,
914 unsigned int actual_length)
915{
916
917 struct pl2303_private *priv = usb_get_serial_port_data(port);
918 unsigned long flags;
919 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200920 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300921 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700922
Thiago Galesi9c537612006-07-29 10:47:12 -0300923 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
924 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
925
926
927 if (idv == SIEMENS_VENDOR_ID) {
928 if (idp == SIEMENS_PRODUCT_ID_X65 ||
929 idp == SIEMENS_PRODUCT_ID_SX1 ||
930 idp == SIEMENS_PRODUCT_ID_X75) {
931
932 length = 1;
933 status_idx = 0;
934 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700935 }
936
937 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300938 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700939
940 /* Save off the uart status for others to look at */
941 spin_lock_irqsave(&priv->lock, flags);
942 priv->line_status = data[status_idx];
943 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300944 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700945}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
David Howells7d12e782006-10-05 14:55:46 +0100947static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
Ming Leicdc97792008-02-24 18:41:47 +0800949 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700951 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700952 int status = urb->status;
953 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Harvey Harrison441b62c2008-03-03 16:08:34 -0800955 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700957 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 case 0:
959 /* success */
960 break;
961 case -ECONNRESET:
962 case -ENOENT:
963 case -ESHUTDOWN:
964 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800965 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700966 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 return;
968 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800969 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700970 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 goto exit;
972 }
973
Harvey Harrison441b62c2008-03-03 16:08:34 -0800974 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300975 urb->actual_length, urb->transfer_buffer);
976
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700977 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700980 retval = usb_submit_urb(urb, GFP_ATOMIC);
981 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300982 dev_err(&urb->dev->dev,
983 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800984 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985}
986
David Howells7d12e782006-10-05 14:55:46 +0100987static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
Ming Leicdc97792008-02-24 18:41:47 +0800989 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 struct pl2303_private *priv = usb_get_serial_port_data(port);
991 struct tty_struct *tty;
992 unsigned char *data = urb->transfer_buffer;
993 unsigned long flags;
994 int i;
995 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700996 int status = urb->status;
997 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 char tty_flag;
999
Harvey Harrison441b62c2008-03-03 16:08:34 -08001000 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001002 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001003 dbg("%s - urb status = %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (!port->open_count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001005 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 return;
1007 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001008 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001009 /* PL2303 mysteriously fails with -EPROTO reschedule
1010 * the read */
1011 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001012 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 urb->dev = port->serial->dev;
1014 result = usb_submit_urb(urb, GFP_ATOMIC);
1015 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001016 dev_err(&urb->dev->dev, "%s - failed"
1017 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001018 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return;
1020 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001021 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 return;
1023 }
1024
Harvey Harrison441b62c2008-03-03 16:08:34 -08001025 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001026 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
1028 /* get tty_flag from status */
1029 tty_flag = TTY_NORMAL;
1030
1031 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001032 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1034 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001035 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 /* break takes precedence over parity, */
1038 /* which takes precedence over framing errors */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001039 if (line_status & UART_BREAK_ERROR )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001041 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001043 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001045 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
1047 tty = port->tty;
1048 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001049 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001051 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001053 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001054 tty_insert_flip_char(tty, data[i], tty_flag);
1055 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057
1058 /* Schedule the next read _if_ we are still open */
1059 if (port->open_count) {
1060 urb->dev = port->serial->dev;
1061 result = usb_submit_urb(urb, GFP_ATOMIC);
1062 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001063 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001064 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 }
1066
1067 return;
1068}
1069
David Howells7d12e782006-10-05 14:55:46 +01001070static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
Ming Leicdc97792008-02-24 18:41:47 +08001072 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 struct pl2303_private *priv = usb_get_serial_port_data(port);
1074 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001075 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Harvey Harrison441b62c2008-03-03 16:08:34 -08001077 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001079 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 case 0:
1081 /* success */
1082 break;
1083 case -ECONNRESET:
1084 case -ENOENT:
1085 case -ESHUTDOWN:
1086 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001087 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001088 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 priv->write_urb_in_use = 0;
1090 return;
1091 default:
1092 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001093 dbg("%s - Overflow in write", __func__);
1094 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001095 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 port->write_urb->transfer_buffer_length = 1;
1097 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001098 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001100 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001101 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 else
1103 return;
1104 }
1105
1106 priv->write_urb_in_use = 0;
1107
1108 /* send any buffered data */
1109 pl2303_send(port);
1110}
1111
Thiago Galesi572d3132006-07-29 10:46:37 -03001112/* All of the device info needed for the PL2303 SIO serial converter */
1113static struct usb_serial_driver pl2303_device = {
1114 .driver = {
1115 .owner = THIS_MODULE,
1116 .name = "pl2303",
1117 },
1118 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001119 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001120 .num_ports = 1,
1121 .open = pl2303_open,
1122 .close = pl2303_close,
1123 .write = pl2303_write,
1124 .ioctl = pl2303_ioctl,
1125 .break_ctl = pl2303_break_ctl,
1126 .set_termios = pl2303_set_termios,
1127 .tiocmget = pl2303_tiocmget,
1128 .tiocmset = pl2303_tiocmset,
1129 .read_bulk_callback = pl2303_read_bulk_callback,
1130 .read_int_callback = pl2303_read_int_callback,
1131 .write_bulk_callback = pl2303_write_bulk_callback,
1132 .write_room = pl2303_write_room,
1133 .chars_in_buffer = pl2303_chars_in_buffer,
1134 .attach = pl2303_startup,
1135 .shutdown = pl2303_shutdown,
1136};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Thiago Galesi372db8a2006-07-31 15:39:27 -03001138static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
1140 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 retval = usb_serial_register(&pl2303_device);
1143 if (retval)
1144 goto failed_usb_serial_register;
1145 retval = usb_register(&pl2303_driver);
1146 if (retval)
1147 goto failed_usb_register;
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001148 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return 0;
1150failed_usb_register:
1151 usb_serial_deregister(&pl2303_device);
1152failed_usb_serial_register:
1153 return retval;
1154}
1155
Thiago Galesi372db8a2006-07-31 15:39:27 -03001156static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001158 usb_deregister(&pl2303_driver);
1159 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160}
1161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162module_init(pl2303_init);
1163module_exit(pl2303_exit);
1164
1165MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166MODULE_LICENSE("GPL");
1167
1168module_param(debug, bool, S_IRUGO | S_IWUSR);
1169MODULE_PARM_DESC(debug, "Debug enabled or not");
1170