blob: 3e86815b270534cfd3633820d5d142edd71df4b6 [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 Cox95da3102008-07-22 11:09:07 +0100694static int pl2303_open(struct tty_struct *tty,
695 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
Alan Cox606d0992006-12-08 02:38:45 -0800697 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 struct usb_serial *serial = port->serial;
699 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 int result;
701
Harvey Harrison441b62c2008-03-03 16:08:34 -0800702 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Dariusz M16948992005-07-28 18:06:13 +0200704 if (priv->type != HX) {
705 usb_clear_halt(serial->dev, port->write_urb->pipe);
706 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800707 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800709 pl2303_vendor_write(8, 0, serial);
710 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 }
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100714 if (tty)
715 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Alan Cox3a0f43e2008-07-22 11:14:49 +0100717 /* FIXME: need to assert RTS and DTR if CRTSCTS off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Harvey Harrison441b62c2008-03-03 16:08:34 -0800719 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300721 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300723 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800724 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100725 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return -EPROTO;
727 }
728
Harvey Harrison441b62c2008-03-03 16:08:34 -0800729 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300731 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300733 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800734 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100735 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return -EPROTO;
737 }
Alan Cox335f8512009-06-11 12:26:29 +0100738 port->port.drain_delay = 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return 0;
740}
741
Alan Cox95da3102008-07-22 11:09:07 +0100742static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300743 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744{
Alan Cox95da3102008-07-22 11:09:07 +0100745 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 struct pl2303_private *priv = usb_get_serial_port_data(port);
747 unsigned long flags;
748 u8 control;
749
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700750 if (!usb_get_intfdata(port->serial->interface))
751 return -ENODEV;
752
Thiago Galesi372db8a2006-07-31 15:39:27 -0300753 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if (set & TIOCM_RTS)
755 priv->line_control |= CONTROL_RTS;
756 if (set & TIOCM_DTR)
757 priv->line_control |= CONTROL_DTR;
758 if (clear & TIOCM_RTS)
759 priv->line_control &= ~CONTROL_RTS;
760 if (clear & TIOCM_DTR)
761 priv->line_control &= ~CONTROL_DTR;
762 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300763 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Thiago Galesi372db8a2006-07-31 15:39:27 -0300765 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
Alan Cox95da3102008-07-22 11:09:07 +0100768static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
Alan Cox95da3102008-07-22 11:09:07 +0100770 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 struct pl2303_private *priv = usb_get_serial_port_data(port);
772 unsigned long flags;
773 unsigned int mcr;
774 unsigned int status;
775 unsigned int result;
776
Harvey Harrison441b62c2008-03-03 16:08:34 -0800777 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700779 if (!usb_get_intfdata(port->serial->interface))
780 return -ENODEV;
781
Thiago Galesi372db8a2006-07-31 15:39:27 -0300782 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 mcr = priv->line_control;
784 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300785 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
788 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
789 | ((status & UART_CTS) ? TIOCM_CTS : 0)
790 | ((status & UART_DSR) ? TIOCM_DSR : 0)
791 | ((status & UART_RING) ? TIOCM_RI : 0)
792 | ((status & UART_DCD) ? TIOCM_CD : 0);
793
Harvey Harrison441b62c2008-03-03 16:08:34 -0800794 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 return result;
797}
798
Alan Cox335f8512009-06-11 12:26:29 +0100799static int pl2303_carrier_raised(struct usb_serial_port *port)
800{
801 struct pl2303_private *priv = usb_get_serial_port_data(port);
802 if (priv->line_status & UART_DCD)
803 return 1;
804 return 0;
805}
806
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
808{
809 struct pl2303_private *priv = usb_get_serial_port_data(port);
810 unsigned long flags;
811 unsigned int prevstatus;
812 unsigned int status;
813 unsigned int changed;
814
Thiago Galesi372db8a2006-07-31 15:39:27 -0300815 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300817 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 while (1) {
820 interruptible_sleep_on(&priv->delta_msr_wait);
821 /* see if a signal did it */
822 if (signal_pending(current))
823 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300824
825 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300827 spin_unlock_irqrestore(&priv->lock, flags);
828
Alan Cox3a0f43e2008-07-22 11:14:49 +0100829 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
832 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
833 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100834 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 return 0;
836 }
837 prevstatus = status;
838 }
839 /* NOTREACHED */
840 return 0;
841}
842
Alan Cox95da3102008-07-22 11:09:07 +0100843static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300844 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845{
Alan Cox95da3102008-07-22 11:09:07 +0100846 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800847 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
849 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100850 case TIOCMIWAIT:
851 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
852 return wait_modem_info(port, arg);
853 default:
854 dbg("%s not supported = 0x%04x", __func__, cmd);
855 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 return -ENOIOCTLCMD;
858}
859
Alan Cox95da3102008-07-22 11:09:07 +0100860static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
Alan Cox95da3102008-07-22 11:09:07 +0100862 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 struct usb_serial *serial = port->serial;
864 u16 state;
865 int result;
866
Harvey Harrison441b62c2008-03-03 16:08:34 -0800867 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
869 if (break_state == 0)
870 state = BREAK_OFF;
871 else
872 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100873 dbg("%s - turning break %s", __func__,
874 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Thiago Galesi372db8a2006-07-31 15:39:27 -0300876 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
877 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
878 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800880 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881}
882
Alan Sternf9c99bb2009-06-02 11:53:55 -0400883static void pl2303_release(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 int i;
886 struct pl2303_private *priv;
887
Harvey Harrison441b62c2008-03-03 16:08:34 -0800888 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
890 for (i = 0; i < serial->num_ports; ++i) {
891 priv = usb_get_serial_port_data(serial->port[i]);
892 if (priv) {
893 pl2303_buf_free(priv->buf);
894 kfree(priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700899static void pl2303_update_line_status(struct usb_serial_port *port,
900 unsigned char *data,
901 unsigned int actual_length)
902{
903
904 struct pl2303_private *priv = usb_get_serial_port_data(port);
905 unsigned long flags;
906 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200907 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300908 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700909
Thiago Galesi9c537612006-07-29 10:47:12 -0300910 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
911 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
912
913
914 if (idv == SIEMENS_VENDOR_ID) {
915 if (idp == SIEMENS_PRODUCT_ID_X65 ||
916 idp == SIEMENS_PRODUCT_ID_SX1 ||
917 idp == SIEMENS_PRODUCT_ID_X75) {
918
919 length = 1;
920 status_idx = 0;
921 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700922 }
923
924 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300925 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700926
Alan Cox3a0f43e2008-07-22 11:14:49 +0100927 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700928 spin_lock_irqsave(&priv->lock, flags);
929 priv->line_status = data[status_idx];
930 spin_unlock_irqrestore(&priv->lock, flags);
Jason Wessel430eb0d2009-05-29 13:34:16 -0500931 if (priv->line_status & UART_BREAK_ERROR)
932 usb_serial_handle_break(port);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300933 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700934}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
David Howells7d12e782006-10-05 14:55:46 +0100936static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
Ming Leicdc97792008-02-24 18:41:47 +0800938 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700940 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700941 int status = urb->status;
942 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Harvey Harrison441b62c2008-03-03 16:08:34 -0800944 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700946 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 case 0:
948 /* success */
949 break;
950 case -ECONNRESET:
951 case -ENOENT:
952 case -ESHUTDOWN:
953 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800954 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700955 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 return;
957 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800958 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700959 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 goto exit;
961 }
962
Harvey Harrison441b62c2008-03-03 16:08:34 -0800963 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300964 urb->actual_length, urb->transfer_buffer);
965
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700966 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700969 retval = usb_submit_urb(urb, GFP_ATOMIC);
970 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300971 dev_err(&urb->dev->dev,
972 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800973 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
Alan Coxd4fc4a72009-07-09 13:36:58 +0100976static void pl2303_push_data(struct tty_struct *tty,
977 struct usb_serial_port *port, struct urb *urb,
978 u8 line_status)
979{
980 unsigned char *data = urb->transfer_buffer;
981 /* get tty_flag from status */
982 char tty_flag = TTY_NORMAL;
983 /* break takes precedence over parity, */
984 /* which takes precedence over framing errors */
985 if (line_status & UART_BREAK_ERROR)
986 tty_flag = TTY_BREAK;
987 else if (line_status & UART_PARITY_ERROR)
988 tty_flag = TTY_PARITY;
989 else if (line_status & UART_FRAME_ERROR)
990 tty_flag = TTY_FRAME;
991 dbg("%s - tty_flag = %d", __func__, tty_flag);
992
993 tty_buffer_request_room(tty, urb->actual_length + 1);
994 /* overrun is special, not associated with a char */
995 if (line_status & UART_OVERRUN_ERROR)
996 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
997 if (port->console && port->sysrq) {
998 int i;
999 for (i = 0; i < urb->actual_length; ++i)
1000 if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
1001 tty_insert_flip_char(tty, data[i], tty_flag);
1002 } else
1003 tty_insert_flip_string(tty, data, urb->actual_length);
1004 tty_flip_buffer_push(tty);
1005}
1006
David Howells7d12e782006-10-05 14:55:46 +01001007static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
Ming Leicdc97792008-02-24 18:41:47 +08001009 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 struct pl2303_private *priv = usb_get_serial_port_data(port);
1011 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001014 int status = urb->status;
1015 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
Harvey Harrison441b62c2008-03-03 16:08:34 -08001017 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001019 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001020 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001021 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001022 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 return;
1024 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001025 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001026 /* PL2303 mysteriously fails with -EPROTO reschedule
1027 * the read */
1028 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001029 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 urb->dev = port->serial->dev;
1031 result = usb_submit_urb(urb, GFP_ATOMIC);
1032 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001033 dev_err(&urb->dev->dev, "%s - failed"
1034 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001035 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return;
1037 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001038 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 return;
1040 }
1041
Harvey Harrison441b62c2008-03-03 16:08:34 -08001042 usb_serial_debug_data(debug, &port->dev, __func__,
Alan Coxd4fc4a72009-07-09 13:36:58 +01001043 urb->actual_length, urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001046 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1048 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001049 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
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 Coxd4fc4a72009-07-09 13:36:58 +01001053 pl2303_push_data(tty, port, urb, line_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
Alan Cox4a90f092008-10-13 10:39:46 +01001055 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001057 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 urb->dev = port->serial->dev;
1059 result = usb_submit_urb(urb, GFP_ATOMIC);
1060 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001061 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001062 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
1064
1065 return;
1066}
1067
David Howells7d12e782006-10-05 14:55:46 +01001068static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
Ming Leicdc97792008-02-24 18:41:47 +08001070 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 struct pl2303_private *priv = usb_get_serial_port_data(port);
1072 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001073 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Harvey Harrison441b62c2008-03-03 16:08:34 -08001075 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001077 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 case 0:
1079 /* success */
1080 break;
1081 case -ECONNRESET:
1082 case -ENOENT:
1083 case -ESHUTDOWN:
1084 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001085 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001086 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 priv->write_urb_in_use = 0;
1088 return;
1089 default:
1090 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001091 dbg("%s - Overflow in write", __func__);
1092 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001093 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 port->write_urb->transfer_buffer_length = 1;
1095 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001096 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001098 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001099 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 else
1101 return;
1102 }
1103
1104 priv->write_urb_in_use = 0;
1105
1106 /* send any buffered data */
1107 pl2303_send(port);
1108}
1109
Thiago Galesi572d3132006-07-29 10:46:37 -03001110/* All of the device info needed for the PL2303 SIO serial converter */
1111static struct usb_serial_driver pl2303_device = {
1112 .driver = {
1113 .owner = THIS_MODULE,
1114 .name = "pl2303",
1115 },
1116 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001117 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001118 .num_ports = 1,
1119 .open = pl2303_open,
1120 .close = pl2303_close,
Alan Cox335f8512009-06-11 12:26:29 +01001121 .dtr_rts = pl2303_dtr_rts,
1122 .carrier_raised = pl2303_carrier_raised,
Thiago Galesi572d3132006-07-29 10:46:37 -03001123 .write = pl2303_write,
1124 .ioctl = pl2303_ioctl,
1125 .break_ctl = pl2303_break_ctl,
1126 .set_termios = pl2303_set_termios,
1127 .tiocmget = pl2303_tiocmget,
1128 .tiocmset = pl2303_tiocmset,
1129 .read_bulk_callback = pl2303_read_bulk_callback,
1130 .read_int_callback = pl2303_read_int_callback,
1131 .write_bulk_callback = pl2303_write_bulk_callback,
1132 .write_room = pl2303_write_room,
1133 .chars_in_buffer = pl2303_chars_in_buffer,
1134 .attach = pl2303_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -04001135 .release = pl2303_release,
Thiago Galesi572d3132006-07-29 10:46:37 -03001136};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Thiago Galesi372db8a2006-07-31 15:39:27 -03001138static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
1140 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 retval = usb_serial_register(&pl2303_device);
1143 if (retval)
1144 goto failed_usb_serial_register;
1145 retval = usb_register(&pl2303_driver);
1146 if (retval)
1147 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001148 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return 0;
1150failed_usb_register:
1151 usb_serial_deregister(&pl2303_device);
1152failed_usb_serial_register:
1153 return retval;
1154}
1155
Thiago Galesi372db8a2006-07-31 15:39:27 -03001156static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001158 usb_deregister(&pl2303_driver);
1159 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160}
1161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162module_init(pl2303_init);
1163module_exit(pl2303_exit);
1164
1165MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166MODULE_LICENSE("GPL");
1167
1168module_param(debug, bool, S_IRUGO | S_IWUSR);
1169MODULE_PARM_DESC(debug, "Debug enabled or not");
1170