blob: 103195abd41710c39133344d8668bab283003819 [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) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090061 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
63 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
64 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
65 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
66 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080067 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
69 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
70 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
71 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
72 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
73 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
74 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
75 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080076 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080078 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070080 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010081 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
82 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010083 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010084 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080085 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040086 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100087 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020088 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090089 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090090 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Piotr Roszatycki002e8f22008-01-02 11:16:57 +010091 { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050092 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 { } /* Terminating entry */
94};
95
Thiago Galesi372db8a2006-07-31 15:39:27 -030096MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 .name = "pl2303",
100 .probe = usb_serial_probe,
101 .disconnect = usb_serial_disconnect,
102 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800103 .suspend = usb_serial_suspend,
104 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800105 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800106 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107};
108
109#define SET_LINE_REQUEST_TYPE 0x21
110#define SET_LINE_REQUEST 0x20
111
112#define SET_CONTROL_REQUEST_TYPE 0x21
113#define SET_CONTROL_REQUEST 0x22
114#define CONTROL_DTR 0x01
115#define CONTROL_RTS 0x02
116
117#define BREAK_REQUEST_TYPE 0x21
118#define BREAK_REQUEST 0x23
119#define BREAK_ON 0xffff
120#define BREAK_OFF 0x0000
121
122#define GET_LINE_REQUEST_TYPE 0xa1
123#define GET_LINE_REQUEST 0x21
124
125#define VENDOR_WRITE_REQUEST_TYPE 0x40
126#define VENDOR_WRITE_REQUEST 0x01
127
128#define VENDOR_READ_REQUEST_TYPE 0xc0
129#define VENDOR_READ_REQUEST 0x01
130
131#define UART_STATE 0x08
132#define UART_STATE_TRANSIENT_MASK 0x74
133#define UART_DCD 0x01
134#define UART_DSR 0x02
135#define UART_BREAK_ERROR 0x04
136#define UART_RING 0x08
137#define UART_FRAME_ERROR 0x10
138#define UART_PARITY_ERROR 0x20
139#define UART_OVERRUN_ERROR 0x40
140#define UART_CTS 0x80
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143enum pl2303_type {
144 type_0, /* don't know the difference between type 0 and */
145 type_1, /* type 1, until someone from prolific tells us... */
146 HX, /* HX version of the pl2303 chip */
147};
148
149struct pl2303_private {
150 spinlock_t lock;
151 struct pl2303_buf *buf;
152 int write_urb_in_use;
153 wait_queue_head_t delta_msr_wait;
154 u8 line_control;
155 u8 line_status;
156 u8 termios_initialized;
157 enum pl2303_type type;
158};
159
Thiago Galesi572d3132006-07-29 10:46:37 -0300160/*
161 * pl2303_buf_alloc
162 *
163 * Allocate a circular buffer and all associated memory.
164 */
165static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
166{
167 struct pl2303_buf *pb;
168
169 if (size == 0)
170 return NULL;
171
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800172 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300173 if (pb == NULL)
174 return NULL;
175
176 pb->buf_buf = kmalloc(size, GFP_KERNEL);
177 if (pb->buf_buf == NULL) {
178 kfree(pb);
179 return NULL;
180 }
181
182 pb->buf_size = size;
183 pb->buf_get = pb->buf_put = pb->buf_buf;
184
185 return pb;
186}
187
188/*
189 * pl2303_buf_free
190 *
191 * Free the buffer and all associated memory.
192 */
193static void pl2303_buf_free(struct pl2303_buf *pb)
194{
195 if (pb) {
196 kfree(pb->buf_buf);
197 kfree(pb);
198 }
199}
200
201/*
202 * pl2303_buf_clear
203 *
204 * Clear out all data in the circular buffer.
205 */
206static void pl2303_buf_clear(struct pl2303_buf *pb)
207{
208 if (pb != NULL)
209 pb->buf_get = pb->buf_put;
210 /* equivalent to a get of all data available */
211}
212
213/*
214 * pl2303_buf_data_avail
215 *
216 * Return the number of bytes of data available in the circular
217 * buffer.
218 */
219static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
220{
221 if (pb == NULL)
222 return 0;
223
224 return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
225}
226
227/*
228 * pl2303_buf_space_avail
229 *
230 * Return the number of bytes of space available in the circular
231 * buffer.
232 */
233static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
234{
235 if (pb == NULL)
236 return 0;
237
238 return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
239}
240
241/*
242 * pl2303_buf_put
243 *
244 * Copy data data from a user buffer and put it into the circular buffer.
245 * Restrict to the amount of space available.
246 *
247 * Return the number of bytes copied.
248 */
249static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
250 unsigned int count)
251{
252 unsigned int len;
253
254 if (pb == NULL)
255 return 0;
256
257 len = pl2303_buf_space_avail(pb);
258 if (count > len)
259 count = len;
260
261 if (count == 0)
262 return 0;
263
264 len = pb->buf_buf + pb->buf_size - pb->buf_put;
265 if (count > len) {
266 memcpy(pb->buf_put, buf, len);
267 memcpy(pb->buf_buf, buf+len, count - len);
268 pb->buf_put = pb->buf_buf + count - len;
269 } else {
270 memcpy(pb->buf_put, buf, count);
271 if (count < len)
272 pb->buf_put += count;
273 else /* count == len */
274 pb->buf_put = pb->buf_buf;
275 }
276
277 return count;
278}
279
280/*
281 * pl2303_buf_get
282 *
283 * Get data from the circular buffer and copy to the given buffer.
284 * Restrict to the amount of data available.
285 *
286 * Return the number of bytes copied.
287 */
288static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
289 unsigned int count)
290{
291 unsigned int len;
292
293 if (pb == NULL)
294 return 0;
295
296 len = pl2303_buf_data_avail(pb);
297 if (count > len)
298 count = len;
299
300 if (count == 0)
301 return 0;
302
303 len = pb->buf_buf + pb->buf_size - pb->buf_get;
304 if (count > len) {
305 memcpy(buf, pb->buf_get, len);
306 memcpy(buf+len, pb->buf_buf, count - len);
307 pb->buf_get = pb->buf_buf + count - len;
308 } else {
309 memcpy(buf, pb->buf_get, count);
310 if (count < len)
311 pb->buf_get += count;
312 else /* count == len */
313 pb->buf_get = pb->buf_buf;
314 }
315
316 return count;
317}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Sarah Sharpeb44da02007-12-14 14:08:00 -0800319static int pl2303_vendor_read(__u16 value, __u16 index,
320 struct usb_serial *serial, unsigned char *buf)
321{
322 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
323 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
324 value, index, buf, 1, 100);
325 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
326 VENDOR_READ_REQUEST, value, index, res, buf[0]);
327 return res;
328}
329
330static int pl2303_vendor_write(__u16 value, __u16 index,
331 struct usb_serial *serial)
332{
333 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
334 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
335 value, index, NULL, 0, 100);
336 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
337 VENDOR_WRITE_REQUEST, value, index, res);
338 return res;
339}
340
Thiago Galesi372db8a2006-07-31 15:39:27 -0300341static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
343 struct pl2303_private *priv;
344 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800345 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 int i;
347
Sarah Sharp3e152502007-12-14 14:08:35 -0800348 buf = kmalloc(10, GFP_KERNEL);
349 if (buf == NULL)
350 return -ENOMEM;
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (serial->dev->descriptor.bDeviceClass == 0x02)
353 type = type_0;
354 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
355 type = HX;
356 else if (serial->dev->descriptor.bDeviceClass == 0x00)
357 type = type_1;
358 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
359 type = type_1;
360 dbg("device type: %d", type);
361
362 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100363 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 if (!priv)
365 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 spin_lock_init(&priv->lock);
367 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
368 if (priv->buf == NULL) {
369 kfree(priv);
370 goto cleanup;
371 }
372 init_waitqueue_head(&priv->delta_msr_wait);
373 priv->type = type;
374 usb_set_serial_port_data(serial->port[i], priv);
375 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800376
377 pl2303_vendor_read(0x8484, 0, serial, buf);
378 pl2303_vendor_write(0x0404, 0, serial);
379 pl2303_vendor_read(0x8484, 0, serial, buf);
380 pl2303_vendor_read(0x8383, 0, serial, buf);
381 pl2303_vendor_read(0x8484, 0, serial, buf);
382 pl2303_vendor_write(0x0404, 1, serial);
383 pl2303_vendor_read(0x8484, 0, serial, buf);
384 pl2303_vendor_read(0x8383, 0, serial, buf);
385 pl2303_vendor_write(0, 1, serial);
386 pl2303_vendor_write(1, 0, serial);
387 if (type == HX)
388 pl2303_vendor_write(2, 0x44, serial);
389 else
390 pl2303_vendor_write(2, 0x24, serial);
391
392 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 return 0;
394
395cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800396 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 for (--i; i>=0; --i) {
398 priv = usb_get_serial_port_data(serial->port[i]);
399 pl2303_buf_free(priv->buf);
400 kfree(priv);
401 usb_set_serial_port_data(serial->port[i], NULL);
402 }
403 return -ENOMEM;
404}
405
Thiago Galesi372db8a2006-07-31 15:39:27 -0300406static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
408 int retval;
409
Thiago Galesi372db8a2006-07-31 15:39:27 -0300410 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
411 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
412 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800413 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 return retval;
415}
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static void pl2303_send(struct usb_serial_port *port)
418{
419 int count, result;
420 struct pl2303_private *priv = usb_get_serial_port_data(port);
421 unsigned long flags;
422
Harvey Harrison441b62c2008-03-03 16:08:34 -0800423 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 spin_lock_irqsave(&priv->lock, flags);
426
427 if (priv->write_urb_in_use) {
428 spin_unlock_irqrestore(&priv->lock, flags);
429 return;
430 }
431
432 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300433 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 if (count == 0) {
436 spin_unlock_irqrestore(&priv->lock, flags);
437 return;
438 }
439
440 priv->write_urb_in_use = 1;
441
442 spin_unlock_irqrestore(&priv->lock, flags);
443
Harvey Harrison441b62c2008-03-03 16:08:34 -0800444 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300445 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 port->write_urb->transfer_buffer_length = count;
448 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300449 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300451 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800452 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 priv->write_urb_in_use = 0;
454 // TODO: reschedule pl2303_send
455 }
456
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700457 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
Thiago Galesi572d3132006-07-29 10:46:37 -0300460static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
461 int count)
462{
463 struct pl2303_private *priv = usb_get_serial_port_data(port);
464 unsigned long flags;
465
Harvey Harrison441b62c2008-03-03 16:08:34 -0800466 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300467
468 if (!count)
469 return count;
470
471 spin_lock_irqsave(&priv->lock, flags);
472 count = pl2303_buf_put(priv->buf, buf, count);
473 spin_unlock_irqrestore(&priv->lock, flags);
474
475 pl2303_send(port);
476
477 return count;
478}
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480static int pl2303_write_room(struct usb_serial_port *port)
481{
482 struct pl2303_private *priv = usb_get_serial_port_data(port);
483 int room = 0;
484 unsigned long flags;
485
Harvey Harrison441b62c2008-03-03 16:08:34 -0800486 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 spin_lock_irqsave(&priv->lock, flags);
489 room = pl2303_buf_space_avail(priv->buf);
490 spin_unlock_irqrestore(&priv->lock, flags);
491
Harvey Harrison441b62c2008-03-03 16:08:34 -0800492 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 return room;
494}
495
496static int pl2303_chars_in_buffer(struct usb_serial_port *port)
497{
498 struct pl2303_private *priv = usb_get_serial_port_data(port);
499 int chars = 0;
500 unsigned long flags;
501
Harvey Harrison441b62c2008-03-03 16:08:34 -0800502 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 spin_lock_irqsave(&priv->lock, flags);
505 chars = pl2303_buf_data_avail(priv->buf);
506 spin_unlock_irqrestore(&priv->lock, flags);
507
Harvey Harrison441b62c2008-03-03 16:08:34 -0800508 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 return chars;
510}
511
Thiago Galesi372db8a2006-07-31 15:39:27 -0300512static void pl2303_set_termios(struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -0800513 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
515 struct usb_serial *serial = port->serial;
516 struct pl2303_private *priv = usb_get_serial_port_data(port);
517 unsigned long flags;
518 unsigned int cflag;
519 unsigned char *buf;
520 int baud;
521 int i;
522 u8 control;
523
Harvey Harrison441b62c2008-03-03 16:08:34 -0800524 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 spin_lock_irqsave(&priv->lock, flags);
527 if (!priv->termios_initialized) {
528 *(port->tty->termios) = tty_std_termios;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300529 port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
530 HUPCL | CLOCAL;
Alan Coxdf64c472007-10-15 20:54:47 +0100531 port->tty->termios->c_ispeed = 9600;
532 port->tty->termios->c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 priv->termios_initialized = 1;
534 }
535 spin_unlock_irqrestore(&priv->lock, flags);
536
Alan Coxbf5e5832008-01-08 14:55:51 +0000537 /* The PL2303 is reported to lose bytes if you change
538 serial settings even to the same values as before. Thus
539 we actually need to filter in this specific case */
540
541 if (!tty_termios_hw_change(port->tty->termios, old_termios))
542 return;
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 cflag = port->tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Thiago Galesi372db8a2006-07-31 15:39:27 -0300546 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800548 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100549 /* Report back no change occurred */
550 *port->tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 return;
552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Thiago Galesi372db8a2006-07-31 15:39:27 -0300554 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
555 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
556 0, 0, buf, 7, 100);
557 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
558 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
560 if (cflag & CSIZE) {
561 switch (cflag & CSIZE) {
562 case CS5: buf[6] = 5; break;
563 case CS6: buf[6] = 6; break;
564 case CS7: buf[6] = 7; break;
565 default:
566 case CS8: buf[6] = 8; break;
567 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800568 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
570
Alan Coxe0c79f52007-07-09 12:03:10 -0700571 baud = tty_get_baud_rate(port->tty);;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800572 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 if (baud) {
574 buf[0] = baud & 0xff;
575 buf[1] = (baud >> 8) & 0xff;
576 buf[2] = (baud >> 16) & 0xff;
577 buf[3] = (baud >> 24) & 0xff;
578 }
579
580 /* For reference buf[4]=0 is 1 stop bits */
581 /* For reference buf[4]=1 is 1.5 stop bits */
582 /* For reference buf[4]=2 is 2 stop bits */
583 if (cflag & CSTOPB) {
584 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800585 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 } else {
587 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800588 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 }
590
591 if (cflag & PARENB) {
592 /* For reference buf[5]=0 is none parity */
593 /* For reference buf[5]=1 is odd parity */
594 /* For reference buf[5]=2 is even parity */
595 /* For reference buf[5]=3 is mark parity */
596 /* For reference buf[5]=4 is space parity */
597 if (cflag & PARODD) {
598 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800599 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 } else {
601 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800602 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 }
604 } else {
605 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800606 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 }
608
Thiago Galesi372db8a2006-07-31 15:39:27 -0300609 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
610 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
611 0, 0, buf, 7, 100);
612 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614 /* change control lines if we are switching to or from B0 */
615 spin_lock_irqsave(&priv->lock, flags);
616 control = priv->line_control;
617 if ((cflag & CBAUD) == B0)
618 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
619 else
620 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
621 if (control != priv->line_control) {
622 control = priv->line_control;
623 spin_unlock_irqrestore(&priv->lock, flags);
624 set_control_lines(serial->dev, control);
625 } else {
626 spin_unlock_irqrestore(&priv->lock, flags);
627 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
630
Thiago Galesi372db8a2006-07-31 15:39:27 -0300631 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
632 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
633 0, 0, buf, 7, 100);
634 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
636
637 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800639 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800641 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200642 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800643 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
645
Alan Coxdf64c472007-10-15 20:54:47 +0100646 /* FIXME: Need to read back resulting baud rate */
647 if (baud)
648 tty_encode_baud_rate(port->tty, baud, baud);
649
Thiago Galesi372db8a2006-07-31 15:39:27 -0300650 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651}
652
Thiago Galesi572d3132006-07-29 10:46:37 -0300653static void pl2303_close(struct usb_serial_port *port, struct file *filp)
654{
655 struct pl2303_private *priv = usb_get_serial_port_data(port);
656 unsigned long flags;
657 unsigned int c_cflag;
658 int bps;
659 long timeout;
660 wait_queue_t wait;
661
Harvey Harrison441b62c2008-03-03 16:08:34 -0800662 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300663
664 /* wait for data to drain from the buffer */
665 spin_lock_irqsave(&priv->lock, flags);
666 timeout = PL2303_CLOSING_WAIT;
667 init_waitqueue_entry(&wait, current);
668 add_wait_queue(&port->tty->write_wait, &wait);
669 for (;;) {
670 set_current_state(TASK_INTERRUPTIBLE);
671 if (pl2303_buf_data_avail(priv->buf) == 0 ||
672 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100673 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300674 break;
675 spin_unlock_irqrestore(&priv->lock, flags);
676 timeout = schedule_timeout(timeout);
677 spin_lock_irqsave(&priv->lock, flags);
678 }
679 set_current_state(TASK_RUNNING);
680 remove_wait_queue(&port->tty->write_wait, &wait);
681 /* clear out any remaining data in the buffer */
682 pl2303_buf_clear(priv->buf);
683 spin_unlock_irqrestore(&priv->lock, flags);
684
685 /* wait for characters to drain from the device */
686 /* (this is long enough for the entire 256 byte */
687 /* pl2303 hardware buffer to drain with no flow */
688 /* control for data rates of 1200 bps or more, */
689 /* for lower rates we should really know how much */
690 /* data is in the buffer to compute a delay */
691 /* that is not unnecessarily long) */
692 bps = tty_get_baud_rate(port->tty);
693 if (bps > 1200)
694 timeout = max((HZ*2560)/bps,HZ/10);
695 else
696 timeout = 2*HZ;
697 schedule_timeout_interruptible(timeout);
698
699 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800700 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300701 usb_kill_urb(port->write_urb);
702 usb_kill_urb(port->read_urb);
703 usb_kill_urb(port->interrupt_in_urb);
704
705 if (port->tty) {
706 c_cflag = port->tty->termios->c_cflag;
707 if (c_cflag & HUPCL) {
708 /* drop DTR and RTS */
709 spin_lock_irqsave(&priv->lock, flags);
710 priv->line_control = 0;
711 spin_unlock_irqrestore(&priv->lock, flags);
712 set_control_lines(port->serial->dev, 0);
713 }
714 }
715}
716
Thiago Galesi372db8a2006-07-31 15:39:27 -0300717static int pl2303_open(struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
Alan Cox606d0992006-12-08 02:38:45 -0800719 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 struct usb_serial *serial = port->serial;
721 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 int result;
723
Harvey Harrison441b62c2008-03-03 16:08:34 -0800724 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Dariusz M16948992005-07-28 18:06:13 +0200726 if (priv->type != HX) {
727 usb_clear_halt(serial->dev, port->write_urb->pipe);
728 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800729 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800731 pl2303_vendor_write(8, 0, serial);
732 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /* Setup termios */
736 if (port->tty) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300737 pl2303_set_termios(port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 }
739
740 //FIXME: need to assert RTS and DTR if CRTSCTS off
741
Harvey Harrison441b62c2008-03-03 16:08:34 -0800742 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300744 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300746 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800747 " error %d\n", __func__, result);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300748 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 return -EPROTO;
750 }
751
Harvey Harrison441b62c2008-03-03 16:08:34 -0800752 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300754 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300756 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800757 " error %d\n", __func__, result);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300758 pl2303_close(port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return -EPROTO;
760 }
761 return 0;
762}
763
Thiago Galesi372db8a2006-07-31 15:39:27 -0300764static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
765 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
767 struct pl2303_private *priv = usb_get_serial_port_data(port);
768 unsigned long flags;
769 u8 control;
770
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700771 if (!usb_get_intfdata(port->serial->interface))
772 return -ENODEV;
773
Thiago Galesi372db8a2006-07-31 15:39:27 -0300774 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (set & TIOCM_RTS)
776 priv->line_control |= CONTROL_RTS;
777 if (set & TIOCM_DTR)
778 priv->line_control |= CONTROL_DTR;
779 if (clear & TIOCM_RTS)
780 priv->line_control &= ~CONTROL_RTS;
781 if (clear & TIOCM_DTR)
782 priv->line_control &= ~CONTROL_DTR;
783 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300784 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Thiago Galesi372db8a2006-07-31 15:39:27 -0300786 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787}
788
Thiago Galesi372db8a2006-07-31 15:39:27 -0300789static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
791 struct pl2303_private *priv = usb_get_serial_port_data(port);
792 unsigned long flags;
793 unsigned int mcr;
794 unsigned int status;
795 unsigned int result;
796
Harvey Harrison441b62c2008-03-03 16:08:34 -0800797 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700799 if (!usb_get_intfdata(port->serial->interface))
800 return -ENODEV;
801
Thiago Galesi372db8a2006-07-31 15:39:27 -0300802 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 mcr = priv->line_control;
804 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300805 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
808 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
809 | ((status & UART_CTS) ? TIOCM_CTS : 0)
810 | ((status & UART_DSR) ? TIOCM_DSR : 0)
811 | ((status & UART_RING) ? TIOCM_RI : 0)
812 | ((status & UART_DCD) ? TIOCM_CD : 0);
813
Harvey Harrison441b62c2008-03-03 16:08:34 -0800814 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 return result;
817}
818
819static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
820{
821 struct pl2303_private *priv = usb_get_serial_port_data(port);
822 unsigned long flags;
823 unsigned int prevstatus;
824 unsigned int status;
825 unsigned int changed;
826
Thiago Galesi372db8a2006-07-31 15:39:27 -0300827 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300829 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 while (1) {
832 interruptible_sleep_on(&priv->delta_msr_wait);
833 /* see if a signal did it */
834 if (signal_pending(current))
835 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300836
837 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300839 spin_unlock_irqrestore(&priv->lock, flags);
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 changed=prevstatus^status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300842
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
844 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
845 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
846 ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
847 return 0;
848 }
849 prevstatus = status;
850 }
851 /* NOTREACHED */
852 return 0;
853}
854
Thiago Galesi372db8a2006-07-31 15:39:27 -0300855static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
856 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857{
Harvey Harrison441b62c2008-03-03 16:08:34 -0800858 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860 switch (cmd) {
861 case TIOCMIWAIT:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800862 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return wait_modem_info(port, arg);
864
865 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800866 dbg("%s not supported = 0x%04x", __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 break;
868 }
869
870 return -ENOIOCTLCMD;
871}
872
Thiago Galesi372db8a2006-07-31 15:39:27 -0300873static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
875 struct usb_serial *serial = port->serial;
876 u16 state;
877 int result;
878
Harvey Harrison441b62c2008-03-03 16:08:34 -0800879 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 if (break_state == 0)
882 state = BREAK_OFF;
883 else
884 state = BREAK_ON;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800885 dbg("%s - turning break %s", __func__, state==BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Thiago Galesi372db8a2006-07-31 15:39:27 -0300887 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
888 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
889 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800891 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
Thiago Galesi372db8a2006-07-31 15:39:27 -0300894static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895{
896 int i;
897 struct pl2303_private *priv;
898
Harvey Harrison441b62c2008-03-03 16:08:34 -0800899 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901 for (i = 0; i < serial->num_ports; ++i) {
902 priv = usb_get_serial_port_data(serial->port[i]);
903 if (priv) {
904 pl2303_buf_free(priv->buf);
905 kfree(priv);
906 usb_set_serial_port_data(serial->port[i], NULL);
907 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909}
910
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700911static void pl2303_update_line_status(struct usb_serial_port *port,
912 unsigned char *data,
913 unsigned int actual_length)
914{
915
916 struct pl2303_private *priv = usb_get_serial_port_data(port);
917 unsigned long flags;
918 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200919 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300920 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700921
Thiago Galesi9c537612006-07-29 10:47:12 -0300922 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
923 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
924
925
926 if (idv == SIEMENS_VENDOR_ID) {
927 if (idp == SIEMENS_PRODUCT_ID_X65 ||
928 idp == SIEMENS_PRODUCT_ID_SX1 ||
929 idp == SIEMENS_PRODUCT_ID_X75) {
930
931 length = 1;
932 status_idx = 0;
933 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700934 }
935
936 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300937 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700938
939 /* Save off the uart status for others to look at */
940 spin_lock_irqsave(&priv->lock, flags);
941 priv->line_status = data[status_idx];
942 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300943 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700944}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
David Howells7d12e782006-10-05 14:55:46 +0100946static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
Ming Leicdc97792008-02-24 18:41:47 +0800948 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700950 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700951 int status = urb->status;
952 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
Harvey Harrison441b62c2008-03-03 16:08:34 -0800954 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700956 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 case 0:
958 /* success */
959 break;
960 case -ECONNRESET:
961 case -ENOENT:
962 case -ESHUTDOWN:
963 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800964 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700965 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 return;
967 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800968 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700969 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 goto exit;
971 }
972
Harvey Harrison441b62c2008-03-03 16:08:34 -0800973 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300974 urb->actual_length, urb->transfer_buffer);
975
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700976 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700979 retval = usb_submit_urb(urb, GFP_ATOMIC);
980 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300981 dev_err(&urb->dev->dev,
982 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800983 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984}
985
David Howells7d12e782006-10-05 14:55:46 +0100986static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
Ming Leicdc97792008-02-24 18:41:47 +0800988 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 struct pl2303_private *priv = usb_get_serial_port_data(port);
990 struct tty_struct *tty;
991 unsigned char *data = urb->transfer_buffer;
992 unsigned long flags;
993 int i;
994 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700995 int status = urb->status;
996 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 char tty_flag;
998
Harvey Harrison441b62c2008-03-03 16:08:34 -0800999 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001001 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001002 dbg("%s - urb status = %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (!port->open_count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001004 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return;
1006 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001007 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001008 /* PL2303 mysteriously fails with -EPROTO reschedule
1009 * the read */
1010 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001011 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 urb->dev = port->serial->dev;
1013 result = usb_submit_urb(urb, GFP_ATOMIC);
1014 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001015 dev_err(&urb->dev->dev, "%s - failed"
1016 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001017 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return;
1019 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001020 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return;
1022 }
1023
Harvey Harrison441b62c2008-03-03 16:08:34 -08001024 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001025 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027 /* get tty_flag from status */
1028 tty_flag = TTY_NORMAL;
1029
1030 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001031 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1033 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001034 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
1036 /* break takes precedence over parity, */
1037 /* which takes precedence over framing errors */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001038 if (line_status & UART_BREAK_ERROR )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001040 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001042 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001044 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
1046 tty = port->tty;
1047 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001048 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001050 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001052 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001053 tty_insert_flip_char(tty, data[i], tty_flag);
1054 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 }
1056
1057 /* Schedule the next read _if_ we are still open */
1058 if (port->open_count) {
1059 urb->dev = port->serial->dev;
1060 result = usb_submit_urb(urb, GFP_ATOMIC);
1061 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001062 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001063 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 }
1065
1066 return;
1067}
1068
David Howells7d12e782006-10-05 14:55:46 +01001069static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070{
Ming Leicdc97792008-02-24 18:41:47 +08001071 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 struct pl2303_private *priv = usb_get_serial_port_data(port);
1073 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001074 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Harvey Harrison441b62c2008-03-03 16:08:34 -08001076 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001078 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 case 0:
1080 /* success */
1081 break;
1082 case -ECONNRESET:
1083 case -ENOENT:
1084 case -ESHUTDOWN:
1085 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001086 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001087 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 priv->write_urb_in_use = 0;
1089 return;
1090 default:
1091 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001092 dbg("%s - Overflow in write", __func__);
1093 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001094 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 port->write_urb->transfer_buffer_length = 1;
1096 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001097 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001099 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001100 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 else
1102 return;
1103 }
1104
1105 priv->write_urb_in_use = 0;
1106
1107 /* send any buffered data */
1108 pl2303_send(port);
1109}
1110
Thiago Galesi572d3132006-07-29 10:46:37 -03001111/* All of the device info needed for the PL2303 SIO serial converter */
1112static struct usb_serial_driver pl2303_device = {
1113 .driver = {
1114 .owner = THIS_MODULE,
1115 .name = "pl2303",
1116 },
1117 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001118 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001119 .num_ports = 1,
1120 .open = pl2303_open,
1121 .close = pl2303_close,
1122 .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,
1134 .shutdown = pl2303_shutdown,
1135};
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-Hartman17a882f2005-06-20 21:15:16 -07001147 info(DRIVER_DESC);
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