blob: 2c9c446ad625ded55144ad36955abc6bef07ddfa [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Prolific PL2303 USB to serial adaptor driver
3 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07004 * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2003 IBM Corp.
6 *
7 * Original driver for 2.2.x by anonymous
8 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07009 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 *
Alan Cox3a0f43e2008-07-22 11:14:49 +010013 * See Documentation/usb/usb-serial.txt for more information on using this
14 * driver
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/kernel.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22#include <linux/tty.h>
23#include <linux/tty_driver.h>
24#include <linux/tty_flip.h>
25#include <linux/serial.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/spinlock.h>
Alan Cox3a0f43e2008-07-22 11:14:49 +010029#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070031#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "pl2303.h"
33
34/*
35 * Version Information
36 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
38
39static int debug;
40
41#define PL2303_CLOSING_WAIT (30*HZ)
42
43#define PL2303_BUF_SIZE 1024
44#define PL2303_TMP_BUF_SIZE 1024
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046struct pl2303_buf {
47 unsigned int buf_size;
48 char *buf_buf;
49 char *buf_get;
50 char *buf_put;
51};
52
53static struct usb_device_id id_table [] = {
54 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
55 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100056 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
58 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070059 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053060 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050061 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090063 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
65 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
66 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
67 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
68 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080069 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
71 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
72 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
73 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
74 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
75 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
76 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
77 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080078 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080080 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020081 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070082 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010083 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
84 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010085 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010086 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080087 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040088 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100089 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020090 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090091 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090092 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Piotr Roszatycki002e8f22008-01-02 11:16:57 +010093 { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050094 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 { } /* Terminating entry */
96};
97
Thiago Galesi372db8a2006-07-31 15:39:27 -030098MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 .name = "pl2303",
102 .probe = usb_serial_probe,
103 .disconnect = usb_serial_disconnect,
104 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800105 .suspend = usb_serial_suspend,
106 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800107 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800108 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109};
110
111#define SET_LINE_REQUEST_TYPE 0x21
112#define SET_LINE_REQUEST 0x20
113
114#define SET_CONTROL_REQUEST_TYPE 0x21
115#define SET_CONTROL_REQUEST 0x22
116#define CONTROL_DTR 0x01
117#define CONTROL_RTS 0x02
118
119#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100120#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#define BREAK_ON 0xffff
122#define BREAK_OFF 0x0000
123
124#define GET_LINE_REQUEST_TYPE 0xa1
125#define GET_LINE_REQUEST 0x21
126
127#define VENDOR_WRITE_REQUEST_TYPE 0x40
128#define VENDOR_WRITE_REQUEST 0x01
129
130#define VENDOR_READ_REQUEST_TYPE 0xc0
131#define VENDOR_READ_REQUEST 0x01
132
133#define UART_STATE 0x08
134#define UART_STATE_TRANSIENT_MASK 0x74
135#define UART_DCD 0x01
136#define UART_DSR 0x02
137#define UART_BREAK_ERROR 0x04
138#define UART_RING 0x08
139#define UART_FRAME_ERROR 0x10
140#define UART_PARITY_ERROR 0x20
141#define UART_OVERRUN_ERROR 0x40
142#define UART_CTS 0x80
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145enum pl2303_type {
146 type_0, /* don't know the difference between type 0 and */
147 type_1, /* type 1, until someone from prolific tells us... */
148 HX, /* HX version of the pl2303 chip */
149};
150
151struct pl2303_private {
152 spinlock_t lock;
153 struct pl2303_buf *buf;
154 int write_urb_in_use;
155 wait_queue_head_t delta_msr_wait;
156 u8 line_control;
157 u8 line_status;
158 u8 termios_initialized;
159 enum pl2303_type type;
160};
161
Thiago Galesi572d3132006-07-29 10:46:37 -0300162/*
163 * pl2303_buf_alloc
164 *
165 * Allocate a circular buffer and all associated memory.
166 */
167static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
168{
169 struct pl2303_buf *pb;
170
171 if (size == 0)
172 return NULL;
173
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800174 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300175 if (pb == NULL)
176 return NULL;
177
178 pb->buf_buf = kmalloc(size, GFP_KERNEL);
179 if (pb->buf_buf == NULL) {
180 kfree(pb);
181 return NULL;
182 }
183
184 pb->buf_size = size;
185 pb->buf_get = pb->buf_put = pb->buf_buf;
186
187 return pb;
188}
189
190/*
191 * pl2303_buf_free
192 *
193 * Free the buffer and all associated memory.
194 */
195static void pl2303_buf_free(struct pl2303_buf *pb)
196{
197 if (pb) {
198 kfree(pb->buf_buf);
199 kfree(pb);
200 }
201}
202
203/*
204 * pl2303_buf_clear
205 *
206 * Clear out all data in the circular buffer.
207 */
208static void pl2303_buf_clear(struct pl2303_buf *pb)
209{
210 if (pb != NULL)
211 pb->buf_get = pb->buf_put;
212 /* equivalent to a get of all data available */
213}
214
215/*
216 * pl2303_buf_data_avail
217 *
218 * Return the number of bytes of data available in the circular
219 * buffer.
220 */
221static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
222{
223 if (pb == NULL)
224 return 0;
225
Alan Cox3a0f43e2008-07-22 11:14:49 +0100226 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300227}
228
229/*
230 * pl2303_buf_space_avail
231 *
232 * Return the number of bytes of space available in the circular
233 * buffer.
234 */
235static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
236{
237 if (pb == NULL)
238 return 0;
239
Alan Cox3a0f43e2008-07-22 11:14:49 +0100240 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300241}
242
243/*
244 * pl2303_buf_put
245 *
246 * Copy data data from a user buffer and put it into the circular buffer.
247 * Restrict to the amount of space available.
248 *
249 * Return the number of bytes copied.
250 */
251static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
252 unsigned int count)
253{
254 unsigned int len;
255
256 if (pb == NULL)
257 return 0;
258
259 len = pl2303_buf_space_avail(pb);
260 if (count > len)
261 count = len;
262
263 if (count == 0)
264 return 0;
265
266 len = pb->buf_buf + pb->buf_size - pb->buf_put;
267 if (count > len) {
268 memcpy(pb->buf_put, buf, len);
269 memcpy(pb->buf_buf, buf+len, count - len);
270 pb->buf_put = pb->buf_buf + count - len;
271 } else {
272 memcpy(pb->buf_put, buf, count);
273 if (count < len)
274 pb->buf_put += count;
275 else /* count == len */
276 pb->buf_put = pb->buf_buf;
277 }
278
279 return count;
280}
281
282/*
283 * pl2303_buf_get
284 *
285 * Get data from the circular buffer and copy to the given buffer.
286 * Restrict to the amount of data available.
287 *
288 * Return the number of bytes copied.
289 */
290static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
291 unsigned int count)
292{
293 unsigned int len;
294
295 if (pb == NULL)
296 return 0;
297
298 len = pl2303_buf_data_avail(pb);
299 if (count > len)
300 count = len;
301
302 if (count == 0)
303 return 0;
304
305 len = pb->buf_buf + pb->buf_size - pb->buf_get;
306 if (count > len) {
307 memcpy(buf, pb->buf_get, len);
308 memcpy(buf+len, pb->buf_buf, count - len);
309 pb->buf_get = pb->buf_buf + count - len;
310 } else {
311 memcpy(buf, pb->buf_get, count);
312 if (count < len)
313 pb->buf_get += count;
314 else /* count == len */
315 pb->buf_get = pb->buf_buf;
316 }
317
318 return count;
319}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Sarah Sharpeb44da02007-12-14 14:08:00 -0800321static int pl2303_vendor_read(__u16 value, __u16 index,
322 struct usb_serial *serial, unsigned char *buf)
323{
324 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
325 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
326 value, index, buf, 1, 100);
327 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
328 VENDOR_READ_REQUEST, value, index, res, buf[0]);
329 return res;
330}
331
332static int pl2303_vendor_write(__u16 value, __u16 index,
333 struct usb_serial *serial)
334{
335 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
336 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
337 value, index, NULL, 0, 100);
338 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
339 VENDOR_WRITE_REQUEST, value, index, res);
340 return res;
341}
342
Thiago Galesi372db8a2006-07-31 15:39:27 -0300343static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
345 struct pl2303_private *priv;
346 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800347 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 int i;
349
Sarah Sharp3e152502007-12-14 14:08:35 -0800350 buf = kmalloc(10, GFP_KERNEL);
351 if (buf == NULL)
352 return -ENOMEM;
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 if (serial->dev->descriptor.bDeviceClass == 0x02)
355 type = type_0;
356 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
357 type = HX;
358 else if (serial->dev->descriptor.bDeviceClass == 0x00)
359 type = type_1;
360 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
361 type = type_1;
362 dbg("device type: %d", type);
363
364 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100365 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 if (!priv)
367 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 spin_lock_init(&priv->lock);
369 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
370 if (priv->buf == NULL) {
371 kfree(priv);
372 goto cleanup;
373 }
374 init_waitqueue_head(&priv->delta_msr_wait);
375 priv->type = type;
376 usb_set_serial_port_data(serial->port[i], priv);
377 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800378
379 pl2303_vendor_read(0x8484, 0, serial, buf);
380 pl2303_vendor_write(0x0404, 0, serial);
381 pl2303_vendor_read(0x8484, 0, serial, buf);
382 pl2303_vendor_read(0x8383, 0, serial, buf);
383 pl2303_vendor_read(0x8484, 0, serial, buf);
384 pl2303_vendor_write(0x0404, 1, serial);
385 pl2303_vendor_read(0x8484, 0, serial, buf);
386 pl2303_vendor_read(0x8383, 0, serial, buf);
387 pl2303_vendor_write(0, 1, serial);
388 pl2303_vendor_write(1, 0, serial);
389 if (type == HX)
390 pl2303_vendor_write(2, 0x44, serial);
391 else
392 pl2303_vendor_write(2, 0x24, serial);
393
394 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return 0;
396
397cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800398 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100399 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 priv = usb_get_serial_port_data(serial->port[i]);
401 pl2303_buf_free(priv->buf);
402 kfree(priv);
403 usb_set_serial_port_data(serial->port[i], NULL);
404 }
405 return -ENOMEM;
406}
407
Thiago Galesi372db8a2006-07-31 15:39:27 -0300408static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
410 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100411
Thiago Galesi372db8a2006-07-31 15:39:27 -0300412 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
413 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
414 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800415 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 return retval;
417}
418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419static void pl2303_send(struct usb_serial_port *port)
420{
421 int count, result;
422 struct pl2303_private *priv = usb_get_serial_port_data(port);
423 unsigned long flags;
424
Harvey Harrison441b62c2008-03-03 16:08:34 -0800425 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 spin_lock_irqsave(&priv->lock, flags);
428
429 if (priv->write_urb_in_use) {
430 spin_unlock_irqrestore(&priv->lock, flags);
431 return;
432 }
433
434 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300435 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 if (count == 0) {
438 spin_unlock_irqrestore(&priv->lock, flags);
439 return;
440 }
441
442 priv->write_urb_in_use = 1;
443
444 spin_unlock_irqrestore(&priv->lock, flags);
445
Harvey Harrison441b62c2008-03-03 16:08:34 -0800446 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300447 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449 port->write_urb->transfer_buffer_length = count;
450 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300451 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300453 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800454 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100456 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
458
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700459 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
Alan Cox95da3102008-07-22 11:09:07 +0100462static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
463 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300464{
465 struct pl2303_private *priv = usb_get_serial_port_data(port);
466 unsigned long flags;
467
Harvey Harrison441b62c2008-03-03 16:08:34 -0800468 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300469
470 if (!count)
471 return count;
472
473 spin_lock_irqsave(&priv->lock, flags);
474 count = pl2303_buf_put(priv->buf, buf, count);
475 spin_unlock_irqrestore(&priv->lock, flags);
476
477 pl2303_send(port);
478
479 return count;
480}
481
Alan Cox95da3102008-07-22 11:09:07 +0100482static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Alan Cox95da3102008-07-22 11:09:07 +0100484 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 struct pl2303_private *priv = usb_get_serial_port_data(port);
486 int room = 0;
487 unsigned long flags;
488
Harvey Harrison441b62c2008-03-03 16:08:34 -0800489 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 spin_lock_irqsave(&priv->lock, flags);
492 room = pl2303_buf_space_avail(priv->buf);
493 spin_unlock_irqrestore(&priv->lock, flags);
494
Harvey Harrison441b62c2008-03-03 16:08:34 -0800495 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 return room;
497}
498
Alan Cox95da3102008-07-22 11:09:07 +0100499static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
Alan Cox95da3102008-07-22 11:09:07 +0100501 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 struct pl2303_private *priv = usb_get_serial_port_data(port);
503 int chars = 0;
504 unsigned long flags;
505
Harvey Harrison441b62c2008-03-03 16:08:34 -0800506 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 spin_lock_irqsave(&priv->lock, flags);
509 chars = pl2303_buf_data_avail(priv->buf);
510 spin_unlock_irqrestore(&priv->lock, flags);
511
Harvey Harrison441b62c2008-03-03 16:08:34 -0800512 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 return chars;
514}
515
Alan Cox95da3102008-07-22 11:09:07 +0100516static void pl2303_set_termios(struct tty_struct *tty,
517 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
519 struct usb_serial *serial = port->serial;
520 struct pl2303_private *priv = usb_get_serial_port_data(port);
521 unsigned long flags;
522 unsigned int cflag;
523 unsigned char *buf;
524 int baud;
525 int i;
526 u8 control;
527
Harvey Harrison441b62c2008-03-03 16:08:34 -0800528 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 spin_lock_irqsave(&priv->lock, flags);
531 if (!priv->termios_initialized) {
Alan Cox95da3102008-07-22 11:09:07 +0100532 *(tty->termios) = tty_std_termios;
533 tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
534 tty->termios->c_ispeed = 9600;
535 tty->termios->c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 priv->termios_initialized = 1;
537 }
538 spin_unlock_irqrestore(&priv->lock, flags);
539
Alan Coxbf5e5832008-01-08 14:55:51 +0000540 /* The PL2303 is reported to lose bytes if you change
541 serial settings even to the same values as before. Thus
542 we actually need to filter in this specific case */
543
Alan Cox95da3102008-07-22 11:09:07 +0100544 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000545 return;
546
Alan Cox95da3102008-07-22 11:09:07 +0100547 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Thiago Galesi372db8a2006-07-31 15:39:27 -0300549 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800551 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100552 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100553 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 return;
555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Thiago Galesi372db8a2006-07-31 15:39:27 -0300557 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
558 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
559 0, 0, buf, 7, 100);
560 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
561 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 if (cflag & CSIZE) {
564 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100565 case CS5:
566 buf[6] = 5;
567 break;
568 case CS6:
569 buf[6] = 6;
570 break;
571 case CS7:
572 buf[6] = 7;
573 break;
574 default:
575 case CS8:
576 buf[6] = 8;
577 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800579 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 }
581
Alan Cox95da3102008-07-22 11:09:07 +0100582 baud = tty_get_baud_rate(tty);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800583 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 if (baud) {
585 buf[0] = baud & 0xff;
586 buf[1] = (baud >> 8) & 0xff;
587 buf[2] = (baud >> 16) & 0xff;
588 buf[3] = (baud >> 24) & 0xff;
589 }
590
591 /* For reference buf[4]=0 is 1 stop bits */
592 /* For reference buf[4]=1 is 1.5 stop bits */
593 /* For reference buf[4]=2 is 2 stop bits */
594 if (cflag & CSTOPB) {
595 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800596 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 } else {
598 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800599 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 }
601
602 if (cflag & PARENB) {
603 /* For reference buf[5]=0 is none parity */
604 /* For reference buf[5]=1 is odd parity */
605 /* For reference buf[5]=2 is even parity */
606 /* For reference buf[5]=3 is mark parity */
607 /* For reference buf[5]=4 is space parity */
608 if (cflag & PARODD) {
609 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800610 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 } else {
612 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800613 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
615 } else {
616 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800617 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 }
619
Thiago Galesi372db8a2006-07-31 15:39:27 -0300620 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
621 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
622 0, 0, buf, 7, 100);
623 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 /* change control lines if we are switching to or from B0 */
626 spin_lock_irqsave(&priv->lock, flags);
627 control = priv->line_control;
628 if ((cflag & CBAUD) == B0)
629 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
630 else
631 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
632 if (control != priv->line_control) {
633 control = priv->line_control;
634 spin_unlock_irqrestore(&priv->lock, flags);
635 set_control_lines(serial->dev, control);
636 } else {
637 spin_unlock_irqrestore(&priv->lock, flags);
638 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
641
Thiago Galesi372db8a2006-07-31 15:39:27 -0300642 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
643 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
644 0, 0, buf, 7, 100);
645 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
647
648 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800650 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800652 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200653 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800654 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
656
Alan Coxdf64c472007-10-15 20:54:47 +0100657 /* FIXME: Need to read back resulting baud rate */
658 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100659 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100660
Thiago Galesi372db8a2006-07-31 15:39:27 -0300661 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}
663
Alan Cox95da3102008-07-22 11:09:07 +0100664static void pl2303_close(struct tty_struct *tty,
665 struct usb_serial_port *port, struct file *filp)
Thiago Galesi572d3132006-07-29 10:46:37 -0300666{
667 struct pl2303_private *priv = usb_get_serial_port_data(port);
668 unsigned long flags;
669 unsigned int c_cflag;
670 int bps;
671 long timeout;
672 wait_queue_t wait;
673
Harvey Harrison441b62c2008-03-03 16:08:34 -0800674 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300675
676 /* wait for data to drain from the buffer */
677 spin_lock_irqsave(&priv->lock, flags);
678 timeout = PL2303_CLOSING_WAIT;
679 init_waitqueue_entry(&wait, current);
Alan Cox95da3102008-07-22 11:09:07 +0100680 add_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300681 for (;;) {
682 set_current_state(TASK_INTERRUPTIBLE);
683 if (pl2303_buf_data_avail(priv->buf) == 0 ||
684 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100685 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300686 break;
687 spin_unlock_irqrestore(&priv->lock, flags);
688 timeout = schedule_timeout(timeout);
689 spin_lock_irqsave(&priv->lock, flags);
690 }
691 set_current_state(TASK_RUNNING);
Alan Cox95da3102008-07-22 11:09:07 +0100692 remove_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300693 /* clear out any remaining data in the buffer */
694 pl2303_buf_clear(priv->buf);
695 spin_unlock_irqrestore(&priv->lock, flags);
696
697 /* wait for characters to drain from the device */
698 /* (this is long enough for the entire 256 byte */
699 /* pl2303 hardware buffer to drain with no flow */
700 /* control for data rates of 1200 bps or more, */
701 /* for lower rates we should really know how much */
702 /* data is in the buffer to compute a delay */
703 /* that is not unnecessarily long) */
Alan Cox95da3102008-07-22 11:09:07 +0100704 bps = tty_get_baud_rate(tty);
Thiago Galesi572d3132006-07-29 10:46:37 -0300705 if (bps > 1200)
Alan Cox3a0f43e2008-07-22 11:14:49 +0100706 timeout = max((HZ*2560)/bps, HZ/10);
Thiago Galesi572d3132006-07-29 10:46:37 -0300707 else
708 timeout = 2*HZ;
709 schedule_timeout_interruptible(timeout);
710
711 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800712 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300713 usb_kill_urb(port->write_urb);
714 usb_kill_urb(port->read_urb);
715 usb_kill_urb(port->interrupt_in_urb);
716
Alan Cox95da3102008-07-22 11:09:07 +0100717 if (tty) {
718 c_cflag = tty->termios->c_cflag;
Thiago Galesi572d3132006-07-29 10:46:37 -0300719 if (c_cflag & HUPCL) {
720 /* drop DTR and RTS */
721 spin_lock_irqsave(&priv->lock, flags);
722 priv->line_control = 0;
723 spin_unlock_irqrestore(&priv->lock, flags);
724 set_control_lines(port->serial->dev, 0);
725 }
726 }
727}
728
Alan Cox95da3102008-07-22 11:09:07 +0100729static int pl2303_open(struct tty_struct *tty,
730 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731{
Alan Cox606d0992006-12-08 02:38:45 -0800732 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 struct usb_serial *serial = port->serial;
734 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 int result;
736
Harvey Harrison441b62c2008-03-03 16:08:34 -0800737 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Dariusz M16948992005-07-28 18:06:13 +0200739 if (priv->type != HX) {
740 usb_clear_halt(serial->dev, port->write_urb->pipe);
741 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800742 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800744 pl2303_vendor_write(8, 0, serial);
745 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 }
747
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100749 if (tty)
750 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Alan Cox3a0f43e2008-07-22 11:14:49 +0100752 /* FIXME: need to assert RTS and DTR if CRTSCTS off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Harvey Harrison441b62c2008-03-03 16:08:34 -0800754 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300756 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300758 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800759 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100760 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return -EPROTO;
762 }
763
Harvey Harrison441b62c2008-03-03 16:08:34 -0800764 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300766 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300768 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800769 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100770 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return -EPROTO;
772 }
773 return 0;
774}
775
Alan Cox95da3102008-07-22 11:09:07 +0100776static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300777 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
Alan Cox95da3102008-07-22 11:09:07 +0100779 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 struct pl2303_private *priv = usb_get_serial_port_data(port);
781 unsigned long flags;
782 u8 control;
783
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700784 if (!usb_get_intfdata(port->serial->interface))
785 return -ENODEV;
786
Thiago Galesi372db8a2006-07-31 15:39:27 -0300787 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if (set & TIOCM_RTS)
789 priv->line_control |= CONTROL_RTS;
790 if (set & TIOCM_DTR)
791 priv->line_control |= CONTROL_DTR;
792 if (clear & TIOCM_RTS)
793 priv->line_control &= ~CONTROL_RTS;
794 if (clear & TIOCM_DTR)
795 priv->line_control &= ~CONTROL_DTR;
796 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300797 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Thiago Galesi372db8a2006-07-31 15:39:27 -0300799 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800}
801
Alan Cox95da3102008-07-22 11:09:07 +0100802static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
Alan Cox95da3102008-07-22 11:09:07 +0100804 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 struct pl2303_private *priv = usb_get_serial_port_data(port);
806 unsigned long flags;
807 unsigned int mcr;
808 unsigned int status;
809 unsigned int result;
810
Harvey Harrison441b62c2008-03-03 16:08:34 -0800811 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700813 if (!usb_get_intfdata(port->serial->interface))
814 return -ENODEV;
815
Thiago Galesi372db8a2006-07-31 15:39:27 -0300816 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 mcr = priv->line_control;
818 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300819 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
822 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
823 | ((status & UART_CTS) ? TIOCM_CTS : 0)
824 | ((status & UART_DSR) ? TIOCM_DSR : 0)
825 | ((status & UART_RING) ? TIOCM_RI : 0)
826 | ((status & UART_DCD) ? TIOCM_CD : 0);
827
Harvey Harrison441b62c2008-03-03 16:08:34 -0800828 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 return result;
831}
832
833static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
834{
835 struct pl2303_private *priv = usb_get_serial_port_data(port);
836 unsigned long flags;
837 unsigned int prevstatus;
838 unsigned int status;
839 unsigned int changed;
840
Thiago Galesi372db8a2006-07-31 15:39:27 -0300841 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300843 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 while (1) {
846 interruptible_sleep_on(&priv->delta_msr_wait);
847 /* see if a signal did it */
848 if (signal_pending(current))
849 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300850
851 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300853 spin_unlock_irqrestore(&priv->lock, flags);
854
Alan Cox3a0f43e2008-07-22 11:14:49 +0100855 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
858 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
859 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100860 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 return 0;
862 }
863 prevstatus = status;
864 }
865 /* NOTREACHED */
866 return 0;
867}
868
Alan Cox95da3102008-07-22 11:09:07 +0100869static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300870 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
Alan Cox95da3102008-07-22 11:09:07 +0100872 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800873 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100876 case TIOCMIWAIT:
877 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
878 return wait_modem_info(port, arg);
879 default:
880 dbg("%s not supported = 0x%04x", __func__, cmd);
881 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 return -ENOIOCTLCMD;
884}
885
Alan Cox95da3102008-07-22 11:09:07 +0100886static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
Alan Cox95da3102008-07-22 11:09:07 +0100888 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 struct usb_serial *serial = port->serial;
890 u16 state;
891 int result;
892
Harvey Harrison441b62c2008-03-03 16:08:34 -0800893 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 if (break_state == 0)
896 state = BREAK_OFF;
897 else
898 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100899 dbg("%s - turning break %s", __func__,
900 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Thiago Galesi372db8a2006-07-31 15:39:27 -0300902 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
903 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
904 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800906 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907}
908
Thiago Galesi372db8a2006-07-31 15:39:27 -0300909static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
911 int i;
912 struct pl2303_private *priv;
913
Harvey Harrison441b62c2008-03-03 16:08:34 -0800914 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 for (i = 0; i < serial->num_ports; ++i) {
917 priv = usb_get_serial_port_data(serial->port[i]);
918 if (priv) {
919 pl2303_buf_free(priv->buf);
920 kfree(priv);
921 usb_set_serial_port_data(serial->port[i], NULL);
922 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924}
925
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700926static void pl2303_update_line_status(struct usb_serial_port *port,
927 unsigned char *data,
928 unsigned int actual_length)
929{
930
931 struct pl2303_private *priv = usb_get_serial_port_data(port);
932 unsigned long flags;
933 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200934 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300935 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700936
Thiago Galesi9c537612006-07-29 10:47:12 -0300937 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
938 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
939
940
941 if (idv == SIEMENS_VENDOR_ID) {
942 if (idp == SIEMENS_PRODUCT_ID_X65 ||
943 idp == SIEMENS_PRODUCT_ID_SX1 ||
944 idp == SIEMENS_PRODUCT_ID_X75) {
945
946 length = 1;
947 status_idx = 0;
948 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700949 }
950
951 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300952 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700953
Alan Cox3a0f43e2008-07-22 11:14:49 +0100954 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700955 spin_lock_irqsave(&priv->lock, flags);
956 priv->line_status = data[status_idx];
957 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300958 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700959}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
David Howells7d12e782006-10-05 14:55:46 +0100961static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Ming Leicdc97792008-02-24 18:41:47 +0800963 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700965 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700966 int status = urb->status;
967 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Harvey Harrison441b62c2008-03-03 16:08:34 -0800969 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700971 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 case 0:
973 /* success */
974 break;
975 case -ECONNRESET:
976 case -ENOENT:
977 case -ESHUTDOWN:
978 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800979 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700980 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return;
982 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800983 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700984 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 goto exit;
986 }
987
Harvey Harrison441b62c2008-03-03 16:08:34 -0800988 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300989 urb->actual_length, urb->transfer_buffer);
990
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700991 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700994 retval = usb_submit_urb(urb, GFP_ATOMIC);
995 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300996 dev_err(&urb->dev->dev,
997 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800998 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999}
1000
David Howells7d12e782006-10-05 14:55:46 +01001001static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002{
Ming Leicdc97792008-02-24 18:41:47 +08001003 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 struct pl2303_private *priv = usb_get_serial_port_data(port);
1005 struct tty_struct *tty;
1006 unsigned char *data = urb->transfer_buffer;
1007 unsigned long flags;
1008 int i;
1009 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001010 int status = urb->status;
1011 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 char tty_flag;
1013
Harvey Harrison441b62c2008-03-03 16:08:34 -08001014 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001016 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001017 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001018 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001019 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return;
1021 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001022 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001023 /* PL2303 mysteriously fails with -EPROTO reschedule
1024 * the read */
1025 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001026 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 urb->dev = port->serial->dev;
1028 result = usb_submit_urb(urb, GFP_ATOMIC);
1029 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001030 dev_err(&urb->dev->dev, "%s - failed"
1031 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001032 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 return;
1034 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001035 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return;
1037 }
1038
Harvey Harrison441b62c2008-03-03 16:08:34 -08001039 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001040 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 /* get tty_flag from status */
1043 tty_flag = TTY_NORMAL;
1044
1045 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001046 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1048 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001049 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
1051 /* break takes precedence over parity, */
1052 /* which takes precedence over framing errors */
Alan Cox3a0f43e2008-07-22 11:14:49 +01001053 if (line_status & UART_BREAK_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001055 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001057 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001059 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Alan Cox95da3102008-07-22 11:09:07 +01001061 tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001063 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001065 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001067 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001068 tty_insert_flip_char(tty, data[i], tty_flag);
1069 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
1071
1072 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001073 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 urb->dev = port->serial->dev;
1075 result = usb_submit_urb(urb, GFP_ATOMIC);
1076 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001077 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001078 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
1080
1081 return;
1082}
1083
David Howells7d12e782006-10-05 14:55:46 +01001084static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085{
Ming Leicdc97792008-02-24 18:41:47 +08001086 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 struct pl2303_private *priv = usb_get_serial_port_data(port);
1088 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001089 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
Harvey Harrison441b62c2008-03-03 16:08:34 -08001091 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001093 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 case 0:
1095 /* success */
1096 break;
1097 case -ECONNRESET:
1098 case -ENOENT:
1099 case -ESHUTDOWN:
1100 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001101 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001102 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 priv->write_urb_in_use = 0;
1104 return;
1105 default:
1106 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001107 dbg("%s - Overflow in write", __func__);
1108 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001109 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 port->write_urb->transfer_buffer_length = 1;
1111 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001112 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001114 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001115 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 else
1117 return;
1118 }
1119
1120 priv->write_urb_in_use = 0;
1121
1122 /* send any buffered data */
1123 pl2303_send(port);
1124}
1125
Thiago Galesi572d3132006-07-29 10:46:37 -03001126/* All of the device info needed for the PL2303 SIO serial converter */
1127static struct usb_serial_driver pl2303_device = {
1128 .driver = {
1129 .owner = THIS_MODULE,
1130 .name = "pl2303",
1131 },
1132 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001133 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001134 .num_ports = 1,
1135 .open = pl2303_open,
1136 .close = pl2303_close,
1137 .write = pl2303_write,
1138 .ioctl = pl2303_ioctl,
1139 .break_ctl = pl2303_break_ctl,
1140 .set_termios = pl2303_set_termios,
1141 .tiocmget = pl2303_tiocmget,
1142 .tiocmset = pl2303_tiocmset,
1143 .read_bulk_callback = pl2303_read_bulk_callback,
1144 .read_int_callback = pl2303_read_int_callback,
1145 .write_bulk_callback = pl2303_write_bulk_callback,
1146 .write_room = pl2303_write_room,
1147 .chars_in_buffer = pl2303_chars_in_buffer,
1148 .attach = pl2303_startup,
1149 .shutdown = pl2303_shutdown,
1150};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Thiago Galesi372db8a2006-07-31 15:39:27 -03001152static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153{
1154 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 retval = usb_serial_register(&pl2303_device);
1157 if (retval)
1158 goto failed_usb_serial_register;
1159 retval = usb_register(&pl2303_driver);
1160 if (retval)
1161 goto failed_usb_register;
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001162 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 return 0;
1164failed_usb_register:
1165 usb_serial_deregister(&pl2303_device);
1166failed_usb_serial_register:
1167 return retval;
1168}
1169
Thiago Galesi372db8a2006-07-31 15:39:27 -03001170static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001172 usb_deregister(&pl2303_driver);
1173 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174}
1175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176module_init(pl2303_init);
1177module_exit(pl2303_exit);
1178
1179MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180MODULE_LICENSE("GPL");
1181
1182module_param(debug, bool, S_IRUGO | S_IWUSR);
1183MODULE_PARM_DESC(debug, "Debug enabled or not");
1184