blob: 1ede1441cb1b8aca43e699d3dbc0d1d45d9b5431 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Prolific PL2303 USB to serial adaptor driver
3 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07004 * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2003 IBM Corp.
6 *
7 * Original driver for 2.2.x by anonymous
8 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07009 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 *
Alan Cox3a0f43e2008-07-22 11:14:49 +010013 * See Documentation/usb/usb-serial.txt for more information on using this
14 * driver
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/kernel.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22#include <linux/tty.h>
23#include <linux/tty_driver.h>
24#include <linux/tty_flip.h>
25#include <linux/serial.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/spinlock.h>
Alan Cox3a0f43e2008-07-22 11:14:49 +010029#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070031#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "pl2303.h"
33
34/*
35 * Version Information
36 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
38
39static int debug;
40
41#define PL2303_CLOSING_WAIT (30*HZ)
42
43#define PL2303_BUF_SIZE 1024
44#define PL2303_TMP_BUF_SIZE 1024
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046struct pl2303_buf {
47 unsigned int buf_size;
48 char *buf_buf;
49 char *buf_get;
50 char *buf_put;
51};
52
53static struct usb_device_id id_table [] = {
54 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
55 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100056 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
58 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070059 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053060 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050061 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090063 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
65 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
66 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
67 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
68 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080069 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
71 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
72 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
73 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
74 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
75 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
76 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
77 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080078 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080080 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020081 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070082 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010083 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
84 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010085 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010086 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080087 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040088 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100089 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020090 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090091 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090092 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050093 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 { } /* Terminating entry */
95};
96
Thiago Galesi372db8a2006-07-31 15:39:27 -030097MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 .name = "pl2303",
101 .probe = usb_serial_probe,
102 .disconnect = usb_serial_disconnect,
103 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800104 .suspend = usb_serial_suspend,
105 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800106 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800107 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110#define SET_LINE_REQUEST_TYPE 0x21
111#define SET_LINE_REQUEST 0x20
112
113#define SET_CONTROL_REQUEST_TYPE 0x21
114#define SET_CONTROL_REQUEST 0x22
115#define CONTROL_DTR 0x01
116#define CONTROL_RTS 0x02
117
118#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100119#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#define BREAK_ON 0xffff
121#define BREAK_OFF 0x0000
122
123#define GET_LINE_REQUEST_TYPE 0xa1
124#define GET_LINE_REQUEST 0x21
125
126#define VENDOR_WRITE_REQUEST_TYPE 0x40
127#define VENDOR_WRITE_REQUEST 0x01
128
129#define VENDOR_READ_REQUEST_TYPE 0xc0
130#define VENDOR_READ_REQUEST 0x01
131
132#define UART_STATE 0x08
133#define UART_STATE_TRANSIENT_MASK 0x74
134#define UART_DCD 0x01
135#define UART_DSR 0x02
136#define UART_BREAK_ERROR 0x04
137#define UART_RING 0x08
138#define UART_FRAME_ERROR 0x10
139#define UART_PARITY_ERROR 0x20
140#define UART_OVERRUN_ERROR 0x40
141#define UART_CTS 0x80
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144enum pl2303_type {
145 type_0, /* don't know the difference between type 0 and */
146 type_1, /* type 1, until someone from prolific tells us... */
147 HX, /* HX version of the pl2303 chip */
148};
149
150struct pl2303_private {
151 spinlock_t lock;
152 struct pl2303_buf *buf;
153 int write_urb_in_use;
154 wait_queue_head_t delta_msr_wait;
155 u8 line_control;
156 u8 line_status;
157 u8 termios_initialized;
158 enum pl2303_type type;
159};
160
Thiago Galesi572d3132006-07-29 10:46:37 -0300161/*
162 * pl2303_buf_alloc
163 *
164 * Allocate a circular buffer and all associated memory.
165 */
166static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
167{
168 struct pl2303_buf *pb;
169
170 if (size == 0)
171 return NULL;
172
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800173 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300174 if (pb == NULL)
175 return NULL;
176
177 pb->buf_buf = kmalloc(size, GFP_KERNEL);
178 if (pb->buf_buf == NULL) {
179 kfree(pb);
180 return NULL;
181 }
182
183 pb->buf_size = size;
184 pb->buf_get = pb->buf_put = pb->buf_buf;
185
186 return pb;
187}
188
189/*
190 * pl2303_buf_free
191 *
192 * Free the buffer and all associated memory.
193 */
194static void pl2303_buf_free(struct pl2303_buf *pb)
195{
196 if (pb) {
197 kfree(pb->buf_buf);
198 kfree(pb);
199 }
200}
201
202/*
203 * pl2303_buf_clear
204 *
205 * Clear out all data in the circular buffer.
206 */
207static void pl2303_buf_clear(struct pl2303_buf *pb)
208{
209 if (pb != NULL)
210 pb->buf_get = pb->buf_put;
211 /* equivalent to a get of all data available */
212}
213
214/*
215 * pl2303_buf_data_avail
216 *
217 * Return the number of bytes of data available in the circular
218 * buffer.
219 */
220static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
221{
222 if (pb == NULL)
223 return 0;
224
Alan Cox3a0f43e2008-07-22 11:14:49 +0100225 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300226}
227
228/*
229 * pl2303_buf_space_avail
230 *
231 * Return the number of bytes of space available in the circular
232 * buffer.
233 */
234static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
235{
236 if (pb == NULL)
237 return 0;
238
Alan Cox3a0f43e2008-07-22 11:14:49 +0100239 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300240}
241
242/*
243 * pl2303_buf_put
244 *
245 * Copy data data from a user buffer and put it into the circular buffer.
246 * Restrict to the amount of space available.
247 *
248 * Return the number of bytes copied.
249 */
250static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
251 unsigned int count)
252{
253 unsigned int len;
254
255 if (pb == NULL)
256 return 0;
257
258 len = pl2303_buf_space_avail(pb);
259 if (count > len)
260 count = len;
261
262 if (count == 0)
263 return 0;
264
265 len = pb->buf_buf + pb->buf_size - pb->buf_put;
266 if (count > len) {
267 memcpy(pb->buf_put, buf, len);
268 memcpy(pb->buf_buf, buf+len, count - len);
269 pb->buf_put = pb->buf_buf + count - len;
270 } else {
271 memcpy(pb->buf_put, buf, count);
272 if (count < len)
273 pb->buf_put += count;
274 else /* count == len */
275 pb->buf_put = pb->buf_buf;
276 }
277
278 return count;
279}
280
281/*
282 * pl2303_buf_get
283 *
284 * Get data from the circular buffer and copy to the given buffer.
285 * Restrict to the amount of data available.
286 *
287 * Return the number of bytes copied.
288 */
289static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
290 unsigned int count)
291{
292 unsigned int len;
293
294 if (pb == NULL)
295 return 0;
296
297 len = pl2303_buf_data_avail(pb);
298 if (count > len)
299 count = len;
300
301 if (count == 0)
302 return 0;
303
304 len = pb->buf_buf + pb->buf_size - pb->buf_get;
305 if (count > len) {
306 memcpy(buf, pb->buf_get, len);
307 memcpy(buf+len, pb->buf_buf, count - len);
308 pb->buf_get = pb->buf_buf + count - len;
309 } else {
310 memcpy(buf, pb->buf_get, count);
311 if (count < len)
312 pb->buf_get += count;
313 else /* count == len */
314 pb->buf_get = pb->buf_buf;
315 }
316
317 return count;
318}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Sarah Sharpeb44da02007-12-14 14:08:00 -0800320static int pl2303_vendor_read(__u16 value, __u16 index,
321 struct usb_serial *serial, unsigned char *buf)
322{
323 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
324 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
325 value, index, buf, 1, 100);
326 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
327 VENDOR_READ_REQUEST, value, index, res, buf[0]);
328 return res;
329}
330
331static int pl2303_vendor_write(__u16 value, __u16 index,
332 struct usb_serial *serial)
333{
334 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
335 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
336 value, index, NULL, 0, 100);
337 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
338 VENDOR_WRITE_REQUEST, value, index, res);
339 return res;
340}
341
Thiago Galesi372db8a2006-07-31 15:39:27 -0300342static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
344 struct pl2303_private *priv;
345 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800346 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 int i;
348
Sarah Sharp3e152502007-12-14 14:08:35 -0800349 buf = kmalloc(10, GFP_KERNEL);
350 if (buf == NULL)
351 return -ENOMEM;
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if (serial->dev->descriptor.bDeviceClass == 0x02)
354 type = type_0;
355 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
356 type = HX;
357 else if (serial->dev->descriptor.bDeviceClass == 0x00)
358 type = type_1;
359 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
360 type = type_1;
361 dbg("device type: %d", type);
362
363 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100364 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (!priv)
366 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 spin_lock_init(&priv->lock);
368 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
369 if (priv->buf == NULL) {
370 kfree(priv);
371 goto cleanup;
372 }
373 init_waitqueue_head(&priv->delta_msr_wait);
374 priv->type = type;
375 usb_set_serial_port_data(serial->port[i], priv);
376 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800377
378 pl2303_vendor_read(0x8484, 0, serial, buf);
379 pl2303_vendor_write(0x0404, 0, serial);
380 pl2303_vendor_read(0x8484, 0, serial, buf);
381 pl2303_vendor_read(0x8383, 0, serial, buf);
382 pl2303_vendor_read(0x8484, 0, serial, buf);
383 pl2303_vendor_write(0x0404, 1, serial);
384 pl2303_vendor_read(0x8484, 0, serial, buf);
385 pl2303_vendor_read(0x8383, 0, serial, buf);
386 pl2303_vendor_write(0, 1, serial);
387 pl2303_vendor_write(1, 0, serial);
388 if (type == HX)
389 pl2303_vendor_write(2, 0x44, serial);
390 else
391 pl2303_vendor_write(2, 0x24, serial);
392
393 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return 0;
395
396cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800397 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100398 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 priv = usb_get_serial_port_data(serial->port[i]);
400 pl2303_buf_free(priv->buf);
401 kfree(priv);
402 usb_set_serial_port_data(serial->port[i], NULL);
403 }
404 return -ENOMEM;
405}
406
Thiago Galesi372db8a2006-07-31 15:39:27 -0300407static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100410
Thiago Galesi372db8a2006-07-31 15:39:27 -0300411 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
412 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
413 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800414 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return retval;
416}
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static void pl2303_send(struct usb_serial_port *port)
419{
420 int count, result;
421 struct pl2303_private *priv = usb_get_serial_port_data(port);
422 unsigned long flags;
423
Harvey Harrison441b62c2008-03-03 16:08:34 -0800424 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 spin_lock_irqsave(&priv->lock, flags);
427
428 if (priv->write_urb_in_use) {
429 spin_unlock_irqrestore(&priv->lock, flags);
430 return;
431 }
432
433 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300434 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 if (count == 0) {
437 spin_unlock_irqrestore(&priv->lock, flags);
438 return;
439 }
440
441 priv->write_urb_in_use = 1;
442
443 spin_unlock_irqrestore(&priv->lock, flags);
444
Harvey Harrison441b62c2008-03-03 16:08:34 -0800445 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300446 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448 port->write_urb->transfer_buffer_length = count;
449 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300450 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300452 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800453 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100455 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
457
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700458 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
Alan Cox95da3102008-07-22 11:09:07 +0100461static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
462 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300463{
464 struct pl2303_private *priv = usb_get_serial_port_data(port);
465 unsigned long flags;
466
Harvey Harrison441b62c2008-03-03 16:08:34 -0800467 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300468
469 if (!count)
470 return count;
471
472 spin_lock_irqsave(&priv->lock, flags);
473 count = pl2303_buf_put(priv->buf, buf, count);
474 spin_unlock_irqrestore(&priv->lock, flags);
475
476 pl2303_send(port);
477
478 return count;
479}
480
Alan Cox95da3102008-07-22 11:09:07 +0100481static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Alan Cox95da3102008-07-22 11:09:07 +0100483 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 struct pl2303_private *priv = usb_get_serial_port_data(port);
485 int room = 0;
486 unsigned long flags;
487
Harvey Harrison441b62c2008-03-03 16:08:34 -0800488 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
490 spin_lock_irqsave(&priv->lock, flags);
491 room = pl2303_buf_space_avail(priv->buf);
492 spin_unlock_irqrestore(&priv->lock, flags);
493
Harvey Harrison441b62c2008-03-03 16:08:34 -0800494 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 return room;
496}
497
Alan Cox95da3102008-07-22 11:09:07 +0100498static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Alan Cox95da3102008-07-22 11:09:07 +0100500 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 struct pl2303_private *priv = usb_get_serial_port_data(port);
502 int chars = 0;
503 unsigned long flags;
504
Harvey Harrison441b62c2008-03-03 16:08:34 -0800505 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 spin_lock_irqsave(&priv->lock, flags);
508 chars = pl2303_buf_data_avail(priv->buf);
509 spin_unlock_irqrestore(&priv->lock, flags);
510
Harvey Harrison441b62c2008-03-03 16:08:34 -0800511 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return chars;
513}
514
Alan Cox95da3102008-07-22 11:09:07 +0100515static void pl2303_set_termios(struct tty_struct *tty,
516 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 struct usb_serial *serial = port->serial;
519 struct pl2303_private *priv = usb_get_serial_port_data(port);
520 unsigned long flags;
521 unsigned int cflag;
522 unsigned char *buf;
523 int baud;
524 int i;
525 u8 control;
526
Harvey Harrison441b62c2008-03-03 16:08:34 -0800527 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 spin_lock_irqsave(&priv->lock, flags);
530 if (!priv->termios_initialized) {
Alan Cox95da3102008-07-22 11:09:07 +0100531 *(tty->termios) = tty_std_termios;
532 tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
533 tty->termios->c_ispeed = 9600;
534 tty->termios->c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 priv->termios_initialized = 1;
536 }
537 spin_unlock_irqrestore(&priv->lock, flags);
538
Alan Coxbf5e5832008-01-08 14:55:51 +0000539 /* The PL2303 is reported to lose bytes if you change
540 serial settings even to the same values as before. Thus
541 we actually need to filter in this specific case */
542
Alan Cox95da3102008-07-22 11:09:07 +0100543 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000544 return;
545
Alan Cox95da3102008-07-22 11:09:07 +0100546 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Thiago Galesi372db8a2006-07-31 15:39:27 -0300548 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800550 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100551 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100552 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 return;
554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Thiago Galesi372db8a2006-07-31 15:39:27 -0300556 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
557 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
558 0, 0, buf, 7, 100);
559 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
560 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 if (cflag & CSIZE) {
563 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100564 case CS5:
565 buf[6] = 5;
566 break;
567 case CS6:
568 buf[6] = 6;
569 break;
570 case CS7:
571 buf[6] = 7;
572 break;
573 default:
574 case CS8:
575 buf[6] = 8;
576 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800578 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
580
Alan Cox95da3102008-07-22 11:09:07 +0100581 baud = tty_get_baud_rate(tty);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800582 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 if (baud) {
584 buf[0] = baud & 0xff;
585 buf[1] = (baud >> 8) & 0xff;
586 buf[2] = (baud >> 16) & 0xff;
587 buf[3] = (baud >> 24) & 0xff;
588 }
589
590 /* For reference buf[4]=0 is 1 stop bits */
591 /* For reference buf[4]=1 is 1.5 stop bits */
592 /* For reference buf[4]=2 is 2 stop bits */
593 if (cflag & CSTOPB) {
594 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800595 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 } else {
597 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800598 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
600
601 if (cflag & PARENB) {
602 /* For reference buf[5]=0 is none parity */
603 /* For reference buf[5]=1 is odd parity */
604 /* For reference buf[5]=2 is even parity */
605 /* For reference buf[5]=3 is mark parity */
606 /* For reference buf[5]=4 is space parity */
607 if (cflag & PARODD) {
608 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800609 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 } else {
611 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800612 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
614 } else {
615 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800616 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618
Thiago Galesi372db8a2006-07-31 15:39:27 -0300619 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
620 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
621 0, 0, buf, 7, 100);
622 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
624 /* change control lines if we are switching to or from B0 */
625 spin_lock_irqsave(&priv->lock, flags);
626 control = priv->line_control;
627 if ((cflag & CBAUD) == B0)
628 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
629 else
630 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
631 if (control != priv->line_control) {
632 control = priv->line_control;
633 spin_unlock_irqrestore(&priv->lock, flags);
634 set_control_lines(serial->dev, control);
635 } else {
636 spin_unlock_irqrestore(&priv->lock, flags);
637 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
640
Thiago Galesi372db8a2006-07-31 15:39:27 -0300641 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
642 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
643 0, 0, buf, 7, 100);
644 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
646
647 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800649 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800651 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200652 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800653 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
655
Alan Coxdf64c472007-10-15 20:54:47 +0100656 /* FIXME: Need to read back resulting baud rate */
657 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100658 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100659
Thiago Galesi372db8a2006-07-31 15:39:27 -0300660 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661}
662
Alan Cox95da3102008-07-22 11:09:07 +0100663static void pl2303_close(struct tty_struct *tty,
664 struct usb_serial_port *port, struct file *filp)
Thiago Galesi572d3132006-07-29 10:46:37 -0300665{
666 struct pl2303_private *priv = usb_get_serial_port_data(port);
667 unsigned long flags;
668 unsigned int c_cflag;
669 int bps;
670 long timeout;
671 wait_queue_t wait;
672
Harvey Harrison441b62c2008-03-03 16:08:34 -0800673 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300674
675 /* wait for data to drain from the buffer */
676 spin_lock_irqsave(&priv->lock, flags);
677 timeout = PL2303_CLOSING_WAIT;
678 init_waitqueue_entry(&wait, current);
Alan Cox95da3102008-07-22 11:09:07 +0100679 add_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300680 for (;;) {
681 set_current_state(TASK_INTERRUPTIBLE);
682 if (pl2303_buf_data_avail(priv->buf) == 0 ||
683 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100684 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300685 break;
686 spin_unlock_irqrestore(&priv->lock, flags);
687 timeout = schedule_timeout(timeout);
688 spin_lock_irqsave(&priv->lock, flags);
689 }
690 set_current_state(TASK_RUNNING);
Alan Cox95da3102008-07-22 11:09:07 +0100691 remove_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300692 /* clear out any remaining data in the buffer */
693 pl2303_buf_clear(priv->buf);
694 spin_unlock_irqrestore(&priv->lock, flags);
695
696 /* wait for characters to drain from the device */
697 /* (this is long enough for the entire 256 byte */
698 /* pl2303 hardware buffer to drain with no flow */
699 /* control for data rates of 1200 bps or more, */
700 /* for lower rates we should really know how much */
701 /* data is in the buffer to compute a delay */
702 /* that is not unnecessarily long) */
Alan Cox95da3102008-07-22 11:09:07 +0100703 bps = tty_get_baud_rate(tty);
Thiago Galesi572d3132006-07-29 10:46:37 -0300704 if (bps > 1200)
Alan Cox3a0f43e2008-07-22 11:14:49 +0100705 timeout = max((HZ*2560)/bps, HZ/10);
Thiago Galesi572d3132006-07-29 10:46:37 -0300706 else
707 timeout = 2*HZ;
708 schedule_timeout_interruptible(timeout);
709
710 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800711 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300712 usb_kill_urb(port->write_urb);
713 usb_kill_urb(port->read_urb);
714 usb_kill_urb(port->interrupt_in_urb);
715
Alan Cox95da3102008-07-22 11:09:07 +0100716 if (tty) {
717 c_cflag = tty->termios->c_cflag;
Thiago Galesi572d3132006-07-29 10:46:37 -0300718 if (c_cflag & HUPCL) {
719 /* drop DTR and RTS */
720 spin_lock_irqsave(&priv->lock, flags);
721 priv->line_control = 0;
722 spin_unlock_irqrestore(&priv->lock, flags);
723 set_control_lines(port->serial->dev, 0);
724 }
725 }
726}
727
Alan Cox95da3102008-07-22 11:09:07 +0100728static int pl2303_open(struct tty_struct *tty,
729 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
Alan Cox606d0992006-12-08 02:38:45 -0800731 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 struct usb_serial *serial = port->serial;
733 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 int result;
735
Harvey Harrison441b62c2008-03-03 16:08:34 -0800736 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Dariusz M16948992005-07-28 18:06:13 +0200738 if (priv->type != HX) {
739 usb_clear_halt(serial->dev, port->write_urb->pipe);
740 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800741 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800743 pl2303_vendor_write(8, 0, serial);
744 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 }
746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100748 if (tty)
749 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Alan Cox3a0f43e2008-07-22 11:14:49 +0100751 /* FIXME: need to assert RTS and DTR if CRTSCTS off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Harvey Harrison441b62c2008-03-03 16:08:34 -0800753 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300755 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300757 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800758 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100759 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return -EPROTO;
761 }
762
Harvey Harrison441b62c2008-03-03 16:08:34 -0800763 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300765 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300767 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800768 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100769 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return -EPROTO;
771 }
772 return 0;
773}
774
Alan Cox95da3102008-07-22 11:09:07 +0100775static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300776 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
Alan Cox95da3102008-07-22 11:09:07 +0100778 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 struct pl2303_private *priv = usb_get_serial_port_data(port);
780 unsigned long flags;
781 u8 control;
782
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700783 if (!usb_get_intfdata(port->serial->interface))
784 return -ENODEV;
785
Thiago Galesi372db8a2006-07-31 15:39:27 -0300786 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 if (set & TIOCM_RTS)
788 priv->line_control |= CONTROL_RTS;
789 if (set & TIOCM_DTR)
790 priv->line_control |= CONTROL_DTR;
791 if (clear & TIOCM_RTS)
792 priv->line_control &= ~CONTROL_RTS;
793 if (clear & TIOCM_DTR)
794 priv->line_control &= ~CONTROL_DTR;
795 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300796 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Thiago Galesi372db8a2006-07-31 15:39:27 -0300798 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799}
800
Alan Cox95da3102008-07-22 11:09:07 +0100801static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
Alan Cox95da3102008-07-22 11:09:07 +0100803 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 struct pl2303_private *priv = usb_get_serial_port_data(port);
805 unsigned long flags;
806 unsigned int mcr;
807 unsigned int status;
808 unsigned int result;
809
Harvey Harrison441b62c2008-03-03 16:08:34 -0800810 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700812 if (!usb_get_intfdata(port->serial->interface))
813 return -ENODEV;
814
Thiago Galesi372db8a2006-07-31 15:39:27 -0300815 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 mcr = priv->line_control;
817 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300818 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
821 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
822 | ((status & UART_CTS) ? TIOCM_CTS : 0)
823 | ((status & UART_DSR) ? TIOCM_DSR : 0)
824 | ((status & UART_RING) ? TIOCM_RI : 0)
825 | ((status & UART_DCD) ? TIOCM_CD : 0);
826
Harvey Harrison441b62c2008-03-03 16:08:34 -0800827 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 return result;
830}
831
832static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
833{
834 struct pl2303_private *priv = usb_get_serial_port_data(port);
835 unsigned long flags;
836 unsigned int prevstatus;
837 unsigned int status;
838 unsigned int changed;
839
Thiago Galesi372db8a2006-07-31 15:39:27 -0300840 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300842 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
844 while (1) {
845 interruptible_sleep_on(&priv->delta_msr_wait);
846 /* see if a signal did it */
847 if (signal_pending(current))
848 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300849
850 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300852 spin_unlock_irqrestore(&priv->lock, flags);
853
Alan Cox3a0f43e2008-07-22 11:14:49 +0100854 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
857 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
858 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100859 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 return 0;
861 }
862 prevstatus = status;
863 }
864 /* NOTREACHED */
865 return 0;
866}
867
Alan Cox95da3102008-07-22 11:09:07 +0100868static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300869 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
Alan Cox95da3102008-07-22 11:09:07 +0100871 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800872 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
874 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100875 case TIOCMIWAIT:
876 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
877 return wait_modem_info(port, arg);
878 default:
879 dbg("%s not supported = 0x%04x", __func__, cmd);
880 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return -ENOIOCTLCMD;
883}
884
Alan Cox95da3102008-07-22 11:09:07 +0100885static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
Alan Cox95da3102008-07-22 11:09:07 +0100887 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 struct usb_serial *serial = port->serial;
889 u16 state;
890 int result;
891
Harvey Harrison441b62c2008-03-03 16:08:34 -0800892 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
894 if (break_state == 0)
895 state = BREAK_OFF;
896 else
897 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100898 dbg("%s - turning break %s", __func__,
899 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
Thiago Galesi372db8a2006-07-31 15:39:27 -0300901 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
902 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
903 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800905 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906}
907
Thiago Galesi372db8a2006-07-31 15:39:27 -0300908static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909{
910 int i;
911 struct pl2303_private *priv;
912
Harvey Harrison441b62c2008-03-03 16:08:34 -0800913 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 for (i = 0; i < serial->num_ports; ++i) {
916 priv = usb_get_serial_port_data(serial->port[i]);
917 if (priv) {
918 pl2303_buf_free(priv->buf);
919 kfree(priv);
920 usb_set_serial_port_data(serial->port[i], NULL);
921 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923}
924
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700925static void pl2303_update_line_status(struct usb_serial_port *port,
926 unsigned char *data,
927 unsigned int actual_length)
928{
929
930 struct pl2303_private *priv = usb_get_serial_port_data(port);
931 unsigned long flags;
932 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200933 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300934 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700935
Thiago Galesi9c537612006-07-29 10:47:12 -0300936 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
937 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
938
939
940 if (idv == SIEMENS_VENDOR_ID) {
941 if (idp == SIEMENS_PRODUCT_ID_X65 ||
942 idp == SIEMENS_PRODUCT_ID_SX1 ||
943 idp == SIEMENS_PRODUCT_ID_X75) {
944
945 length = 1;
946 status_idx = 0;
947 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700948 }
949
950 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300951 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700952
Alan Cox3a0f43e2008-07-22 11:14:49 +0100953 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700954 spin_lock_irqsave(&priv->lock, flags);
955 priv->line_status = data[status_idx];
956 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300957 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700958}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
David Howells7d12e782006-10-05 14:55:46 +0100960static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
Ming Leicdc97792008-02-24 18:41:47 +0800962 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700964 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700965 int status = urb->status;
966 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Harvey Harrison441b62c2008-03-03 16:08:34 -0800968 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700970 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 case 0:
972 /* success */
973 break;
974 case -ECONNRESET:
975 case -ENOENT:
976 case -ESHUTDOWN:
977 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800978 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700979 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 return;
981 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800982 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700983 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 goto exit;
985 }
986
Harvey Harrison441b62c2008-03-03 16:08:34 -0800987 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300988 urb->actual_length, urb->transfer_buffer);
989
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700990 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700993 retval = usb_submit_urb(urb, GFP_ATOMIC);
994 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300995 dev_err(&urb->dev->dev,
996 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800997 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
David Howells7d12e782006-10-05 14:55:46 +01001000static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
Ming Leicdc97792008-02-24 18:41:47 +08001002 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 struct pl2303_private *priv = usb_get_serial_port_data(port);
1004 struct tty_struct *tty;
1005 unsigned char *data = urb->transfer_buffer;
1006 unsigned long flags;
1007 int i;
1008 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001009 int status = urb->status;
1010 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 char tty_flag;
1012
Harvey Harrison441b62c2008-03-03 16:08:34 -08001013 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001015 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001016 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001017 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001018 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return;
1020 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001021 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001022 /* PL2303 mysteriously fails with -EPROTO reschedule
1023 * the read */
1024 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001025 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 urb->dev = port->serial->dev;
1027 result = usb_submit_urb(urb, GFP_ATOMIC);
1028 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001029 dev_err(&urb->dev->dev, "%s - failed"
1030 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001031 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return;
1033 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001034 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return;
1036 }
1037
Harvey Harrison441b62c2008-03-03 16:08:34 -08001038 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001039 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041 /* get tty_flag from status */
1042 tty_flag = TTY_NORMAL;
1043
1044 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001045 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1047 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001048 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
1050 /* break takes precedence over parity, */
1051 /* which takes precedence over framing errors */
Alan Cox3a0f43e2008-07-22 11:14:49 +01001052 if (line_status & UART_BREAK_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001054 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001056 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001058 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Alan Cox95da3102008-07-22 11:09:07 +01001060 tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001062 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001064 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001066 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001067 tty_insert_flip_char(tty, data[i], tty_flag);
1068 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 }
1070
1071 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001072 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 urb->dev = port->serial->dev;
1074 result = usb_submit_urb(urb, GFP_ATOMIC);
1075 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001076 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001077 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 }
1079
1080 return;
1081}
1082
David Howells7d12e782006-10-05 14:55:46 +01001083static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084{
Ming Leicdc97792008-02-24 18:41:47 +08001085 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 struct pl2303_private *priv = usb_get_serial_port_data(port);
1087 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001088 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Harvey Harrison441b62c2008-03-03 16:08:34 -08001090 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001092 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 case 0:
1094 /* success */
1095 break;
1096 case -ECONNRESET:
1097 case -ENOENT:
1098 case -ESHUTDOWN:
1099 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001100 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001101 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 priv->write_urb_in_use = 0;
1103 return;
1104 default:
1105 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001106 dbg("%s - Overflow in write", __func__);
1107 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001108 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 port->write_urb->transfer_buffer_length = 1;
1110 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001111 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001113 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001114 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 else
1116 return;
1117 }
1118
1119 priv->write_urb_in_use = 0;
1120
1121 /* send any buffered data */
1122 pl2303_send(port);
1123}
1124
Thiago Galesi572d3132006-07-29 10:46:37 -03001125/* All of the device info needed for the PL2303 SIO serial converter */
1126static struct usb_serial_driver pl2303_device = {
1127 .driver = {
1128 .owner = THIS_MODULE,
1129 .name = "pl2303",
1130 },
1131 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001132 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001133 .num_ports = 1,
1134 .open = pl2303_open,
1135 .close = pl2303_close,
1136 .write = pl2303_write,
1137 .ioctl = pl2303_ioctl,
1138 .break_ctl = pl2303_break_ctl,
1139 .set_termios = pl2303_set_termios,
1140 .tiocmget = pl2303_tiocmget,
1141 .tiocmset = pl2303_tiocmset,
1142 .read_bulk_callback = pl2303_read_bulk_callback,
1143 .read_int_callback = pl2303_read_int_callback,
1144 .write_bulk_callback = pl2303_write_bulk_callback,
1145 .write_room = pl2303_write_room,
1146 .chars_in_buffer = pl2303_chars_in_buffer,
1147 .attach = pl2303_startup,
1148 .shutdown = pl2303_shutdown,
1149};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Thiago Galesi372db8a2006-07-31 15:39:27 -03001151static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152{
1153 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 retval = usb_serial_register(&pl2303_device);
1156 if (retval)
1157 goto failed_usb_serial_register;
1158 retval = usb_register(&pl2303_driver);
1159 if (retval)
1160 goto failed_usb_register;
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001161 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 return 0;
1163failed_usb_register:
1164 usb_serial_deregister(&pl2303_device);
1165failed_usb_serial_register:
1166 return retval;
1167}
1168
Thiago Galesi372db8a2006-07-31 15:39:27 -03001169static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001171 usb_deregister(&pl2303_driver);
1172 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173}
1174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175module_init(pl2303_init);
1176module_exit(pl2303_exit);
1177
1178MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179MODULE_LICENSE("GPL");
1180
1181module_param(debug, bool, S_IRUGO | S_IWUSR);
1182MODULE_PARM_DESC(debug, "Debug enabled or not");
1183