blob: 1aed584be5eb9a528d904b3b3209afef29f40383 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Prolific PL2303 USB to serial adaptor driver
3 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07004 * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2003 IBM Corp.
6 *
7 * Original driver for 2.2.x by anonymous
8 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07009 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 *
Alan Cox3a0f43e2008-07-22 11:14:49 +010013 * See Documentation/usb/usb-serial.txt for more information on using this
14 * driver
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/kernel.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22#include <linux/tty.h>
23#include <linux/tty_driver.h>
24#include <linux/tty_flip.h>
25#include <linux/serial.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/spinlock.h>
Alan Cox3a0f43e2008-07-22 11:14:49 +010029#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070031#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "pl2303.h"
33
34/*
35 * Version Information
36 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
38
39static int debug;
40
41#define PL2303_CLOSING_WAIT (30*HZ)
42
43#define PL2303_BUF_SIZE 1024
44#define PL2303_TMP_BUF_SIZE 1024
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046struct pl2303_buf {
47 unsigned int buf_size;
48 char *buf_buf;
49 char *buf_get;
50 char *buf_put;
51};
52
53static struct usb_device_id id_table [] = {
54 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
55 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100056 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
58 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070059 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053060 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050061 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090063 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
65 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
66 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
67 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
68 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080069 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
71 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
72 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
73 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
74 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
75 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
76 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
77 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080078 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080080 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020081 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070082 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010083 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
84 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010085 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010086 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080087 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040088 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100089 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020090 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090091 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090092 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050093 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Matthew Arnold7c992002008-12-13 22:42:53 +110094 { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
Mike Provencheraf4b8512008-12-16 14:30:14 -060095 { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 { } /* Terminating entry */
97};
98
Thiago Galesi372db8a2006-07-31 15:39:27 -030099MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 .name = "pl2303",
103 .probe = usb_serial_probe,
104 .disconnect = usb_serial_disconnect,
105 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800106 .suspend = usb_serial_suspend,
107 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800108 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800109 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110};
111
112#define SET_LINE_REQUEST_TYPE 0x21
113#define SET_LINE_REQUEST 0x20
114
115#define SET_CONTROL_REQUEST_TYPE 0x21
116#define SET_CONTROL_REQUEST 0x22
117#define CONTROL_DTR 0x01
118#define CONTROL_RTS 0x02
119
120#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100121#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#define BREAK_ON 0xffff
123#define BREAK_OFF 0x0000
124
125#define GET_LINE_REQUEST_TYPE 0xa1
126#define GET_LINE_REQUEST 0x21
127
128#define VENDOR_WRITE_REQUEST_TYPE 0x40
129#define VENDOR_WRITE_REQUEST 0x01
130
131#define VENDOR_READ_REQUEST_TYPE 0xc0
132#define VENDOR_READ_REQUEST 0x01
133
134#define UART_STATE 0x08
135#define UART_STATE_TRANSIENT_MASK 0x74
136#define UART_DCD 0x01
137#define UART_DSR 0x02
138#define UART_BREAK_ERROR 0x04
139#define UART_RING 0x08
140#define UART_FRAME_ERROR 0x10
141#define UART_PARITY_ERROR 0x20
142#define UART_OVERRUN_ERROR 0x40
143#define UART_CTS 0x80
144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146enum pl2303_type {
147 type_0, /* don't know the difference between type 0 and */
148 type_1, /* type 1, until someone from prolific tells us... */
149 HX, /* HX version of the pl2303 chip */
150};
151
152struct pl2303_private {
153 spinlock_t lock;
154 struct pl2303_buf *buf;
155 int write_urb_in_use;
156 wait_queue_head_t delta_msr_wait;
157 u8 line_control;
158 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 enum pl2303_type type;
160};
161
Thiago Galesi572d3132006-07-29 10:46:37 -0300162/*
163 * pl2303_buf_alloc
164 *
165 * Allocate a circular buffer and all associated memory.
166 */
167static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
168{
169 struct pl2303_buf *pb;
170
171 if (size == 0)
172 return NULL;
173
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800174 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300175 if (pb == NULL)
176 return NULL;
177
178 pb->buf_buf = kmalloc(size, GFP_KERNEL);
179 if (pb->buf_buf == NULL) {
180 kfree(pb);
181 return NULL;
182 }
183
184 pb->buf_size = size;
185 pb->buf_get = pb->buf_put = pb->buf_buf;
186
187 return pb;
188}
189
190/*
191 * pl2303_buf_free
192 *
193 * Free the buffer and all associated memory.
194 */
195static void pl2303_buf_free(struct pl2303_buf *pb)
196{
197 if (pb) {
198 kfree(pb->buf_buf);
199 kfree(pb);
200 }
201}
202
203/*
204 * pl2303_buf_clear
205 *
206 * Clear out all data in the circular buffer.
207 */
208static void pl2303_buf_clear(struct pl2303_buf *pb)
209{
210 if (pb != NULL)
211 pb->buf_get = pb->buf_put;
212 /* equivalent to a get of all data available */
213}
214
215/*
216 * pl2303_buf_data_avail
217 *
218 * Return the number of bytes of data available in the circular
219 * buffer.
220 */
221static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
222{
223 if (pb == NULL)
224 return 0;
225
Alan Cox3a0f43e2008-07-22 11:14:49 +0100226 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300227}
228
229/*
230 * pl2303_buf_space_avail
231 *
232 * Return the number of bytes of space available in the circular
233 * buffer.
234 */
235static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
236{
237 if (pb == NULL)
238 return 0;
239
Alan Cox3a0f43e2008-07-22 11:14:49 +0100240 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300241}
242
243/*
244 * pl2303_buf_put
245 *
246 * Copy data data from a user buffer and put it into the circular buffer.
247 * Restrict to the amount of space available.
248 *
249 * Return the number of bytes copied.
250 */
251static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
252 unsigned int count)
253{
254 unsigned int len;
255
256 if (pb == NULL)
257 return 0;
258
259 len = pl2303_buf_space_avail(pb);
260 if (count > len)
261 count = len;
262
263 if (count == 0)
264 return 0;
265
266 len = pb->buf_buf + pb->buf_size - pb->buf_put;
267 if (count > len) {
268 memcpy(pb->buf_put, buf, len);
269 memcpy(pb->buf_buf, buf+len, count - len);
270 pb->buf_put = pb->buf_buf + count - len;
271 } else {
272 memcpy(pb->buf_put, buf, count);
273 if (count < len)
274 pb->buf_put += count;
275 else /* count == len */
276 pb->buf_put = pb->buf_buf;
277 }
278
279 return count;
280}
281
282/*
283 * pl2303_buf_get
284 *
285 * Get data from the circular buffer and copy to the given buffer.
286 * Restrict to the amount of data available.
287 *
288 * Return the number of bytes copied.
289 */
290static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
291 unsigned int count)
292{
293 unsigned int len;
294
295 if (pb == NULL)
296 return 0;
297
298 len = pl2303_buf_data_avail(pb);
299 if (count > len)
300 count = len;
301
302 if (count == 0)
303 return 0;
304
305 len = pb->buf_buf + pb->buf_size - pb->buf_get;
306 if (count > len) {
307 memcpy(buf, pb->buf_get, len);
308 memcpy(buf+len, pb->buf_buf, count - len);
309 pb->buf_get = pb->buf_buf + count - len;
310 } else {
311 memcpy(buf, pb->buf_get, count);
312 if (count < len)
313 pb->buf_get += count;
314 else /* count == len */
315 pb->buf_get = pb->buf_buf;
316 }
317
318 return count;
319}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Sarah Sharpeb44da02007-12-14 14:08:00 -0800321static int pl2303_vendor_read(__u16 value, __u16 index,
322 struct usb_serial *serial, unsigned char *buf)
323{
324 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
325 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
326 value, index, buf, 1, 100);
327 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
328 VENDOR_READ_REQUEST, value, index, res, buf[0]);
329 return res;
330}
331
332static int pl2303_vendor_write(__u16 value, __u16 index,
333 struct usb_serial *serial)
334{
335 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
336 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
337 value, index, NULL, 0, 100);
338 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
339 VENDOR_WRITE_REQUEST, value, index, res);
340 return res;
341}
342
Thiago Galesi372db8a2006-07-31 15:39:27 -0300343static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
345 struct pl2303_private *priv;
346 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800347 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 int i;
349
Sarah Sharp3e152502007-12-14 14:08:35 -0800350 buf = kmalloc(10, GFP_KERNEL);
351 if (buf == NULL)
352 return -ENOMEM;
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 if (serial->dev->descriptor.bDeviceClass == 0x02)
355 type = type_0;
356 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
357 type = HX;
358 else if (serial->dev->descriptor.bDeviceClass == 0x00)
359 type = type_1;
360 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
361 type = type_1;
362 dbg("device type: %d", type);
363
364 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100365 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 if (!priv)
367 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 spin_lock_init(&priv->lock);
369 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
370 if (priv->buf == NULL) {
371 kfree(priv);
372 goto cleanup;
373 }
374 init_waitqueue_head(&priv->delta_msr_wait);
375 priv->type = type;
376 usb_set_serial_port_data(serial->port[i], priv);
377 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800378
379 pl2303_vendor_read(0x8484, 0, serial, buf);
380 pl2303_vendor_write(0x0404, 0, serial);
381 pl2303_vendor_read(0x8484, 0, serial, buf);
382 pl2303_vendor_read(0x8383, 0, serial, buf);
383 pl2303_vendor_read(0x8484, 0, serial, buf);
384 pl2303_vendor_write(0x0404, 1, serial);
385 pl2303_vendor_read(0x8484, 0, serial, buf);
386 pl2303_vendor_read(0x8383, 0, serial, buf);
387 pl2303_vendor_write(0, 1, serial);
388 pl2303_vendor_write(1, 0, serial);
389 if (type == HX)
390 pl2303_vendor_write(2, 0x44, serial);
391 else
392 pl2303_vendor_write(2, 0x24, serial);
393
394 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return 0;
396
397cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800398 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100399 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 priv = usb_get_serial_port_data(serial->port[i]);
401 pl2303_buf_free(priv->buf);
402 kfree(priv);
403 usb_set_serial_port_data(serial->port[i], NULL);
404 }
405 return -ENOMEM;
406}
407
Thiago Galesi372db8a2006-07-31 15:39:27 -0300408static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
410 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100411
Thiago Galesi372db8a2006-07-31 15:39:27 -0300412 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
413 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
414 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800415 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 return retval;
417}
418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419static void pl2303_send(struct usb_serial_port *port)
420{
421 int count, result;
422 struct pl2303_private *priv = usb_get_serial_port_data(port);
423 unsigned long flags;
424
Harvey Harrison441b62c2008-03-03 16:08:34 -0800425 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 spin_lock_irqsave(&priv->lock, flags);
428
429 if (priv->write_urb_in_use) {
430 spin_unlock_irqrestore(&priv->lock, flags);
431 return;
432 }
433
434 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300435 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 if (count == 0) {
438 spin_unlock_irqrestore(&priv->lock, flags);
439 return;
440 }
441
442 priv->write_urb_in_use = 1;
443
444 spin_unlock_irqrestore(&priv->lock, flags);
445
Harvey Harrison441b62c2008-03-03 16:08:34 -0800446 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300447 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449 port->write_urb->transfer_buffer_length = count;
450 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300451 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300453 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800454 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100456 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
458
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700459 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
Alan Cox95da3102008-07-22 11:09:07 +0100462static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
463 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300464{
465 struct pl2303_private *priv = usb_get_serial_port_data(port);
466 unsigned long flags;
467
Harvey Harrison441b62c2008-03-03 16:08:34 -0800468 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300469
470 if (!count)
471 return count;
472
473 spin_lock_irqsave(&priv->lock, flags);
474 count = pl2303_buf_put(priv->buf, buf, count);
475 spin_unlock_irqrestore(&priv->lock, flags);
476
477 pl2303_send(port);
478
479 return count;
480}
481
Alan Cox95da3102008-07-22 11:09:07 +0100482static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Alan Cox95da3102008-07-22 11:09:07 +0100484 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 struct pl2303_private *priv = usb_get_serial_port_data(port);
486 int room = 0;
487 unsigned long flags;
488
Harvey Harrison441b62c2008-03-03 16:08:34 -0800489 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 spin_lock_irqsave(&priv->lock, flags);
492 room = pl2303_buf_space_avail(priv->buf);
493 spin_unlock_irqrestore(&priv->lock, flags);
494
Harvey Harrison441b62c2008-03-03 16:08:34 -0800495 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 return room;
497}
498
Alan Cox95da3102008-07-22 11:09:07 +0100499static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
Alan Cox95da3102008-07-22 11:09:07 +0100501 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 struct pl2303_private *priv = usb_get_serial_port_data(port);
503 int chars = 0;
504 unsigned long flags;
505
Harvey Harrison441b62c2008-03-03 16:08:34 -0800506 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 spin_lock_irqsave(&priv->lock, flags);
509 chars = pl2303_buf_data_avail(priv->buf);
510 spin_unlock_irqrestore(&priv->lock, flags);
511
Harvey Harrison441b62c2008-03-03 16:08:34 -0800512 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 return chars;
514}
515
Alan Cox95da3102008-07-22 11:09:07 +0100516static void pl2303_set_termios(struct tty_struct *tty,
517 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
519 struct usb_serial *serial = port->serial;
520 struct pl2303_private *priv = usb_get_serial_port_data(port);
521 unsigned long flags;
522 unsigned int cflag;
523 unsigned char *buf;
524 int baud;
525 int i;
526 u8 control;
527
Harvey Harrison441b62c2008-03-03 16:08:34 -0800528 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Alan Coxbf5e5832008-01-08 14:55:51 +0000530 /* The PL2303 is reported to lose bytes if you change
531 serial settings even to the same values as before. Thus
532 we actually need to filter in this specific case */
533
Alan Cox95da3102008-07-22 11:09:07 +0100534 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000535 return;
536
Alan Cox95da3102008-07-22 11:09:07 +0100537 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Thiago Galesi372db8a2006-07-31 15:39:27 -0300539 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800541 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100542 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100543 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 return;
545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Thiago Galesi372db8a2006-07-31 15:39:27 -0300547 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
548 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
549 0, 0, buf, 7, 100);
550 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
551 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 if (cflag & CSIZE) {
554 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100555 case CS5:
556 buf[6] = 5;
557 break;
558 case CS6:
559 buf[6] = 6;
560 break;
561 case CS7:
562 buf[6] = 7;
563 break;
564 default:
565 case CS8:
566 buf[6] = 8;
567 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800569 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
571
Alan Cox95da3102008-07-22 11:09:07 +0100572 baud = tty_get_baud_rate(tty);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800573 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 if (baud) {
575 buf[0] = baud & 0xff;
576 buf[1] = (baud >> 8) & 0xff;
577 buf[2] = (baud >> 16) & 0xff;
578 buf[3] = (baud >> 24) & 0xff;
579 }
580
581 /* For reference buf[4]=0 is 1 stop bits */
582 /* For reference buf[4]=1 is 1.5 stop bits */
583 /* For reference buf[4]=2 is 2 stop bits */
584 if (cflag & CSTOPB) {
585 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800586 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 } else {
588 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800589 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
591
592 if (cflag & PARENB) {
593 /* For reference buf[5]=0 is none parity */
594 /* For reference buf[5]=1 is odd parity */
595 /* For reference buf[5]=2 is even parity */
596 /* For reference buf[5]=3 is mark parity */
597 /* For reference buf[5]=4 is space parity */
598 if (cflag & PARODD) {
599 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800600 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 } else {
602 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800603 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 }
605 } else {
606 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800607 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
609
Thiago Galesi372db8a2006-07-31 15:39:27 -0300610 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
611 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
612 0, 0, buf, 7, 100);
613 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 /* change control lines if we are switching to or from B0 */
616 spin_lock_irqsave(&priv->lock, flags);
617 control = priv->line_control;
618 if ((cflag & CBAUD) == B0)
619 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
620 else
621 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
622 if (control != priv->line_control) {
623 control = priv->line_control;
624 spin_unlock_irqrestore(&priv->lock, flags);
625 set_control_lines(serial->dev, control);
626 } else {
627 spin_unlock_irqrestore(&priv->lock, flags);
628 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
631
Thiago Galesi372db8a2006-07-31 15:39:27 -0300632 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
633 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
634 0, 0, buf, 7, 100);
635 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
637
638 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800640 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800642 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200643 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800644 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
646
Alan Coxdf64c472007-10-15 20:54:47 +0100647 /* FIXME: Need to read back resulting baud rate */
648 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100649 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100650
Thiago Galesi372db8a2006-07-31 15:39:27 -0300651 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652}
653
Alan Cox95da3102008-07-22 11:09:07 +0100654static void pl2303_close(struct tty_struct *tty,
655 struct usb_serial_port *port, struct file *filp)
Thiago Galesi572d3132006-07-29 10:46:37 -0300656{
657 struct pl2303_private *priv = usb_get_serial_port_data(port);
658 unsigned long flags;
659 unsigned int c_cflag;
660 int bps;
661 long timeout;
662 wait_queue_t wait;
663
Harvey Harrison441b62c2008-03-03 16:08:34 -0800664 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300665
666 /* wait for data to drain from the buffer */
667 spin_lock_irqsave(&priv->lock, flags);
668 timeout = PL2303_CLOSING_WAIT;
669 init_waitqueue_entry(&wait, current);
Alan Cox95da3102008-07-22 11:09:07 +0100670 add_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300671 for (;;) {
672 set_current_state(TASK_INTERRUPTIBLE);
673 if (pl2303_buf_data_avail(priv->buf) == 0 ||
674 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100675 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300676 break;
677 spin_unlock_irqrestore(&priv->lock, flags);
678 timeout = schedule_timeout(timeout);
679 spin_lock_irqsave(&priv->lock, flags);
680 }
681 set_current_state(TASK_RUNNING);
Alan Cox95da3102008-07-22 11:09:07 +0100682 remove_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300683 /* clear out any remaining data in the buffer */
684 pl2303_buf_clear(priv->buf);
685 spin_unlock_irqrestore(&priv->lock, flags);
686
687 /* wait for characters to drain from the device */
688 /* (this is long enough for the entire 256 byte */
689 /* pl2303 hardware buffer to drain with no flow */
690 /* control for data rates of 1200 bps or more, */
691 /* for lower rates we should really know how much */
692 /* data is in the buffer to compute a delay */
693 /* that is not unnecessarily long) */
Alan Cox95da3102008-07-22 11:09:07 +0100694 bps = tty_get_baud_rate(tty);
Thiago Galesi572d3132006-07-29 10:46:37 -0300695 if (bps > 1200)
Alan Cox3a0f43e2008-07-22 11:14:49 +0100696 timeout = max((HZ*2560)/bps, HZ/10);
Thiago Galesi572d3132006-07-29 10:46:37 -0300697 else
698 timeout = 2*HZ;
699 schedule_timeout_interruptible(timeout);
700
701 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800702 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300703 usb_kill_urb(port->write_urb);
704 usb_kill_urb(port->read_urb);
705 usb_kill_urb(port->interrupt_in_urb);
706
Alan Cox95da3102008-07-22 11:09:07 +0100707 if (tty) {
708 c_cflag = tty->termios->c_cflag;
Thiago Galesi572d3132006-07-29 10:46:37 -0300709 if (c_cflag & HUPCL) {
710 /* drop DTR and RTS */
711 spin_lock_irqsave(&priv->lock, flags);
712 priv->line_control = 0;
713 spin_unlock_irqrestore(&priv->lock, flags);
714 set_control_lines(port->serial->dev, 0);
715 }
716 }
717}
718
Alan Cox95da3102008-07-22 11:09:07 +0100719static int pl2303_open(struct tty_struct *tty,
720 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Alan Cox606d0992006-12-08 02:38:45 -0800722 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 struct usb_serial *serial = port->serial;
724 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 int result;
726
Harvey Harrison441b62c2008-03-03 16:08:34 -0800727 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Dariusz M16948992005-07-28 18:06:13 +0200729 if (priv->type != HX) {
730 usb_clear_halt(serial->dev, port->write_urb->pipe);
731 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800732 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800734 pl2303_vendor_write(8, 0, serial);
735 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100739 if (tty)
740 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Alan Cox3a0f43e2008-07-22 11:14:49 +0100742 /* FIXME: need to assert RTS and DTR if CRTSCTS off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Harvey Harrison441b62c2008-03-03 16:08:34 -0800744 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300746 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300748 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800749 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100750 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return -EPROTO;
752 }
753
Harvey Harrison441b62c2008-03-03 16:08:34 -0800754 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300756 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300758 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800759 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100760 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return -EPROTO;
762 }
763 return 0;
764}
765
Alan Cox95da3102008-07-22 11:09:07 +0100766static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300767 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
Alan Cox95da3102008-07-22 11:09:07 +0100769 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 struct pl2303_private *priv = usb_get_serial_port_data(port);
771 unsigned long flags;
772 u8 control;
773
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700774 if (!usb_get_intfdata(port->serial->interface))
775 return -ENODEV;
776
Thiago Galesi372db8a2006-07-31 15:39:27 -0300777 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 if (set & TIOCM_RTS)
779 priv->line_control |= CONTROL_RTS;
780 if (set & TIOCM_DTR)
781 priv->line_control |= CONTROL_DTR;
782 if (clear & TIOCM_RTS)
783 priv->line_control &= ~CONTROL_RTS;
784 if (clear & TIOCM_DTR)
785 priv->line_control &= ~CONTROL_DTR;
786 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300787 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Thiago Galesi372db8a2006-07-31 15:39:27 -0300789 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790}
791
Alan Cox95da3102008-07-22 11:09:07 +0100792static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
Alan Cox95da3102008-07-22 11:09:07 +0100794 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 struct pl2303_private *priv = usb_get_serial_port_data(port);
796 unsigned long flags;
797 unsigned int mcr;
798 unsigned int status;
799 unsigned int result;
800
Harvey Harrison441b62c2008-03-03 16:08:34 -0800801 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700803 if (!usb_get_intfdata(port->serial->interface))
804 return -ENODEV;
805
Thiago Galesi372db8a2006-07-31 15:39:27 -0300806 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 mcr = priv->line_control;
808 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300809 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
812 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
813 | ((status & UART_CTS) ? TIOCM_CTS : 0)
814 | ((status & UART_DSR) ? TIOCM_DSR : 0)
815 | ((status & UART_RING) ? TIOCM_RI : 0)
816 | ((status & UART_DCD) ? TIOCM_CD : 0);
817
Harvey Harrison441b62c2008-03-03 16:08:34 -0800818 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820 return result;
821}
822
823static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
824{
825 struct pl2303_private *priv = usb_get_serial_port_data(port);
826 unsigned long flags;
827 unsigned int prevstatus;
828 unsigned int status;
829 unsigned int changed;
830
Thiago Galesi372db8a2006-07-31 15:39:27 -0300831 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300833 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 while (1) {
836 interruptible_sleep_on(&priv->delta_msr_wait);
837 /* see if a signal did it */
838 if (signal_pending(current))
839 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300840
841 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300843 spin_unlock_irqrestore(&priv->lock, flags);
844
Alan Cox3a0f43e2008-07-22 11:14:49 +0100845 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
848 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
849 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100850 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return 0;
852 }
853 prevstatus = status;
854 }
855 /* NOTREACHED */
856 return 0;
857}
858
Alan Cox95da3102008-07-22 11:09:07 +0100859static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300860 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
Alan Cox95da3102008-07-22 11:09:07 +0100862 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800863 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
865 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100866 case TIOCMIWAIT:
867 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
868 return wait_modem_info(port, arg);
869 default:
870 dbg("%s not supported = 0x%04x", __func__, cmd);
871 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 return -ENOIOCTLCMD;
874}
875
Alan Cox95da3102008-07-22 11:09:07 +0100876static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
Alan Cox95da3102008-07-22 11:09:07 +0100878 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 struct usb_serial *serial = port->serial;
880 u16 state;
881 int result;
882
Harvey Harrison441b62c2008-03-03 16:08:34 -0800883 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 if (break_state == 0)
886 state = BREAK_OFF;
887 else
888 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100889 dbg("%s - turning break %s", __func__,
890 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
Thiago Galesi372db8a2006-07-31 15:39:27 -0300892 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
893 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
894 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800896 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
Thiago Galesi372db8a2006-07-31 15:39:27 -0300899static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
901 int i;
902 struct pl2303_private *priv;
903
Harvey Harrison441b62c2008-03-03 16:08:34 -0800904 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 for (i = 0; i < serial->num_ports; ++i) {
907 priv = usb_get_serial_port_data(serial->port[i]);
908 if (priv) {
909 pl2303_buf_free(priv->buf);
910 kfree(priv);
911 usb_set_serial_port_data(serial->port[i], NULL);
912 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914}
915
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700916static void pl2303_update_line_status(struct usb_serial_port *port,
917 unsigned char *data,
918 unsigned int actual_length)
919{
920
921 struct pl2303_private *priv = usb_get_serial_port_data(port);
922 unsigned long flags;
923 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200924 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300925 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700926
Thiago Galesi9c537612006-07-29 10:47:12 -0300927 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
928 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
929
930
931 if (idv == SIEMENS_VENDOR_ID) {
932 if (idp == SIEMENS_PRODUCT_ID_X65 ||
933 idp == SIEMENS_PRODUCT_ID_SX1 ||
934 idp == SIEMENS_PRODUCT_ID_X75) {
935
936 length = 1;
937 status_idx = 0;
938 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700939 }
940
941 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300942 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700943
Alan Cox3a0f43e2008-07-22 11:14:49 +0100944 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700945 spin_lock_irqsave(&priv->lock, flags);
946 priv->line_status = data[status_idx];
947 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300948 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700949}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
David Howells7d12e782006-10-05 14:55:46 +0100951static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
Ming Leicdc97792008-02-24 18:41:47 +0800953 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700955 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700956 int status = urb->status;
957 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Harvey Harrison441b62c2008-03-03 16:08:34 -0800959 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700961 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 case 0:
963 /* success */
964 break;
965 case -ECONNRESET:
966 case -ENOENT:
967 case -ESHUTDOWN:
968 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800969 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700970 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 return;
972 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800973 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700974 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 goto exit;
976 }
977
Harvey Harrison441b62c2008-03-03 16:08:34 -0800978 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300979 urb->actual_length, urb->transfer_buffer);
980
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700981 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700984 retval = usb_submit_urb(urb, GFP_ATOMIC);
985 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300986 dev_err(&urb->dev->dev,
987 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800988 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989}
990
David Howells7d12e782006-10-05 14:55:46 +0100991static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992{
Ming Leicdc97792008-02-24 18:41:47 +0800993 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 struct pl2303_private *priv = usb_get_serial_port_data(port);
995 struct tty_struct *tty;
996 unsigned char *data = urb->transfer_buffer;
997 unsigned long flags;
998 int i;
999 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001000 int status = urb->status;
1001 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 char tty_flag;
1003
Harvey Harrison441b62c2008-03-03 16:08:34 -08001004 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001006 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001007 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001008 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001009 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return;
1011 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001012 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001013 /* PL2303 mysteriously fails with -EPROTO reschedule
1014 * the read */
1015 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001016 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 urb->dev = port->serial->dev;
1018 result = usb_submit_urb(urb, GFP_ATOMIC);
1019 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001020 dev_err(&urb->dev->dev, "%s - failed"
1021 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001022 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 return;
1024 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001025 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 return;
1027 }
1028
Harvey Harrison441b62c2008-03-03 16:08:34 -08001029 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001030 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032 /* get tty_flag from status */
1033 tty_flag = TTY_NORMAL;
1034
1035 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001036 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1038 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001039 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041 /* break takes precedence over parity, */
1042 /* which takes precedence over framing errors */
Alan Cox3a0f43e2008-07-22 11:14:49 +01001043 if (line_status & UART_BREAK_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001045 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001047 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001049 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Alan Cox4a90f092008-10-13 10:39:46 +01001051 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001053 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001055 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001057 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001058 tty_insert_flip_char(tty, data[i], tty_flag);
1059 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
Alan Cox4a90f092008-10-13 10:39:46 +01001061 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001063 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 urb->dev = port->serial->dev;
1065 result = usb_submit_urb(urb, GFP_ATOMIC);
1066 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001067 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001068 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 }
1070
1071 return;
1072}
1073
David Howells7d12e782006-10-05 14:55:46 +01001074static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
Ming Leicdc97792008-02-24 18:41:47 +08001076 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 struct pl2303_private *priv = usb_get_serial_port_data(port);
1078 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001079 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Harvey Harrison441b62c2008-03-03 16:08:34 -08001081 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001083 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 case 0:
1085 /* success */
1086 break;
1087 case -ECONNRESET:
1088 case -ENOENT:
1089 case -ESHUTDOWN:
1090 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001091 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001092 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 priv->write_urb_in_use = 0;
1094 return;
1095 default:
1096 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001097 dbg("%s - Overflow in write", __func__);
1098 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001099 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 port->write_urb->transfer_buffer_length = 1;
1101 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001102 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001104 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001105 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 else
1107 return;
1108 }
1109
1110 priv->write_urb_in_use = 0;
1111
1112 /* send any buffered data */
1113 pl2303_send(port);
1114}
1115
Thiago Galesi572d3132006-07-29 10:46:37 -03001116/* All of the device info needed for the PL2303 SIO serial converter */
1117static struct usb_serial_driver pl2303_device = {
1118 .driver = {
1119 .owner = THIS_MODULE,
1120 .name = "pl2303",
1121 },
1122 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001123 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001124 .num_ports = 1,
1125 .open = pl2303_open,
1126 .close = pl2303_close,
1127 .write = pl2303_write,
1128 .ioctl = pl2303_ioctl,
1129 .break_ctl = pl2303_break_ctl,
1130 .set_termios = pl2303_set_termios,
1131 .tiocmget = pl2303_tiocmget,
1132 .tiocmset = pl2303_tiocmset,
1133 .read_bulk_callback = pl2303_read_bulk_callback,
1134 .read_int_callback = pl2303_read_int_callback,
1135 .write_bulk_callback = pl2303_write_bulk_callback,
1136 .write_room = pl2303_write_room,
1137 .chars_in_buffer = pl2303_chars_in_buffer,
1138 .attach = pl2303_startup,
1139 .shutdown = pl2303_shutdown,
1140};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Thiago Galesi372db8a2006-07-31 15:39:27 -03001142static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001145
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 retval = usb_serial_register(&pl2303_device);
1147 if (retval)
1148 goto failed_usb_serial_register;
1149 retval = usb_register(&pl2303_driver);
1150 if (retval)
1151 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001152 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 return 0;
1154failed_usb_register:
1155 usb_serial_deregister(&pl2303_device);
1156failed_usb_serial_register:
1157 return retval;
1158}
1159
Thiago Galesi372db8a2006-07-31 15:39:27 -03001160static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001162 usb_deregister(&pl2303_driver);
1163 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164}
1165
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166module_init(pl2303_init);
1167module_exit(pl2303_exit);
1168
1169MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170MODULE_LICENSE("GPL");
1171
1172module_param(debug, bool, S_IRUGO | S_IWUSR);
1173MODULE_PARM_DESC(debug, "Debug enabled or not");
1174