blob: a63ea99936f79b46fec8a989890da0564d8fbf52 [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) },
Alan Cox912299f2009-04-06 17:35:12 +010082 { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070083 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010084 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
85 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010086 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010087 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080088 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040089 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100090 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020091 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090092 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090093 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050094 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Matthew Arnold7c992002008-12-13 22:42:53 +110095 { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
Mike Provencheraf4b8512008-12-16 14:30:14 -060096 { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
Gianpaolo Cugola8540d662009-06-05 22:57:52 +020097 { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
Khanh-Dang Nguyen Thu Lam49276562009-07-28 19:41:17 +020098 { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 { } /* Terminating entry */
100};
101
Thiago Galesi372db8a2006-07-31 15:39:27 -0300102MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 .name = "pl2303",
106 .probe = usb_serial_probe,
107 .disconnect = usb_serial_disconnect,
108 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800109 .suspend = usb_serial_suspend,
110 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800111 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800112 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113};
114
115#define SET_LINE_REQUEST_TYPE 0x21
116#define SET_LINE_REQUEST 0x20
117
118#define SET_CONTROL_REQUEST_TYPE 0x21
119#define SET_CONTROL_REQUEST 0x22
120#define CONTROL_DTR 0x01
121#define CONTROL_RTS 0x02
122
123#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100124#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125#define BREAK_ON 0xffff
126#define BREAK_OFF 0x0000
127
128#define GET_LINE_REQUEST_TYPE 0xa1
129#define GET_LINE_REQUEST 0x21
130
131#define VENDOR_WRITE_REQUEST_TYPE 0x40
132#define VENDOR_WRITE_REQUEST 0x01
133
134#define VENDOR_READ_REQUEST_TYPE 0xc0
135#define VENDOR_READ_REQUEST 0x01
136
137#define UART_STATE 0x08
138#define UART_STATE_TRANSIENT_MASK 0x74
139#define UART_DCD 0x01
140#define UART_DSR 0x02
141#define UART_BREAK_ERROR 0x04
142#define UART_RING 0x08
143#define UART_FRAME_ERROR 0x10
144#define UART_PARITY_ERROR 0x20
145#define UART_OVERRUN_ERROR 0x40
146#define UART_CTS 0x80
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149enum pl2303_type {
150 type_0, /* don't know the difference between type 0 and */
151 type_1, /* type 1, until someone from prolific tells us... */
152 HX, /* HX version of the pl2303 chip */
153};
154
155struct pl2303_private {
156 spinlock_t lock;
157 struct pl2303_buf *buf;
158 int write_urb_in_use;
159 wait_queue_head_t delta_msr_wait;
160 u8 line_control;
161 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 enum pl2303_type type;
163};
164
Thiago Galesi572d3132006-07-29 10:46:37 -0300165/*
166 * pl2303_buf_alloc
167 *
168 * Allocate a circular buffer and all associated memory.
169 */
170static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
171{
172 struct pl2303_buf *pb;
173
174 if (size == 0)
175 return NULL;
176
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800177 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300178 if (pb == NULL)
179 return NULL;
180
181 pb->buf_buf = kmalloc(size, GFP_KERNEL);
182 if (pb->buf_buf == NULL) {
183 kfree(pb);
184 return NULL;
185 }
186
187 pb->buf_size = size;
188 pb->buf_get = pb->buf_put = pb->buf_buf;
189
190 return pb;
191}
192
193/*
194 * pl2303_buf_free
195 *
196 * Free the buffer and all associated memory.
197 */
198static void pl2303_buf_free(struct pl2303_buf *pb)
199{
200 if (pb) {
201 kfree(pb->buf_buf);
202 kfree(pb);
203 }
204}
205
206/*
207 * pl2303_buf_clear
208 *
209 * Clear out all data in the circular buffer.
210 */
211static void pl2303_buf_clear(struct pl2303_buf *pb)
212{
213 if (pb != NULL)
214 pb->buf_get = pb->buf_put;
215 /* equivalent to a get of all data available */
216}
217
218/*
219 * pl2303_buf_data_avail
220 *
221 * Return the number of bytes of data available in the circular
222 * buffer.
223 */
224static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
225{
226 if (pb == NULL)
227 return 0;
228
Alan Cox3a0f43e2008-07-22 11:14:49 +0100229 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300230}
231
232/*
233 * pl2303_buf_space_avail
234 *
235 * Return the number of bytes of space available in the circular
236 * buffer.
237 */
238static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
239{
240 if (pb == NULL)
241 return 0;
242
Alan Cox3a0f43e2008-07-22 11:14:49 +0100243 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300244}
245
246/*
247 * pl2303_buf_put
248 *
249 * Copy data data from a user buffer and put it into the circular buffer.
250 * Restrict to the amount of space available.
251 *
252 * Return the number of bytes copied.
253 */
254static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
255 unsigned int count)
256{
257 unsigned int len;
258
259 if (pb == NULL)
260 return 0;
261
262 len = pl2303_buf_space_avail(pb);
263 if (count > len)
264 count = len;
265
266 if (count == 0)
267 return 0;
268
269 len = pb->buf_buf + pb->buf_size - pb->buf_put;
270 if (count > len) {
271 memcpy(pb->buf_put, buf, len);
272 memcpy(pb->buf_buf, buf+len, count - len);
273 pb->buf_put = pb->buf_buf + count - len;
274 } else {
275 memcpy(pb->buf_put, buf, count);
276 if (count < len)
277 pb->buf_put += count;
278 else /* count == len */
279 pb->buf_put = pb->buf_buf;
280 }
281
282 return count;
283}
284
285/*
286 * pl2303_buf_get
287 *
288 * Get data from the circular buffer and copy to the given buffer.
289 * Restrict to the amount of data available.
290 *
291 * Return the number of bytes copied.
292 */
293static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
294 unsigned int count)
295{
296 unsigned int len;
297
298 if (pb == NULL)
299 return 0;
300
301 len = pl2303_buf_data_avail(pb);
302 if (count > len)
303 count = len;
304
305 if (count == 0)
306 return 0;
307
308 len = pb->buf_buf + pb->buf_size - pb->buf_get;
309 if (count > len) {
310 memcpy(buf, pb->buf_get, len);
311 memcpy(buf+len, pb->buf_buf, count - len);
312 pb->buf_get = pb->buf_buf + count - len;
313 } else {
314 memcpy(buf, pb->buf_get, count);
315 if (count < len)
316 pb->buf_get += count;
317 else /* count == len */
318 pb->buf_get = pb->buf_buf;
319 }
320
321 return count;
322}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Sarah Sharpeb44da02007-12-14 14:08:00 -0800324static int pl2303_vendor_read(__u16 value, __u16 index,
325 struct usb_serial *serial, unsigned char *buf)
326{
327 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
328 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
329 value, index, buf, 1, 100);
330 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
331 VENDOR_READ_REQUEST, value, index, res, buf[0]);
332 return res;
333}
334
335static int pl2303_vendor_write(__u16 value, __u16 index,
336 struct usb_serial *serial)
337{
338 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
339 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
340 value, index, NULL, 0, 100);
341 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
342 VENDOR_WRITE_REQUEST, value, index, res);
343 return res;
344}
345
Thiago Galesi372db8a2006-07-31 15:39:27 -0300346static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 struct pl2303_private *priv;
349 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800350 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 int i;
352
Sarah Sharp3e152502007-12-14 14:08:35 -0800353 buf = kmalloc(10, GFP_KERNEL);
354 if (buf == NULL)
355 return -ENOMEM;
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 if (serial->dev->descriptor.bDeviceClass == 0x02)
358 type = type_0;
359 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
360 type = HX;
361 else if (serial->dev->descriptor.bDeviceClass == 0x00)
362 type = type_1;
363 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
364 type = type_1;
365 dbg("device type: %d", type);
366
367 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100368 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 if (!priv)
370 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 spin_lock_init(&priv->lock);
372 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
373 if (priv->buf == NULL) {
374 kfree(priv);
375 goto cleanup;
376 }
377 init_waitqueue_head(&priv->delta_msr_wait);
378 priv->type = type;
379 usb_set_serial_port_data(serial->port[i], priv);
380 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800381
382 pl2303_vendor_read(0x8484, 0, serial, buf);
383 pl2303_vendor_write(0x0404, 0, serial);
384 pl2303_vendor_read(0x8484, 0, serial, buf);
385 pl2303_vendor_read(0x8383, 0, serial, buf);
386 pl2303_vendor_read(0x8484, 0, serial, buf);
387 pl2303_vendor_write(0x0404, 1, serial);
388 pl2303_vendor_read(0x8484, 0, serial, buf);
389 pl2303_vendor_read(0x8383, 0, serial, buf);
390 pl2303_vendor_write(0, 1, serial);
391 pl2303_vendor_write(1, 0, serial);
392 if (type == HX)
393 pl2303_vendor_write(2, 0x44, serial);
394 else
395 pl2303_vendor_write(2, 0x24, serial);
396
397 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 return 0;
399
400cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800401 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100402 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 priv = usb_get_serial_port_data(serial->port[i]);
404 pl2303_buf_free(priv->buf);
405 kfree(priv);
406 usb_set_serial_port_data(serial->port[i], NULL);
407 }
408 return -ENOMEM;
409}
410
Thiago Galesi372db8a2006-07-31 15:39:27 -0300411static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
413 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100414
Thiago Galesi372db8a2006-07-31 15:39:27 -0300415 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
416 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
417 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800418 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 return retval;
420}
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422static void pl2303_send(struct usb_serial_port *port)
423{
424 int count, result;
425 struct pl2303_private *priv = usb_get_serial_port_data(port);
426 unsigned long flags;
427
Harvey Harrison441b62c2008-03-03 16:08:34 -0800428 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
430 spin_lock_irqsave(&priv->lock, flags);
431
432 if (priv->write_urb_in_use) {
433 spin_unlock_irqrestore(&priv->lock, flags);
434 return;
435 }
436
437 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300438 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 if (count == 0) {
441 spin_unlock_irqrestore(&priv->lock, flags);
442 return;
443 }
444
445 priv->write_urb_in_use = 1;
446
447 spin_unlock_irqrestore(&priv->lock, flags);
448
Harvey Harrison441b62c2008-03-03 16:08:34 -0800449 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300450 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
452 port->write_urb->transfer_buffer_length = count;
453 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300454 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300456 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800457 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100459 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 }
461
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700462 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
Alan Cox95da3102008-07-22 11:09:07 +0100465static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
466 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300467{
468 struct pl2303_private *priv = usb_get_serial_port_data(port);
469 unsigned long flags;
470
Harvey Harrison441b62c2008-03-03 16:08:34 -0800471 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300472
473 if (!count)
474 return count;
475
476 spin_lock_irqsave(&priv->lock, flags);
477 count = pl2303_buf_put(priv->buf, buf, count);
478 spin_unlock_irqrestore(&priv->lock, flags);
479
480 pl2303_send(port);
481
482 return count;
483}
484
Alan Cox95da3102008-07-22 11:09:07 +0100485static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Alan Cox95da3102008-07-22 11:09:07 +0100487 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 struct pl2303_private *priv = usb_get_serial_port_data(port);
489 int room = 0;
490 unsigned long flags;
491
Harvey Harrison441b62c2008-03-03 16:08:34 -0800492 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494 spin_lock_irqsave(&priv->lock, flags);
495 room = pl2303_buf_space_avail(priv->buf);
496 spin_unlock_irqrestore(&priv->lock, flags);
497
Harvey Harrison441b62c2008-03-03 16:08:34 -0800498 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return room;
500}
501
Alan Cox95da3102008-07-22 11:09:07 +0100502static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
Alan Cox95da3102008-07-22 11:09:07 +0100504 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 struct pl2303_private *priv = usb_get_serial_port_data(port);
506 int chars = 0;
507 unsigned long flags;
508
Harvey Harrison441b62c2008-03-03 16:08:34 -0800509 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
511 spin_lock_irqsave(&priv->lock, flags);
512 chars = pl2303_buf_data_avail(priv->buf);
513 spin_unlock_irqrestore(&priv->lock, flags);
514
Harvey Harrison441b62c2008-03-03 16:08:34 -0800515 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 return chars;
517}
518
Alan Cox95da3102008-07-22 11:09:07 +0100519static void pl2303_set_termios(struct tty_struct *tty,
520 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
522 struct usb_serial *serial = port->serial;
523 struct pl2303_private *priv = usb_get_serial_port_data(port);
524 unsigned long flags;
525 unsigned int cflag;
526 unsigned char *buf;
527 int baud;
528 int i;
529 u8 control;
530
Harvey Harrison441b62c2008-03-03 16:08:34 -0800531 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
Alan Coxbf5e5832008-01-08 14:55:51 +0000533 /* The PL2303 is reported to lose bytes if you change
534 serial settings even to the same values as before. Thus
535 we actually need to filter in this specific case */
536
Alan Cox95da3102008-07-22 11:09:07 +0100537 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000538 return;
539
Alan Cox95da3102008-07-22 11:09:07 +0100540 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Thiago Galesi372db8a2006-07-31 15:39:27 -0300542 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800544 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100545 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100546 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 return;
548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Thiago Galesi372db8a2006-07-31 15:39:27 -0300550 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
551 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
552 0, 0, buf, 7, 100);
553 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
554 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 if (cflag & CSIZE) {
557 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100558 case CS5:
559 buf[6] = 5;
560 break;
561 case CS6:
562 buf[6] = 6;
563 break;
564 case CS7:
565 buf[6] = 7;
566 break;
567 default:
568 case CS8:
569 buf[6] = 8;
570 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800572 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 }
574
Alan Cox95da3102008-07-22 11:09:07 +0100575 baud = tty_get_baud_rate(tty);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800576 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 if (baud) {
578 buf[0] = baud & 0xff;
579 buf[1] = (baud >> 8) & 0xff;
580 buf[2] = (baud >> 16) & 0xff;
581 buf[3] = (baud >> 24) & 0xff;
582 }
583
584 /* For reference buf[4]=0 is 1 stop bits */
585 /* For reference buf[4]=1 is 1.5 stop bits */
586 /* For reference buf[4]=2 is 2 stop bits */
587 if (cflag & CSTOPB) {
588 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800589 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 } else {
591 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800592 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 }
594
595 if (cflag & PARENB) {
596 /* For reference buf[5]=0 is none parity */
597 /* For reference buf[5]=1 is odd parity */
598 /* For reference buf[5]=2 is even parity */
599 /* For reference buf[5]=3 is mark parity */
600 /* For reference buf[5]=4 is space parity */
601 if (cflag & PARODD) {
602 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800603 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 } else {
605 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800606 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 }
608 } else {
609 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800610 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 }
612
Thiago Galesi372db8a2006-07-31 15:39:27 -0300613 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
614 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
615 0, 0, buf, 7, 100);
616 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 /* change control lines if we are switching to or from B0 */
619 spin_lock_irqsave(&priv->lock, flags);
620 control = priv->line_control;
621 if ((cflag & CBAUD) == B0)
622 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
623 else
624 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
625 if (control != priv->line_control) {
626 control = priv->line_control;
627 spin_unlock_irqrestore(&priv->lock, flags);
628 set_control_lines(serial->dev, control);
629 } else {
630 spin_unlock_irqrestore(&priv->lock, flags);
631 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
634
Thiago Galesi372db8a2006-07-31 15:39:27 -0300635 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
636 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
637 0, 0, buf, 7, 100);
638 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
640
641 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800643 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800645 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200646 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800647 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
649
Alan Coxdf64c472007-10-15 20:54:47 +0100650 /* FIXME: Need to read back resulting baud rate */
651 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100652 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100653
Thiago Galesi372db8a2006-07-31 15:39:27 -0300654 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
Alan Cox335f8512009-06-11 12:26:29 +0100657static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
Thiago Galesi572d3132006-07-29 10:46:37 -0300658{
659 struct pl2303_private *priv = usb_get_serial_port_data(port);
660 unsigned long flags;
Alan Cox335f8512009-06-11 12:26:29 +0100661 u8 control;
662
663 spin_lock_irqsave(&priv->lock, flags);
664 /* Change DTR and RTS */
665 if (on)
666 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
667 else
668 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
669 control = priv->line_control;
670 spin_unlock_irqrestore(&priv->lock, flags);
671 set_control_lines(port->serial->dev, control);
672}
673
674static void pl2303_close(struct usb_serial_port *port)
675{
676 struct pl2303_private *priv = usb_get_serial_port_data(port);
677 unsigned long flags;
Thiago Galesi572d3132006-07-29 10:46:37 -0300678
Harvey Harrison441b62c2008-03-03 16:08:34 -0800679 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300680
Thiago Galesi572d3132006-07-29 10:46:37 -0300681 spin_lock_irqsave(&priv->lock, flags);
Thiago Galesi572d3132006-07-29 10:46:37 -0300682 /* clear out any remaining data in the buffer */
683 pl2303_buf_clear(priv->buf);
684 spin_unlock_irqrestore(&priv->lock, flags);
685
Thiago Galesi572d3132006-07-29 10:46:37 -0300686 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800687 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300688 usb_kill_urb(port->write_urb);
689 usb_kill_urb(port->read_urb);
690 usb_kill_urb(port->interrupt_in_urb);
691
Thiago Galesi572d3132006-07-29 10:46:37 -0300692}
693
Alan Coxa509a7e2009-09-19 13:13:26 -0700694static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Alan Cox606d0992006-12-08 02:38:45 -0800696 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 struct usb_serial *serial = port->serial;
698 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 int result;
700
Harvey Harrison441b62c2008-03-03 16:08:34 -0800701 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Dariusz M16948992005-07-28 18:06:13 +0200703 if (priv->type != HX) {
704 usb_clear_halt(serial->dev, port->write_urb->pipe);
705 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800706 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800708 pl2303_vendor_write(8, 0, serial);
709 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 }
711
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100713 if (tty)
714 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Harvey Harrison441b62c2008-03-03 16:08:34 -0800716 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300718 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300720 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800721 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100722 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return -EPROTO;
724 }
725
Harvey Harrison441b62c2008-03-03 16:08:34 -0800726 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300728 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300730 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800731 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100732 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 return -EPROTO;
734 }
Alan Cox335f8512009-06-11 12:26:29 +0100735 port->port.drain_delay = 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return 0;
737}
738
Alan Cox95da3102008-07-22 11:09:07 +0100739static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300740 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Alan Cox95da3102008-07-22 11:09:07 +0100742 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 struct pl2303_private *priv = usb_get_serial_port_data(port);
744 unsigned long flags;
745 u8 control;
746
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700747 if (!usb_get_intfdata(port->serial->interface))
748 return -ENODEV;
749
Thiago Galesi372db8a2006-07-31 15:39:27 -0300750 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (set & TIOCM_RTS)
752 priv->line_control |= CONTROL_RTS;
753 if (set & TIOCM_DTR)
754 priv->line_control |= CONTROL_DTR;
755 if (clear & TIOCM_RTS)
756 priv->line_control &= ~CONTROL_RTS;
757 if (clear & TIOCM_DTR)
758 priv->line_control &= ~CONTROL_DTR;
759 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300760 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Thiago Galesi372db8a2006-07-31 15:39:27 -0300762 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}
764
Alan Cox95da3102008-07-22 11:09:07 +0100765static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Alan Cox95da3102008-07-22 11:09:07 +0100767 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 struct pl2303_private *priv = usb_get_serial_port_data(port);
769 unsigned long flags;
770 unsigned int mcr;
771 unsigned int status;
772 unsigned int result;
773
Harvey Harrison441b62c2008-03-03 16:08:34 -0800774 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700776 if (!usb_get_intfdata(port->serial->interface))
777 return -ENODEV;
778
Thiago Galesi372db8a2006-07-31 15:39:27 -0300779 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 mcr = priv->line_control;
781 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300782 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
785 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
786 | ((status & UART_CTS) ? TIOCM_CTS : 0)
787 | ((status & UART_DSR) ? TIOCM_DSR : 0)
788 | ((status & UART_RING) ? TIOCM_RI : 0)
789 | ((status & UART_DCD) ? TIOCM_CD : 0);
790
Harvey Harrison441b62c2008-03-03 16:08:34 -0800791 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 return result;
794}
795
Alan Cox335f8512009-06-11 12:26:29 +0100796static int pl2303_carrier_raised(struct usb_serial_port *port)
797{
798 struct pl2303_private *priv = usb_get_serial_port_data(port);
799 if (priv->line_status & UART_DCD)
800 return 1;
801 return 0;
802}
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
805{
806 struct pl2303_private *priv = usb_get_serial_port_data(port);
807 unsigned long flags;
808 unsigned int prevstatus;
809 unsigned int status;
810 unsigned int changed;
811
Thiago Galesi372db8a2006-07-31 15:39:27 -0300812 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300814 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 while (1) {
817 interruptible_sleep_on(&priv->delta_msr_wait);
818 /* see if a signal did it */
819 if (signal_pending(current))
820 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300821
822 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300824 spin_unlock_irqrestore(&priv->lock, flags);
825
Alan Cox3a0f43e2008-07-22 11:14:49 +0100826 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300827
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
829 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
830 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100831 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return 0;
833 }
834 prevstatus = status;
835 }
836 /* NOTREACHED */
837 return 0;
838}
839
Alan Cox95da3102008-07-22 11:09:07 +0100840static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300841 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
Alan Cox95da3102008-07-22 11:09:07 +0100843 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800844 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100847 case TIOCMIWAIT:
848 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
849 return wait_modem_info(port, arg);
850 default:
851 dbg("%s not supported = 0x%04x", __func__, cmd);
852 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 return -ENOIOCTLCMD;
855}
856
Alan Cox95da3102008-07-22 11:09:07 +0100857static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858{
Alan Cox95da3102008-07-22 11:09:07 +0100859 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 struct usb_serial *serial = port->serial;
861 u16 state;
862 int result;
863
Harvey Harrison441b62c2008-03-03 16:08:34 -0800864 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 if (break_state == 0)
867 state = BREAK_OFF;
868 else
869 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100870 dbg("%s - turning break %s", __func__,
871 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Thiago Galesi372db8a2006-07-31 15:39:27 -0300873 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
874 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
875 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800877 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878}
879
Alan Sternf9c99bb2009-06-02 11:53:55 -0400880static void pl2303_release(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
882 int i;
883 struct pl2303_private *priv;
884
Harvey Harrison441b62c2008-03-03 16:08:34 -0800885 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
887 for (i = 0; i < serial->num_ports; ++i) {
888 priv = usb_get_serial_port_data(serial->port[i]);
889 if (priv) {
890 pl2303_buf_free(priv->buf);
891 kfree(priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894}
895
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700896static void pl2303_update_line_status(struct usb_serial_port *port,
897 unsigned char *data,
898 unsigned int actual_length)
899{
900
901 struct pl2303_private *priv = usb_get_serial_port_data(port);
902 unsigned long flags;
903 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200904 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300905 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700906
Thiago Galesi9c537612006-07-29 10:47:12 -0300907 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
908 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
909
910
911 if (idv == SIEMENS_VENDOR_ID) {
912 if (idp == SIEMENS_PRODUCT_ID_X65 ||
913 idp == SIEMENS_PRODUCT_ID_SX1 ||
914 idp == SIEMENS_PRODUCT_ID_X75) {
915
916 length = 1;
917 status_idx = 0;
918 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700919 }
920
921 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300922 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700923
Alan Cox3a0f43e2008-07-22 11:14:49 +0100924 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700925 spin_lock_irqsave(&priv->lock, flags);
926 priv->line_status = data[status_idx];
927 spin_unlock_irqrestore(&priv->lock, flags);
Jason Wessel430eb0d2009-05-29 13:34:16 -0500928 if (priv->line_status & UART_BREAK_ERROR)
929 usb_serial_handle_break(port);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300930 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700931}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
David Howells7d12e782006-10-05 14:55:46 +0100933static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
Ming Leicdc97792008-02-24 18:41:47 +0800935 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700937 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700938 int status = urb->status;
939 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Harvey Harrison441b62c2008-03-03 16:08:34 -0800941 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700943 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 case 0:
945 /* success */
946 break;
947 case -ECONNRESET:
948 case -ENOENT:
949 case -ESHUTDOWN:
950 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800951 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700952 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 return;
954 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800955 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700956 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 goto exit;
958 }
959
Harvey Harrison441b62c2008-03-03 16:08:34 -0800960 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300961 urb->actual_length, urb->transfer_buffer);
962
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700963 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700966 retval = usb_submit_urb(urb, GFP_ATOMIC);
967 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300968 dev_err(&urb->dev->dev,
969 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800970 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971}
972
Alan Coxd4fc4a72009-07-09 13:36:58 +0100973static void pl2303_push_data(struct tty_struct *tty,
974 struct usb_serial_port *port, struct urb *urb,
975 u8 line_status)
976{
977 unsigned char *data = urb->transfer_buffer;
978 /* get tty_flag from status */
979 char tty_flag = TTY_NORMAL;
980 /* break takes precedence over parity, */
981 /* which takes precedence over framing errors */
982 if (line_status & UART_BREAK_ERROR)
983 tty_flag = TTY_BREAK;
984 else if (line_status & UART_PARITY_ERROR)
985 tty_flag = TTY_PARITY;
986 else if (line_status & UART_FRAME_ERROR)
987 tty_flag = TTY_FRAME;
988 dbg("%s - tty_flag = %d", __func__, tty_flag);
989
990 tty_buffer_request_room(tty, urb->actual_length + 1);
991 /* overrun is special, not associated with a char */
992 if (line_status & UART_OVERRUN_ERROR)
993 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
994 if (port->console && port->sysrq) {
995 int i;
996 for (i = 0; i < urb->actual_length; ++i)
997 if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
998 tty_insert_flip_char(tty, data[i], tty_flag);
999 } else
1000 tty_insert_flip_string(tty, data, urb->actual_length);
1001 tty_flip_buffer_push(tty);
1002}
1003
David Howells7d12e782006-10-05 14:55:46 +01001004static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005{
Ming Leicdc97792008-02-24 18:41:47 +08001006 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 struct pl2303_private *priv = usb_get_serial_port_data(port);
1008 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001011 int status = urb->status;
1012 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
Harvey Harrison441b62c2008-03-03 16:08:34 -08001014 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001016 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001017 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001018 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001019 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return;
1021 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001022 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001023 /* PL2303 mysteriously fails with -EPROTO reschedule
1024 * the read */
1025 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001026 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 urb->dev = port->serial->dev;
1028 result = usb_submit_urb(urb, GFP_ATOMIC);
1029 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001030 dev_err(&urb->dev->dev, "%s - failed"
1031 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001032 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 return;
1034 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001035 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return;
1037 }
1038
Harvey Harrison441b62c2008-03-03 16:08:34 -08001039 usb_serial_debug_data(debug, &port->dev, __func__,
Alan Coxd4fc4a72009-07-09 13:36:58 +01001040 urb->actual_length, urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001043 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1045 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001046 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Alan Cox4a90f092008-10-13 10:39:46 +01001048 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 if (tty && urb->actual_length) {
Alan Coxd4fc4a72009-07-09 13:36:58 +01001050 pl2303_push_data(tty, port, urb, line_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
Alan Cox4a90f092008-10-13 10:39:46 +01001052 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001054 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 urb->dev = port->serial->dev;
1056 result = usb_submit_urb(urb, GFP_ATOMIC);
1057 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001058 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001059 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
1061
1062 return;
1063}
1064
David Howells7d12e782006-10-05 14:55:46 +01001065static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
Ming Leicdc97792008-02-24 18:41:47 +08001067 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 struct pl2303_private *priv = usb_get_serial_port_data(port);
1069 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001070 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Harvey Harrison441b62c2008-03-03 16:08:34 -08001072 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001074 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 case 0:
1076 /* success */
1077 break;
1078 case -ECONNRESET:
1079 case -ENOENT:
1080 case -ESHUTDOWN:
1081 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001082 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001083 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 priv->write_urb_in_use = 0;
1085 return;
1086 default:
1087 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001088 dbg("%s - Overflow in write", __func__);
1089 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001090 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 port->write_urb->transfer_buffer_length = 1;
1092 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001093 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001095 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001096 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 else
1098 return;
1099 }
1100
1101 priv->write_urb_in_use = 0;
1102
1103 /* send any buffered data */
1104 pl2303_send(port);
1105}
1106
Thiago Galesi572d3132006-07-29 10:46:37 -03001107/* All of the device info needed for the PL2303 SIO serial converter */
1108static struct usb_serial_driver pl2303_device = {
1109 .driver = {
1110 .owner = THIS_MODULE,
1111 .name = "pl2303",
1112 },
1113 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001114 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001115 .num_ports = 1,
1116 .open = pl2303_open,
1117 .close = pl2303_close,
Alan Cox335f8512009-06-11 12:26:29 +01001118 .dtr_rts = pl2303_dtr_rts,
1119 .carrier_raised = pl2303_carrier_raised,
Thiago Galesi572d3132006-07-29 10:46:37 -03001120 .write = pl2303_write,
1121 .ioctl = pl2303_ioctl,
1122 .break_ctl = pl2303_break_ctl,
1123 .set_termios = pl2303_set_termios,
1124 .tiocmget = pl2303_tiocmget,
1125 .tiocmset = pl2303_tiocmset,
1126 .read_bulk_callback = pl2303_read_bulk_callback,
1127 .read_int_callback = pl2303_read_int_callback,
1128 .write_bulk_callback = pl2303_write_bulk_callback,
1129 .write_room = pl2303_write_room,
1130 .chars_in_buffer = pl2303_chars_in_buffer,
1131 .attach = pl2303_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -04001132 .release = pl2303_release,
Thiago Galesi572d3132006-07-29 10:46:37 -03001133};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Thiago Galesi372db8a2006-07-31 15:39:27 -03001135static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136{
1137 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 retval = usb_serial_register(&pl2303_device);
1140 if (retval)
1141 goto failed_usb_serial_register;
1142 retval = usb_register(&pl2303_driver);
1143 if (retval)
1144 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001145 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 return 0;
1147failed_usb_register:
1148 usb_serial_deregister(&pl2303_device);
1149failed_usb_serial_register:
1150 return retval;
1151}
1152
Thiago Galesi372db8a2006-07-31 15:39:27 -03001153static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001155 usb_deregister(&pl2303_driver);
1156 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157}
1158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159module_init(pl2303_init);
1160module_exit(pl2303_exit);
1161
1162MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163MODULE_LICENSE("GPL");
1164
1165module_param(debug, bool, S_IRUGO | S_IWUSR);
1166MODULE_PARM_DESC(debug, "Debug enabled or not");
1167