blob: a0016725d3149fb8a6c7d082d117fa197392a8d3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Prolific PL2303 USB to serial adaptor driver
3 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07004 * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2003 IBM Corp.
6 *
7 * Original driver for 2.2.x by anonymous
8 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07009 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 *
13 * See Documentation/usb/usb-serial.txt for more information on using this driver
14 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 */
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/tty.h>
22#include <linux/tty_driver.h>
23#include <linux/tty_flip.h>
24#include <linux/serial.h>
25#include <linux/module.h>
26#include <linux/moduleparam.h>
27#include <linux/spinlock.h>
28#include <asm/uaccess.h>
29#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070030#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include "pl2303.h"
32
33/*
34 * Version Information
35 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
37
38static int debug;
39
40#define PL2303_CLOSING_WAIT (30*HZ)
41
42#define PL2303_BUF_SIZE 1024
43#define PL2303_TMP_BUF_SIZE 1024
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045struct pl2303_buf {
46 unsigned int buf_size;
47 char *buf_buf;
48 char *buf_get;
49 char *buf_put;
50};
51
52static struct usb_device_id id_table [] = {
53 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
54 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100055 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
57 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070058 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053059 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050060 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090062 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
64 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
65 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
66 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
67 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080068 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
70 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
71 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
72 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
73 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
74 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
75 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
76 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080077 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020080 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070081 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010082 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
83 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010084 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010085 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080086 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040087 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100088 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020089 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090090 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090091 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Piotr Roszatycki002e8f22008-01-02 11:16:57 +010092 { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050093 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 { } /* Terminating entry */
95};
96
Thiago Galesi372db8a2006-07-31 15:39:27 -030097MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 .name = "pl2303",
101 .probe = usb_serial_probe,
102 .disconnect = usb_serial_disconnect,
103 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800104 .suspend = usb_serial_suspend,
105 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800106 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800107 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110#define SET_LINE_REQUEST_TYPE 0x21
111#define SET_LINE_REQUEST 0x20
112
113#define SET_CONTROL_REQUEST_TYPE 0x21
114#define SET_CONTROL_REQUEST 0x22
115#define CONTROL_DTR 0x01
116#define CONTROL_RTS 0x02
117
118#define BREAK_REQUEST_TYPE 0x21
119#define BREAK_REQUEST 0x23
120#define BREAK_ON 0xffff
121#define BREAK_OFF 0x0000
122
123#define GET_LINE_REQUEST_TYPE 0xa1
124#define GET_LINE_REQUEST 0x21
125
126#define VENDOR_WRITE_REQUEST_TYPE 0x40
127#define VENDOR_WRITE_REQUEST 0x01
128
129#define VENDOR_READ_REQUEST_TYPE 0xc0
130#define VENDOR_READ_REQUEST 0x01
131
132#define UART_STATE 0x08
133#define UART_STATE_TRANSIENT_MASK 0x74
134#define UART_DCD 0x01
135#define UART_DSR 0x02
136#define UART_BREAK_ERROR 0x04
137#define UART_RING 0x08
138#define UART_FRAME_ERROR 0x10
139#define UART_PARITY_ERROR 0x20
140#define UART_OVERRUN_ERROR 0x40
141#define UART_CTS 0x80
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144enum pl2303_type {
145 type_0, /* don't know the difference between type 0 and */
146 type_1, /* type 1, until someone from prolific tells us... */
147 HX, /* HX version of the pl2303 chip */
148};
149
150struct pl2303_private {
151 spinlock_t lock;
152 struct pl2303_buf *buf;
153 int write_urb_in_use;
154 wait_queue_head_t delta_msr_wait;
155 u8 line_control;
156 u8 line_status;
157 u8 termios_initialized;
158 enum pl2303_type type;
159};
160
Thiago Galesi572d3132006-07-29 10:46:37 -0300161/*
162 * pl2303_buf_alloc
163 *
164 * Allocate a circular buffer and all associated memory.
165 */
166static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
167{
168 struct pl2303_buf *pb;
169
170 if (size == 0)
171 return NULL;
172
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800173 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300174 if (pb == NULL)
175 return NULL;
176
177 pb->buf_buf = kmalloc(size, GFP_KERNEL);
178 if (pb->buf_buf == NULL) {
179 kfree(pb);
180 return NULL;
181 }
182
183 pb->buf_size = size;
184 pb->buf_get = pb->buf_put = pb->buf_buf;
185
186 return pb;
187}
188
189/*
190 * pl2303_buf_free
191 *
192 * Free the buffer and all associated memory.
193 */
194static void pl2303_buf_free(struct pl2303_buf *pb)
195{
196 if (pb) {
197 kfree(pb->buf_buf);
198 kfree(pb);
199 }
200}
201
202/*
203 * pl2303_buf_clear
204 *
205 * Clear out all data in the circular buffer.
206 */
207static void pl2303_buf_clear(struct pl2303_buf *pb)
208{
209 if (pb != NULL)
210 pb->buf_get = pb->buf_put;
211 /* equivalent to a get of all data available */
212}
213
214/*
215 * pl2303_buf_data_avail
216 *
217 * Return the number of bytes of data available in the circular
218 * buffer.
219 */
220static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
221{
222 if (pb == NULL)
223 return 0;
224
225 return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
226}
227
228/*
229 * pl2303_buf_space_avail
230 *
231 * Return the number of bytes of space available in the circular
232 * buffer.
233 */
234static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
235{
236 if (pb == NULL)
237 return 0;
238
239 return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
240}
241
242/*
243 * pl2303_buf_put
244 *
245 * Copy data data from a user buffer and put it into the circular buffer.
246 * Restrict to the amount of space available.
247 *
248 * Return the number of bytes copied.
249 */
250static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
251 unsigned int count)
252{
253 unsigned int len;
254
255 if (pb == NULL)
256 return 0;
257
258 len = pl2303_buf_space_avail(pb);
259 if (count > len)
260 count = len;
261
262 if (count == 0)
263 return 0;
264
265 len = pb->buf_buf + pb->buf_size - pb->buf_put;
266 if (count > len) {
267 memcpy(pb->buf_put, buf, len);
268 memcpy(pb->buf_buf, buf+len, count - len);
269 pb->buf_put = pb->buf_buf + count - len;
270 } else {
271 memcpy(pb->buf_put, buf, count);
272 if (count < len)
273 pb->buf_put += count;
274 else /* count == len */
275 pb->buf_put = pb->buf_buf;
276 }
277
278 return count;
279}
280
281/*
282 * pl2303_buf_get
283 *
284 * Get data from the circular buffer and copy to the given buffer.
285 * Restrict to the amount of data available.
286 *
287 * Return the number of bytes copied.
288 */
289static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
290 unsigned int count)
291{
292 unsigned int len;
293
294 if (pb == NULL)
295 return 0;
296
297 len = pl2303_buf_data_avail(pb);
298 if (count > len)
299 count = len;
300
301 if (count == 0)
302 return 0;
303
304 len = pb->buf_buf + pb->buf_size - pb->buf_get;
305 if (count > len) {
306 memcpy(buf, pb->buf_get, len);
307 memcpy(buf+len, pb->buf_buf, count - len);
308 pb->buf_get = pb->buf_buf + count - len;
309 } else {
310 memcpy(buf, pb->buf_get, count);
311 if (count < len)
312 pb->buf_get += count;
313 else /* count == len */
314 pb->buf_get = pb->buf_buf;
315 }
316
317 return count;
318}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Sarah Sharpeb44da02007-12-14 14:08:00 -0800320static int pl2303_vendor_read(__u16 value, __u16 index,
321 struct usb_serial *serial, unsigned char *buf)
322{
323 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
324 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
325 value, index, buf, 1, 100);
326 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
327 VENDOR_READ_REQUEST, value, index, res, buf[0]);
328 return res;
329}
330
331static int pl2303_vendor_write(__u16 value, __u16 index,
332 struct usb_serial *serial)
333{
334 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
335 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
336 value, index, NULL, 0, 100);
337 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
338 VENDOR_WRITE_REQUEST, value, index, res);
339 return res;
340}
341
Thiago Galesi372db8a2006-07-31 15:39:27 -0300342static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
344 struct pl2303_private *priv;
345 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800346 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 int i;
348
Sarah Sharp3e152502007-12-14 14:08:35 -0800349 buf = kmalloc(10, GFP_KERNEL);
350 if (buf == NULL)
351 return -ENOMEM;
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if (serial->dev->descriptor.bDeviceClass == 0x02)
354 type = type_0;
355 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
356 type = HX;
357 else if (serial->dev->descriptor.bDeviceClass == 0x00)
358 type = type_1;
359 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
360 type = type_1;
361 dbg("device type: %d", type);
362
363 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100364 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (!priv)
366 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 spin_lock_init(&priv->lock);
368 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
369 if (priv->buf == NULL) {
370 kfree(priv);
371 goto cleanup;
372 }
373 init_waitqueue_head(&priv->delta_msr_wait);
374 priv->type = type;
375 usb_set_serial_port_data(serial->port[i], priv);
376 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800377
378 pl2303_vendor_read(0x8484, 0, serial, buf);
379 pl2303_vendor_write(0x0404, 0, serial);
380 pl2303_vendor_read(0x8484, 0, serial, buf);
381 pl2303_vendor_read(0x8383, 0, serial, buf);
382 pl2303_vendor_read(0x8484, 0, serial, buf);
383 pl2303_vendor_write(0x0404, 1, serial);
384 pl2303_vendor_read(0x8484, 0, serial, buf);
385 pl2303_vendor_read(0x8383, 0, serial, buf);
386 pl2303_vendor_write(0, 1, serial);
387 pl2303_vendor_write(1, 0, serial);
388 if (type == HX)
389 pl2303_vendor_write(2, 0x44, serial);
390 else
391 pl2303_vendor_write(2, 0x24, serial);
392
393 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return 0;
395
396cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800397 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 for (--i; i>=0; --i) {
399 priv = usb_get_serial_port_data(serial->port[i]);
400 pl2303_buf_free(priv->buf);
401 kfree(priv);
402 usb_set_serial_port_data(serial->port[i], NULL);
403 }
404 return -ENOMEM;
405}
406
Thiago Galesi372db8a2006-07-31 15:39:27 -0300407static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 int retval;
410
Thiago Galesi372db8a2006-07-31 15:39:27 -0300411 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
412 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
413 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800414 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return retval;
416}
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static void pl2303_send(struct usb_serial_port *port)
419{
420 int count, result;
421 struct pl2303_private *priv = usb_get_serial_port_data(port);
422 unsigned long flags;
423
Harvey Harrison441b62c2008-03-03 16:08:34 -0800424 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 spin_lock_irqsave(&priv->lock, flags);
427
428 if (priv->write_urb_in_use) {
429 spin_unlock_irqrestore(&priv->lock, flags);
430 return;
431 }
432
433 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300434 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 if (count == 0) {
437 spin_unlock_irqrestore(&priv->lock, flags);
438 return;
439 }
440
441 priv->write_urb_in_use = 1;
442
443 spin_unlock_irqrestore(&priv->lock, flags);
444
Harvey Harrison441b62c2008-03-03 16:08:34 -0800445 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300446 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448 port->write_urb->transfer_buffer_length = count;
449 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300450 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300452 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800453 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 priv->write_urb_in_use = 0;
455 // TODO: reschedule pl2303_send
456 }
457
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700458 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
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) {
564 case CS5: buf[6] = 5; break;
565 case CS6: buf[6] = 6; break;
566 case CS7: buf[6] = 7; break;
567 default:
568 case CS8: buf[6] = 8; break;
569 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800570 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
572
Alan Cox95da3102008-07-22 11:09:07 +0100573 baud = tty_get_baud_rate(tty);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800574 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 if (baud) {
576 buf[0] = baud & 0xff;
577 buf[1] = (baud >> 8) & 0xff;
578 buf[2] = (baud >> 16) & 0xff;
579 buf[3] = (baud >> 24) & 0xff;
580 }
581
582 /* For reference buf[4]=0 is 1 stop bits */
583 /* For reference buf[4]=1 is 1.5 stop bits */
584 /* For reference buf[4]=2 is 2 stop bits */
585 if (cflag & CSTOPB) {
586 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800587 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 } else {
589 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800590 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
592
593 if (cflag & PARENB) {
594 /* For reference buf[5]=0 is none parity */
595 /* For reference buf[5]=1 is odd parity */
596 /* For reference buf[5]=2 is even parity */
597 /* For reference buf[5]=3 is mark parity */
598 /* For reference buf[5]=4 is space parity */
599 if (cflag & PARODD) {
600 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800601 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 } else {
603 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800604 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
606 } else {
607 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800608 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610
Thiago Galesi372db8a2006-07-31 15:39:27 -0300611 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
612 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
613 0, 0, buf, 7, 100);
614 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 /* change control lines if we are switching to or from B0 */
617 spin_lock_irqsave(&priv->lock, flags);
618 control = priv->line_control;
619 if ((cflag & CBAUD) == B0)
620 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
621 else
622 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
623 if (control != priv->line_control) {
624 control = priv->line_control;
625 spin_unlock_irqrestore(&priv->lock, flags);
626 set_control_lines(serial->dev, control);
627 } else {
628 spin_unlock_irqrestore(&priv->lock, flags);
629 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
632
Thiago Galesi372db8a2006-07-31 15:39:27 -0300633 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
634 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
635 0, 0, buf, 7, 100);
636 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
638
639 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800641 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800643 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200644 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800645 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
647
Alan Coxdf64c472007-10-15 20:54:47 +0100648 /* FIXME: Need to read back resulting baud rate */
649 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100650 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100651
Thiago Galesi372db8a2006-07-31 15:39:27 -0300652 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
654
Alan Cox95da3102008-07-22 11:09:07 +0100655static void pl2303_close(struct tty_struct *tty,
656 struct usb_serial_port *port, struct file *filp)
Thiago Galesi572d3132006-07-29 10:46:37 -0300657{
658 struct pl2303_private *priv = usb_get_serial_port_data(port);
659 unsigned long flags;
660 unsigned int c_cflag;
661 int bps;
662 long timeout;
663 wait_queue_t wait;
664
Harvey Harrison441b62c2008-03-03 16:08:34 -0800665 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300666
667 /* wait for data to drain from the buffer */
668 spin_lock_irqsave(&priv->lock, flags);
669 timeout = PL2303_CLOSING_WAIT;
670 init_waitqueue_entry(&wait, current);
Alan Cox95da3102008-07-22 11:09:07 +0100671 add_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300672 for (;;) {
673 set_current_state(TASK_INTERRUPTIBLE);
674 if (pl2303_buf_data_avail(priv->buf) == 0 ||
675 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100676 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300677 break;
678 spin_unlock_irqrestore(&priv->lock, flags);
679 timeout = schedule_timeout(timeout);
680 spin_lock_irqsave(&priv->lock, flags);
681 }
682 set_current_state(TASK_RUNNING);
Alan Cox95da3102008-07-22 11:09:07 +0100683 remove_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300684 /* clear out any remaining data in the buffer */
685 pl2303_buf_clear(priv->buf);
686 spin_unlock_irqrestore(&priv->lock, flags);
687
688 /* wait for characters to drain from the device */
689 /* (this is long enough for the entire 256 byte */
690 /* pl2303 hardware buffer to drain with no flow */
691 /* control for data rates of 1200 bps or more, */
692 /* for lower rates we should really know how much */
693 /* data is in the buffer to compute a delay */
694 /* that is not unnecessarily long) */
Alan Cox95da3102008-07-22 11:09:07 +0100695 bps = tty_get_baud_rate(tty);
Thiago Galesi572d3132006-07-29 10:46:37 -0300696 if (bps > 1200)
697 timeout = max((HZ*2560)/bps,HZ/10);
698 else
699 timeout = 2*HZ;
700 schedule_timeout_interruptible(timeout);
701
702 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800703 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300704 usb_kill_urb(port->write_urb);
705 usb_kill_urb(port->read_urb);
706 usb_kill_urb(port->interrupt_in_urb);
707
Alan Cox95da3102008-07-22 11:09:07 +0100708 if (tty) {
709 c_cflag = tty->termios->c_cflag;
Thiago Galesi572d3132006-07-29 10:46:37 -0300710 if (c_cflag & HUPCL) {
711 /* drop DTR and RTS */
712 spin_lock_irqsave(&priv->lock, flags);
713 priv->line_control = 0;
714 spin_unlock_irqrestore(&priv->lock, flags);
715 set_control_lines(port->serial->dev, 0);
716 }
717 }
718}
719
Alan Cox95da3102008-07-22 11:09:07 +0100720static int pl2303_open(struct tty_struct *tty,
721 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Alan Cox606d0992006-12-08 02:38:45 -0800723 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 struct usb_serial *serial = port->serial;
725 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 int result;
727
Harvey Harrison441b62c2008-03-03 16:08:34 -0800728 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Dariusz M16948992005-07-28 18:06:13 +0200730 if (priv->type != HX) {
731 usb_clear_halt(serial->dev, port->write_urb->pipe);
732 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800733 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800735 pl2303_vendor_write(8, 0, serial);
736 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 }
738
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100740 if (tty)
741 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743 //FIXME: need to assert RTS and DTR if CRTSCTS off
744
Harvey Harrison441b62c2008-03-03 16:08:34 -0800745 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300747 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300749 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800750 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100751 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return -EPROTO;
753 }
754
Harvey Harrison441b62c2008-03-03 16:08:34 -0800755 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300757 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300759 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800760 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100761 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return -EPROTO;
763 }
764 return 0;
765}
766
Alan Cox95da3102008-07-22 11:09:07 +0100767static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300768 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
Alan Cox95da3102008-07-22 11:09:07 +0100770 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 struct pl2303_private *priv = usb_get_serial_port_data(port);
772 unsigned long flags;
773 u8 control;
774
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700775 if (!usb_get_intfdata(port->serial->interface))
776 return -ENODEV;
777
Thiago Galesi372db8a2006-07-31 15:39:27 -0300778 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (set & TIOCM_RTS)
780 priv->line_control |= CONTROL_RTS;
781 if (set & TIOCM_DTR)
782 priv->line_control |= CONTROL_DTR;
783 if (clear & TIOCM_RTS)
784 priv->line_control &= ~CONTROL_RTS;
785 if (clear & TIOCM_DTR)
786 priv->line_control &= ~CONTROL_DTR;
787 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300788 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Thiago Galesi372db8a2006-07-31 15:39:27 -0300790 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
Alan Cox95da3102008-07-22 11:09:07 +0100793static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
Alan Cox95da3102008-07-22 11:09:07 +0100795 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 struct pl2303_private *priv = usb_get_serial_port_data(port);
797 unsigned long flags;
798 unsigned int mcr;
799 unsigned int status;
800 unsigned int result;
801
Harvey Harrison441b62c2008-03-03 16:08:34 -0800802 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700804 if (!usb_get_intfdata(port->serial->interface))
805 return -ENODEV;
806
Thiago Galesi372db8a2006-07-31 15:39:27 -0300807 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 mcr = priv->line_control;
809 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300810 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
813 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
814 | ((status & UART_CTS) ? TIOCM_CTS : 0)
815 | ((status & UART_DSR) ? TIOCM_DSR : 0)
816 | ((status & UART_RING) ? TIOCM_RI : 0)
817 | ((status & UART_DCD) ? TIOCM_CD : 0);
818
Harvey Harrison441b62c2008-03-03 16:08:34 -0800819 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 return result;
822}
823
824static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
825{
826 struct pl2303_private *priv = usb_get_serial_port_data(port);
827 unsigned long flags;
828 unsigned int prevstatus;
829 unsigned int status;
830 unsigned int changed;
831
Thiago Galesi372db8a2006-07-31 15:39:27 -0300832 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300834 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 while (1) {
837 interruptible_sleep_on(&priv->delta_msr_wait);
838 /* see if a signal did it */
839 if (signal_pending(current))
840 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300841
842 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300844 spin_unlock_irqrestore(&priv->lock, flags);
845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 changed=prevstatus^status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
849 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
850 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
851 ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
852 return 0;
853 }
854 prevstatus = status;
855 }
856 /* NOTREACHED */
857 return 0;
858}
859
Alan Cox95da3102008-07-22 11:09:07 +0100860static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300861 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
Alan Cox95da3102008-07-22 11:09:07 +0100863 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800864 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 switch (cmd) {
867 case TIOCMIWAIT:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800868 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 return wait_modem_info(port, arg);
870
871 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800872 dbg("%s not supported = 0x%04x", __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 break;
874 }
875
876 return -ENOIOCTLCMD;
877}
878
Alan Cox95da3102008-07-22 11:09:07 +0100879static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880{
Alan Cox95da3102008-07-22 11:09:07 +0100881 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 struct usb_serial *serial = port->serial;
883 u16 state;
884 int result;
885
Harvey Harrison441b62c2008-03-03 16:08:34 -0800886 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 if (break_state == 0)
889 state = BREAK_OFF;
890 else
891 state = BREAK_ON;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800892 dbg("%s - turning break %s", __func__, state==BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Thiago Galesi372db8a2006-07-31 15:39:27 -0300894 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
895 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
896 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800898 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899}
900
Thiago Galesi372db8a2006-07-31 15:39:27 -0300901static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902{
903 int i;
904 struct pl2303_private *priv;
905
Harvey Harrison441b62c2008-03-03 16:08:34 -0800906 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908 for (i = 0; i < serial->num_ports; ++i) {
909 priv = usb_get_serial_port_data(serial->port[i]);
910 if (priv) {
911 pl2303_buf_free(priv->buf);
912 kfree(priv);
913 usb_set_serial_port_data(serial->port[i], NULL);
914 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916}
917
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700918static void pl2303_update_line_status(struct usb_serial_port *port,
919 unsigned char *data,
920 unsigned int actual_length)
921{
922
923 struct pl2303_private *priv = usb_get_serial_port_data(port);
924 unsigned long flags;
925 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200926 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300927 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700928
Thiago Galesi9c537612006-07-29 10:47:12 -0300929 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
930 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
931
932
933 if (idv == SIEMENS_VENDOR_ID) {
934 if (idp == SIEMENS_PRODUCT_ID_X65 ||
935 idp == SIEMENS_PRODUCT_ID_SX1 ||
936 idp == SIEMENS_PRODUCT_ID_X75) {
937
938 length = 1;
939 status_idx = 0;
940 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700941 }
942
943 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300944 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700945
946 /* Save off the uart status for others to look at */
947 spin_lock_irqsave(&priv->lock, flags);
948 priv->line_status = data[status_idx];
949 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300950 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700951}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
David Howells7d12e782006-10-05 14:55:46 +0100953static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954{
Ming Leicdc97792008-02-24 18:41:47 +0800955 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700957 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700958 int status = urb->status;
959 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Harvey Harrison441b62c2008-03-03 16:08:34 -0800961 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700963 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 case 0:
965 /* success */
966 break;
967 case -ECONNRESET:
968 case -ENOENT:
969 case -ESHUTDOWN:
970 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800971 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700972 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return;
974 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800975 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700976 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 goto exit;
978 }
979
Harvey Harrison441b62c2008-03-03 16:08:34 -0800980 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300981 urb->actual_length, urb->transfer_buffer);
982
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700983 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700986 retval = usb_submit_urb(urb, GFP_ATOMIC);
987 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300988 dev_err(&urb->dev->dev,
989 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800990 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
David Howells7d12e782006-10-05 14:55:46 +0100993static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994{
Ming Leicdc97792008-02-24 18:41:47 +0800995 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 struct pl2303_private *priv = usb_get_serial_port_data(port);
997 struct tty_struct *tty;
998 unsigned char *data = urb->transfer_buffer;
999 unsigned long flags;
1000 int i;
1001 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001002 int status = urb->status;
1003 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 char tty_flag;
1005
Harvey Harrison441b62c2008-03-03 16:08:34 -08001006 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001008 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001009 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001010 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001011 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return;
1013 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001014 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001015 /* PL2303 mysteriously fails with -EPROTO reschedule
1016 * the read */
1017 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001018 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 urb->dev = port->serial->dev;
1020 result = usb_submit_urb(urb, GFP_ATOMIC);
1021 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001022 dev_err(&urb->dev->dev, "%s - failed"
1023 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001024 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return;
1026 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001027 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return;
1029 }
1030
Harvey Harrison441b62c2008-03-03 16:08:34 -08001031 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001032 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 /* get tty_flag from status */
1035 tty_flag = TTY_NORMAL;
1036
1037 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001038 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1040 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001041 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
1043 /* break takes precedence over parity, */
1044 /* which takes precedence over framing errors */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001045 if (line_status & UART_BREAK_ERROR )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001047 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001049 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001051 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
Alan Cox95da3102008-07-22 11:09:07 +01001053 tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001055 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001057 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001059 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001060 tty_insert_flip_char(tty, data[i], tty_flag);
1061 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
1063
1064 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001065 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 urb->dev = port->serial->dev;
1067 result = usb_submit_urb(urb, GFP_ATOMIC);
1068 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001069 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001070 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
1072
1073 return;
1074}
1075
David Howells7d12e782006-10-05 14:55:46 +01001076static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077{
Ming Leicdc97792008-02-24 18:41:47 +08001078 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 struct pl2303_private *priv = usb_get_serial_port_data(port);
1080 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001081 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Harvey Harrison441b62c2008-03-03 16:08:34 -08001083 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001085 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 case 0:
1087 /* success */
1088 break;
1089 case -ECONNRESET:
1090 case -ENOENT:
1091 case -ESHUTDOWN:
1092 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001093 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001094 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 priv->write_urb_in_use = 0;
1096 return;
1097 default:
1098 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001099 dbg("%s - Overflow in write", __func__);
1100 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001101 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 port->write_urb->transfer_buffer_length = 1;
1103 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001104 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001106 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001107 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 else
1109 return;
1110 }
1111
1112 priv->write_urb_in_use = 0;
1113
1114 /* send any buffered data */
1115 pl2303_send(port);
1116}
1117
Thiago Galesi572d3132006-07-29 10:46:37 -03001118/* All of the device info needed for the PL2303 SIO serial converter */
1119static struct usb_serial_driver pl2303_device = {
1120 .driver = {
1121 .owner = THIS_MODULE,
1122 .name = "pl2303",
1123 },
1124 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001125 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001126 .num_ports = 1,
1127 .open = pl2303_open,
1128 .close = pl2303_close,
1129 .write = pl2303_write,
1130 .ioctl = pl2303_ioctl,
1131 .break_ctl = pl2303_break_ctl,
1132 .set_termios = pl2303_set_termios,
1133 .tiocmget = pl2303_tiocmget,
1134 .tiocmset = pl2303_tiocmset,
1135 .read_bulk_callback = pl2303_read_bulk_callback,
1136 .read_int_callback = pl2303_read_int_callback,
1137 .write_bulk_callback = pl2303_write_bulk_callback,
1138 .write_room = pl2303_write_room,
1139 .chars_in_buffer = pl2303_chars_in_buffer,
1140 .attach = pl2303_startup,
1141 .shutdown = pl2303_shutdown,
1142};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Thiago Galesi372db8a2006-07-31 15:39:27 -03001144static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145{
1146 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001147
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 retval = usb_serial_register(&pl2303_device);
1149 if (retval)
1150 goto failed_usb_serial_register;
1151 retval = usb_register(&pl2303_driver);
1152 if (retval)
1153 goto failed_usb_register;
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001154 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 return 0;
1156failed_usb_register:
1157 usb_serial_deregister(&pl2303_device);
1158failed_usb_serial_register:
1159 return retval;
1160}
1161
Thiago Galesi372db8a2006-07-31 15:39:27 -03001162static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001164 usb_deregister(&pl2303_driver);
1165 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166}
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168module_init(pl2303_init);
1169module_exit(pl2303_exit);
1170
1171MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172MODULE_LICENSE("GPL");
1173
1174module_param(debug, bool, S_IRUGO | S_IWUSR);
1175MODULE_PARM_DESC(debug, "Debug enabled or not");
1176