blob: 029b314a1fb24e9041482bc88a07b24263563e5b [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) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 { } /* Terminating entry */
96};
97
Thiago Galesi372db8a2006-07-31 15:39:27 -030098MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 .name = "pl2303",
102 .probe = usb_serial_probe,
103 .disconnect = usb_serial_disconnect,
104 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800105 .suspend = usb_serial_suspend,
106 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800107 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800108 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109};
110
111#define SET_LINE_REQUEST_TYPE 0x21
112#define SET_LINE_REQUEST 0x20
113
114#define SET_CONTROL_REQUEST_TYPE 0x21
115#define SET_CONTROL_REQUEST 0x22
116#define CONTROL_DTR 0x01
117#define CONTROL_RTS 0x02
118
119#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100120#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#define BREAK_ON 0xffff
122#define BREAK_OFF 0x0000
123
124#define GET_LINE_REQUEST_TYPE 0xa1
125#define GET_LINE_REQUEST 0x21
126
127#define VENDOR_WRITE_REQUEST_TYPE 0x40
128#define VENDOR_WRITE_REQUEST 0x01
129
130#define VENDOR_READ_REQUEST_TYPE 0xc0
131#define VENDOR_READ_REQUEST 0x01
132
133#define UART_STATE 0x08
134#define UART_STATE_TRANSIENT_MASK 0x74
135#define UART_DCD 0x01
136#define UART_DSR 0x02
137#define UART_BREAK_ERROR 0x04
138#define UART_RING 0x08
139#define UART_FRAME_ERROR 0x10
140#define UART_PARITY_ERROR 0x20
141#define UART_OVERRUN_ERROR 0x40
142#define UART_CTS 0x80
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145enum pl2303_type {
146 type_0, /* don't know the difference between type 0 and */
147 type_1, /* type 1, until someone from prolific tells us... */
148 HX, /* HX version of the pl2303 chip */
149};
150
151struct pl2303_private {
152 spinlock_t lock;
153 struct pl2303_buf *buf;
154 int write_urb_in_use;
155 wait_queue_head_t delta_msr_wait;
156 u8 line_control;
157 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 enum pl2303_type type;
159};
160
Thiago Galesi572d3132006-07-29 10:46:37 -0300161/*
162 * pl2303_buf_alloc
163 *
164 * Allocate a circular buffer and all associated memory.
165 */
166static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
167{
168 struct pl2303_buf *pb;
169
170 if (size == 0)
171 return NULL;
172
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800173 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300174 if (pb == NULL)
175 return NULL;
176
177 pb->buf_buf = kmalloc(size, GFP_KERNEL);
178 if (pb->buf_buf == NULL) {
179 kfree(pb);
180 return NULL;
181 }
182
183 pb->buf_size = size;
184 pb->buf_get = pb->buf_put = pb->buf_buf;
185
186 return pb;
187}
188
189/*
190 * pl2303_buf_free
191 *
192 * Free the buffer and all associated memory.
193 */
194static void pl2303_buf_free(struct pl2303_buf *pb)
195{
196 if (pb) {
197 kfree(pb->buf_buf);
198 kfree(pb);
199 }
200}
201
202/*
203 * pl2303_buf_clear
204 *
205 * Clear out all data in the circular buffer.
206 */
207static void pl2303_buf_clear(struct pl2303_buf *pb)
208{
209 if (pb != NULL)
210 pb->buf_get = pb->buf_put;
211 /* equivalent to a get of all data available */
212}
213
214/*
215 * pl2303_buf_data_avail
216 *
217 * Return the number of bytes of data available in the circular
218 * buffer.
219 */
220static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
221{
222 if (pb == NULL)
223 return 0;
224
Alan Cox3a0f43e2008-07-22 11:14:49 +0100225 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300226}
227
228/*
229 * pl2303_buf_space_avail
230 *
231 * Return the number of bytes of space available in the circular
232 * buffer.
233 */
234static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
235{
236 if (pb == NULL)
237 return 0;
238
Alan Cox3a0f43e2008-07-22 11:14:49 +0100239 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300240}
241
242/*
243 * pl2303_buf_put
244 *
245 * Copy data data from a user buffer and put it into the circular buffer.
246 * Restrict to the amount of space available.
247 *
248 * Return the number of bytes copied.
249 */
250static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
251 unsigned int count)
252{
253 unsigned int len;
254
255 if (pb == NULL)
256 return 0;
257
258 len = pl2303_buf_space_avail(pb);
259 if (count > len)
260 count = len;
261
262 if (count == 0)
263 return 0;
264
265 len = pb->buf_buf + pb->buf_size - pb->buf_put;
266 if (count > len) {
267 memcpy(pb->buf_put, buf, len);
268 memcpy(pb->buf_buf, buf+len, count - len);
269 pb->buf_put = pb->buf_buf + count - len;
270 } else {
271 memcpy(pb->buf_put, buf, count);
272 if (count < len)
273 pb->buf_put += count;
274 else /* count == len */
275 pb->buf_put = pb->buf_buf;
276 }
277
278 return count;
279}
280
281/*
282 * pl2303_buf_get
283 *
284 * Get data from the circular buffer and copy to the given buffer.
285 * Restrict to the amount of data available.
286 *
287 * Return the number of bytes copied.
288 */
289static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
290 unsigned int count)
291{
292 unsigned int len;
293
294 if (pb == NULL)
295 return 0;
296
297 len = pl2303_buf_data_avail(pb);
298 if (count > len)
299 count = len;
300
301 if (count == 0)
302 return 0;
303
304 len = pb->buf_buf + pb->buf_size - pb->buf_get;
305 if (count > len) {
306 memcpy(buf, pb->buf_get, len);
307 memcpy(buf+len, pb->buf_buf, count - len);
308 pb->buf_get = pb->buf_buf + count - len;
309 } else {
310 memcpy(buf, pb->buf_get, count);
311 if (count < len)
312 pb->buf_get += count;
313 else /* count == len */
314 pb->buf_get = pb->buf_buf;
315 }
316
317 return count;
318}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Sarah Sharpeb44da02007-12-14 14:08:00 -0800320static int pl2303_vendor_read(__u16 value, __u16 index,
321 struct usb_serial *serial, unsigned char *buf)
322{
323 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
324 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
325 value, index, buf, 1, 100);
326 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
327 VENDOR_READ_REQUEST, value, index, res, buf[0]);
328 return res;
329}
330
331static int pl2303_vendor_write(__u16 value, __u16 index,
332 struct usb_serial *serial)
333{
334 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
335 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
336 value, index, NULL, 0, 100);
337 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
338 VENDOR_WRITE_REQUEST, value, index, res);
339 return res;
340}
341
Thiago Galesi372db8a2006-07-31 15:39:27 -0300342static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
344 struct pl2303_private *priv;
345 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800346 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 int i;
348
Sarah Sharp3e152502007-12-14 14:08:35 -0800349 buf = kmalloc(10, GFP_KERNEL);
350 if (buf == NULL)
351 return -ENOMEM;
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if (serial->dev->descriptor.bDeviceClass == 0x02)
354 type = type_0;
355 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
356 type = HX;
357 else if (serial->dev->descriptor.bDeviceClass == 0x00)
358 type = type_1;
359 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
360 type = type_1;
361 dbg("device type: %d", type);
362
363 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100364 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (!priv)
366 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 spin_lock_init(&priv->lock);
368 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
369 if (priv->buf == NULL) {
370 kfree(priv);
371 goto cleanup;
372 }
373 init_waitqueue_head(&priv->delta_msr_wait);
374 priv->type = type;
375 usb_set_serial_port_data(serial->port[i], priv);
376 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800377
378 pl2303_vendor_read(0x8484, 0, serial, buf);
379 pl2303_vendor_write(0x0404, 0, serial);
380 pl2303_vendor_read(0x8484, 0, serial, buf);
381 pl2303_vendor_read(0x8383, 0, serial, buf);
382 pl2303_vendor_read(0x8484, 0, serial, buf);
383 pl2303_vendor_write(0x0404, 1, serial);
384 pl2303_vendor_read(0x8484, 0, serial, buf);
385 pl2303_vendor_read(0x8383, 0, serial, buf);
386 pl2303_vendor_write(0, 1, serial);
387 pl2303_vendor_write(1, 0, serial);
388 if (type == HX)
389 pl2303_vendor_write(2, 0x44, serial);
390 else
391 pl2303_vendor_write(2, 0x24, serial);
392
393 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return 0;
395
396cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800397 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100398 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 priv = usb_get_serial_port_data(serial->port[i]);
400 pl2303_buf_free(priv->buf);
401 kfree(priv);
402 usb_set_serial_port_data(serial->port[i], NULL);
403 }
404 return -ENOMEM;
405}
406
Thiago Galesi372db8a2006-07-31 15:39:27 -0300407static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100410
Thiago Galesi372db8a2006-07-31 15:39:27 -0300411 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
412 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
413 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800414 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return retval;
416}
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static void pl2303_send(struct usb_serial_port *port)
419{
420 int count, result;
421 struct pl2303_private *priv = usb_get_serial_port_data(port);
422 unsigned long flags;
423
Harvey Harrison441b62c2008-03-03 16:08:34 -0800424 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 spin_lock_irqsave(&priv->lock, flags);
427
428 if (priv->write_urb_in_use) {
429 spin_unlock_irqrestore(&priv->lock, flags);
430 return;
431 }
432
433 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300434 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 if (count == 0) {
437 spin_unlock_irqrestore(&priv->lock, flags);
438 return;
439 }
440
441 priv->write_urb_in_use = 1;
442
443 spin_unlock_irqrestore(&priv->lock, flags);
444
Harvey Harrison441b62c2008-03-03 16:08:34 -0800445 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300446 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448 port->write_urb->transfer_buffer_length = count;
449 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300450 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300452 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800453 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100455 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
457
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700458 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
Alan Cox95da3102008-07-22 11:09:07 +0100461static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
462 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300463{
464 struct pl2303_private *priv = usb_get_serial_port_data(port);
465 unsigned long flags;
466
Harvey Harrison441b62c2008-03-03 16:08:34 -0800467 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300468
469 if (!count)
470 return count;
471
472 spin_lock_irqsave(&priv->lock, flags);
473 count = pl2303_buf_put(priv->buf, buf, count);
474 spin_unlock_irqrestore(&priv->lock, flags);
475
476 pl2303_send(port);
477
478 return count;
479}
480
Alan Cox95da3102008-07-22 11:09:07 +0100481static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Alan Cox95da3102008-07-22 11:09:07 +0100483 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 struct pl2303_private *priv = usb_get_serial_port_data(port);
485 int room = 0;
486 unsigned long flags;
487
Harvey Harrison441b62c2008-03-03 16:08:34 -0800488 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
490 spin_lock_irqsave(&priv->lock, flags);
491 room = pl2303_buf_space_avail(priv->buf);
492 spin_unlock_irqrestore(&priv->lock, flags);
493
Harvey Harrison441b62c2008-03-03 16:08:34 -0800494 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 return room;
496}
497
Alan Cox95da3102008-07-22 11:09:07 +0100498static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Alan Cox95da3102008-07-22 11:09:07 +0100500 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 struct pl2303_private *priv = usb_get_serial_port_data(port);
502 int chars = 0;
503 unsigned long flags;
504
Harvey Harrison441b62c2008-03-03 16:08:34 -0800505 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 spin_lock_irqsave(&priv->lock, flags);
508 chars = pl2303_buf_data_avail(priv->buf);
509 spin_unlock_irqrestore(&priv->lock, flags);
510
Harvey Harrison441b62c2008-03-03 16:08:34 -0800511 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return chars;
513}
514
Alan Cox95da3102008-07-22 11:09:07 +0100515static void pl2303_set_termios(struct tty_struct *tty,
516 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 struct usb_serial *serial = port->serial;
519 struct pl2303_private *priv = usb_get_serial_port_data(port);
520 unsigned long flags;
521 unsigned int cflag;
522 unsigned char *buf;
523 int baud;
524 int i;
525 u8 control;
526
Harvey Harrison441b62c2008-03-03 16:08:34 -0800527 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Alan Coxbf5e5832008-01-08 14:55:51 +0000529 /* The PL2303 is reported to lose bytes if you change
530 serial settings even to the same values as before. Thus
531 we actually need to filter in this specific case */
532
Alan Cox95da3102008-07-22 11:09:07 +0100533 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000534 return;
535
Alan Cox95da3102008-07-22 11:09:07 +0100536 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Thiago Galesi372db8a2006-07-31 15:39:27 -0300538 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800540 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100541 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100542 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 return;
544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Thiago Galesi372db8a2006-07-31 15:39:27 -0300546 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
547 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
548 0, 0, buf, 7, 100);
549 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
550 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 if (cflag & CSIZE) {
553 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100554 case CS5:
555 buf[6] = 5;
556 break;
557 case CS6:
558 buf[6] = 6;
559 break;
560 case CS7:
561 buf[6] = 7;
562 break;
563 default:
564 case CS8:
565 buf[6] = 8;
566 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800568 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
570
Alan Cox95da3102008-07-22 11:09:07 +0100571 baud = tty_get_baud_rate(tty);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800572 dbg("%s - baud = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 if (baud) {
574 buf[0] = baud & 0xff;
575 buf[1] = (baud >> 8) & 0xff;
576 buf[2] = (baud >> 16) & 0xff;
577 buf[3] = (baud >> 24) & 0xff;
578 }
579
580 /* For reference buf[4]=0 is 1 stop bits */
581 /* For reference buf[4]=1 is 1.5 stop bits */
582 /* For reference buf[4]=2 is 2 stop bits */
583 if (cflag & CSTOPB) {
584 buf[4] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800585 dbg("%s - stop bits = 2", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 } else {
587 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800588 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 }
590
591 if (cflag & PARENB) {
592 /* For reference buf[5]=0 is none parity */
593 /* For reference buf[5]=1 is odd parity */
594 /* For reference buf[5]=2 is even parity */
595 /* For reference buf[5]=3 is mark parity */
596 /* For reference buf[5]=4 is space parity */
597 if (cflag & PARODD) {
598 buf[5] = 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800599 dbg("%s - parity = odd", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 } else {
601 buf[5] = 2;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800602 dbg("%s - parity = even", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 }
604 } else {
605 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800606 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 }
608
Thiago Galesi372db8a2006-07-31 15:39:27 -0300609 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
610 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
611 0, 0, buf, 7, 100);
612 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614 /* change control lines if we are switching to or from B0 */
615 spin_lock_irqsave(&priv->lock, flags);
616 control = priv->line_control;
617 if ((cflag & CBAUD) == B0)
618 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
619 else
620 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
621 if (control != priv->line_control) {
622 control = priv->line_control;
623 spin_unlock_irqrestore(&priv->lock, flags);
624 set_control_lines(serial->dev, control);
625 } else {
626 spin_unlock_irqrestore(&priv->lock, flags);
627 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
630
Thiago Galesi372db8a2006-07-31 15:39:27 -0300631 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
632 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
633 0, 0, buf, 7, 100);
634 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
636
637 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800639 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800641 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200642 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800643 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
645
Alan Coxdf64c472007-10-15 20:54:47 +0100646 /* FIXME: Need to read back resulting baud rate */
647 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100648 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100649
Thiago Galesi372db8a2006-07-31 15:39:27 -0300650 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651}
652
Alan Cox95da3102008-07-22 11:09:07 +0100653static void pl2303_close(struct tty_struct *tty,
654 struct usb_serial_port *port, struct file *filp)
Thiago Galesi572d3132006-07-29 10:46:37 -0300655{
656 struct pl2303_private *priv = usb_get_serial_port_data(port);
657 unsigned long flags;
658 unsigned int c_cflag;
659 int bps;
660 long timeout;
661 wait_queue_t wait;
662
Harvey Harrison441b62c2008-03-03 16:08:34 -0800663 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300664
665 /* wait for data to drain from the buffer */
666 spin_lock_irqsave(&priv->lock, flags);
667 timeout = PL2303_CLOSING_WAIT;
668 init_waitqueue_entry(&wait, current);
Alan Cox95da3102008-07-22 11:09:07 +0100669 add_wait_queue(&tty->write_wait, &wait);
Thiago Galesi572d3132006-07-29 10:46:37 -0300670 for (;;) {
671 set_current_state(TASK_INTERRUPTIBLE);
672 if (pl2303_buf_data_avail(priv->buf) == 0 ||
673 timeout == 0 || signal_pending(current) ||
Oliver Neukum0915f492008-01-23 12:28:45 +0100674 port->serial->disconnected)
Thiago Galesi572d3132006-07-29 10:46:37 -0300675 break;
676 spin_unlock_irqrestore(&priv->lock, flags);
677 timeout = schedule_timeout(timeout);
678 spin_lock_irqsave(&priv->lock, flags);
679 }
680 set_current_state(TASK_RUNNING);
Alan Cox95da3102008-07-22 11:09:07 +0100681 remove_wait_queue(&tty->write_wait, &wait);
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
686 /* wait for characters to drain from the device */
687 /* (this is long enough for the entire 256 byte */
688 /* pl2303 hardware buffer to drain with no flow */
689 /* control for data rates of 1200 bps or more, */
690 /* for lower rates we should really know how much */
691 /* data is in the buffer to compute a delay */
692 /* that is not unnecessarily long) */
Alan Cox95da3102008-07-22 11:09:07 +0100693 bps = tty_get_baud_rate(tty);
Thiago Galesi572d3132006-07-29 10:46:37 -0300694 if (bps > 1200)
Alan Cox3a0f43e2008-07-22 11:14:49 +0100695 timeout = max((HZ*2560)/bps, HZ/10);
Thiago Galesi572d3132006-07-29 10:46:37 -0300696 else
697 timeout = 2*HZ;
698 schedule_timeout_interruptible(timeout);
699
700 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800701 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300702 usb_kill_urb(port->write_urb);
703 usb_kill_urb(port->read_urb);
704 usb_kill_urb(port->interrupt_in_urb);
705
Alan Cox95da3102008-07-22 11:09:07 +0100706 if (tty) {
707 c_cflag = tty->termios->c_cflag;
Thiago Galesi572d3132006-07-29 10:46:37 -0300708 if (c_cflag & HUPCL) {
709 /* drop DTR and RTS */
710 spin_lock_irqsave(&priv->lock, flags);
711 priv->line_control = 0;
712 spin_unlock_irqrestore(&priv->lock, flags);
713 set_control_lines(port->serial->dev, 0);
714 }
715 }
716}
717
Alan Cox95da3102008-07-22 11:09:07 +0100718static int pl2303_open(struct tty_struct *tty,
719 struct usb_serial_port *port, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
Alan Cox606d0992006-12-08 02:38:45 -0800721 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 struct usb_serial *serial = port->serial;
723 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 int result;
725
Harvey Harrison441b62c2008-03-03 16:08:34 -0800726 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
Dariusz M16948992005-07-28 18:06:13 +0200728 if (priv->type != HX) {
729 usb_clear_halt(serial->dev, port->write_urb->pipe);
730 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800731 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800733 pl2303_vendor_write(8, 0, serial);
734 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 }
736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100738 if (tty)
739 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
Alan Cox3a0f43e2008-07-22 11:14:49 +0100741 /* FIXME: need to assert RTS and DTR if CRTSCTS off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Harvey Harrison441b62c2008-03-03 16:08:34 -0800743 dbg("%s - submitting read urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 port->read_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300745 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300747 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800748 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100749 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 return -EPROTO;
751 }
752
Harvey Harrison441b62c2008-03-03 16:08:34 -0800753 dbg("%s - submitting interrupt urb", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 port->interrupt_in_urb->dev = serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300755 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300757 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800758 " error %d\n", __func__, result);
Alan Cox95da3102008-07-22 11:09:07 +0100759 pl2303_close(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return -EPROTO;
761 }
762 return 0;
763}
764
Alan Cox95da3102008-07-22 11:09:07 +0100765static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300766 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
Alan Cox95da3102008-07-22 11:09:07 +0100768 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 struct pl2303_private *priv = usb_get_serial_port_data(port);
770 unsigned long flags;
771 u8 control;
772
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700773 if (!usb_get_intfdata(port->serial->interface))
774 return -ENODEV;
775
Thiago Galesi372db8a2006-07-31 15:39:27 -0300776 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 if (set & TIOCM_RTS)
778 priv->line_control |= CONTROL_RTS;
779 if (set & TIOCM_DTR)
780 priv->line_control |= CONTROL_DTR;
781 if (clear & TIOCM_RTS)
782 priv->line_control &= ~CONTROL_RTS;
783 if (clear & TIOCM_DTR)
784 priv->line_control &= ~CONTROL_DTR;
785 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300786 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Thiago Galesi372db8a2006-07-31 15:39:27 -0300788 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789}
790
Alan Cox95da3102008-07-22 11:09:07 +0100791static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
Alan Cox95da3102008-07-22 11:09:07 +0100793 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 struct pl2303_private *priv = usb_get_serial_port_data(port);
795 unsigned long flags;
796 unsigned int mcr;
797 unsigned int status;
798 unsigned int result;
799
Harvey Harrison441b62c2008-03-03 16:08:34 -0800800 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700802 if (!usb_get_intfdata(port->serial->interface))
803 return -ENODEV;
804
Thiago Galesi372db8a2006-07-31 15:39:27 -0300805 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 mcr = priv->line_control;
807 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300808 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
810 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
811 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
812 | ((status & UART_CTS) ? TIOCM_CTS : 0)
813 | ((status & UART_DSR) ? TIOCM_DSR : 0)
814 | ((status & UART_RING) ? TIOCM_RI : 0)
815 | ((status & UART_DCD) ? TIOCM_CD : 0);
816
Harvey Harrison441b62c2008-03-03 16:08:34 -0800817 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 return result;
820}
821
822static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
823{
824 struct pl2303_private *priv = usb_get_serial_port_data(port);
825 unsigned long flags;
826 unsigned int prevstatus;
827 unsigned int status;
828 unsigned int changed;
829
Thiago Galesi372db8a2006-07-31 15:39:27 -0300830 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300832 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834 while (1) {
835 interruptible_sleep_on(&priv->delta_msr_wait);
836 /* see if a signal did it */
837 if (signal_pending(current))
838 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300839
840 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300842 spin_unlock_irqrestore(&priv->lock, flags);
843
Alan Cox3a0f43e2008-07-22 11:14:49 +0100844 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
847 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
848 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100849 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 return 0;
851 }
852 prevstatus = status;
853 }
854 /* NOTREACHED */
855 return 0;
856}
857
Alan Cox95da3102008-07-22 11:09:07 +0100858static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300859 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
Alan Cox95da3102008-07-22 11:09:07 +0100861 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800862 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
864 switch (cmd) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100865 case TIOCMIWAIT:
866 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
867 return wait_modem_info(port, arg);
868 default:
869 dbg("%s not supported = 0x%04x", __func__, cmd);
870 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return -ENOIOCTLCMD;
873}
874
Alan Cox95da3102008-07-22 11:09:07 +0100875static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
Alan Cox95da3102008-07-22 11:09:07 +0100877 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 struct usb_serial *serial = port->serial;
879 u16 state;
880 int result;
881
Harvey Harrison441b62c2008-03-03 16:08:34 -0800882 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 if (break_state == 0)
885 state = BREAK_OFF;
886 else
887 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100888 dbg("%s - turning break %s", __func__,
889 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Thiago Galesi372db8a2006-07-31 15:39:27 -0300891 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
892 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
893 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800895 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
Thiago Galesi372db8a2006-07-31 15:39:27 -0300898static void pl2303_shutdown(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
900 int i;
901 struct pl2303_private *priv;
902
Harvey Harrison441b62c2008-03-03 16:08:34 -0800903 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
905 for (i = 0; i < serial->num_ports; ++i) {
906 priv = usb_get_serial_port_data(serial->port[i]);
907 if (priv) {
908 pl2303_buf_free(priv->buf);
909 kfree(priv);
910 usb_set_serial_port_data(serial->port[i], NULL);
911 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700915static void pl2303_update_line_status(struct usb_serial_port *port,
916 unsigned char *data,
917 unsigned int actual_length)
918{
919
920 struct pl2303_private *priv = usb_get_serial_port_data(port);
921 unsigned long flags;
922 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200923 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300924 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700925
Thiago Galesi9c537612006-07-29 10:47:12 -0300926 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
927 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
928
929
930 if (idv == SIEMENS_VENDOR_ID) {
931 if (idp == SIEMENS_PRODUCT_ID_X65 ||
932 idp == SIEMENS_PRODUCT_ID_SX1 ||
933 idp == SIEMENS_PRODUCT_ID_X75) {
934
935 length = 1;
936 status_idx = 0;
937 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700938 }
939
940 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300941 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700942
Alan Cox3a0f43e2008-07-22 11:14:49 +0100943 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700944 spin_lock_irqsave(&priv->lock, flags);
945 priv->line_status = data[status_idx];
946 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300947 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700948}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
David Howells7d12e782006-10-05 14:55:46 +0100950static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951{
Ming Leicdc97792008-02-24 18:41:47 +0800952 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700954 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700955 int status = urb->status;
956 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Harvey Harrison441b62c2008-03-03 16:08:34 -0800958 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700960 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 case 0:
962 /* success */
963 break;
964 case -ECONNRESET:
965 case -ENOENT:
966 case -ESHUTDOWN:
967 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800968 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700969 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 return;
971 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800972 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700973 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 goto exit;
975 }
976
Harvey Harrison441b62c2008-03-03 16:08:34 -0800977 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300978 urb->actual_length, urb->transfer_buffer);
979
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700980 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700983 retval = usb_submit_urb(urb, GFP_ATOMIC);
984 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300985 dev_err(&urb->dev->dev,
986 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800987 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988}
989
David Howells7d12e782006-10-05 14:55:46 +0100990static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
Ming Leicdc97792008-02-24 18:41:47 +0800992 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 struct pl2303_private *priv = usb_get_serial_port_data(port);
994 struct tty_struct *tty;
995 unsigned char *data = urb->transfer_buffer;
996 unsigned long flags;
997 int i;
998 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700999 int status = urb->status;
1000 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 char tty_flag;
1002
Harvey Harrison441b62c2008-03-03 16:08:34 -08001003 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001005 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001006 dbg("%s - urb status = %d", __func__, status);
Alan Cox95da3102008-07-22 11:09:07 +01001007 if (!port->port.count) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001008 dbg("%s - port is closed, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return;
1010 }
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001011 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001012 /* PL2303 mysteriously fails with -EPROTO reschedule
1013 * the read */
1014 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001015 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 urb->dev = port->serial->dev;
1017 result = usb_submit_urb(urb, GFP_ATOMIC);
1018 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001019 dev_err(&urb->dev->dev, "%s - failed"
1020 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001021 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 return;
1023 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001024 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return;
1026 }
1027
Harvey Harrison441b62c2008-03-03 16:08:34 -08001028 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001029 urb->actual_length, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
1031 /* get tty_flag from status */
1032 tty_flag = TTY_NORMAL;
1033
1034 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001035 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1037 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001038 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
1040 /* break takes precedence over parity, */
1041 /* which takes precedence over framing errors */
Alan Cox3a0f43e2008-07-22 11:14:49 +01001042 if (line_status & UART_BREAK_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 tty_flag = TTY_BREAK;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001044 else if (line_status & UART_PARITY_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 tty_flag = TTY_PARITY;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001046 else if (line_status & UART_FRAME_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 tty_flag = TTY_FRAME;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001048 dbg("%s - tty_flag = %d", __func__, tty_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Alan Cox4a90f092008-10-13 10:39:46 +01001050 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 if (tty && urb->actual_length) {
Alan Cox33f0f882006-01-09 20:54:13 -08001052 tty_buffer_request_room(tty, urb->actual_length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 /* overrun is special, not associated with a char */
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001054 if (line_status & UART_OVERRUN_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Alan Cox33f0f882006-01-09 20:54:13 -08001056 for (i = 0; i < urb->actual_length; ++i)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001057 tty_insert_flip_char(tty, data[i], tty_flag);
1058 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
Alan Cox4a90f092008-10-13 10:39:46 +01001060 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 /* Schedule the next read _if_ we are still open */
Alan Cox95da3102008-07-22 11:09:07 +01001062 if (port->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 urb->dev = port->serial->dev;
1064 result = usb_submit_urb(urb, GFP_ATOMIC);
1065 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001066 dev_err(&urb->dev->dev, "%s - failed resubmitting"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001067 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 }
1069
1070 return;
1071}
1072
David Howells7d12e782006-10-05 14:55:46 +01001073static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074{
Ming Leicdc97792008-02-24 18:41:47 +08001075 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 struct pl2303_private *priv = usb_get_serial_port_data(port);
1077 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001078 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
Harvey Harrison441b62c2008-03-03 16:08:34 -08001080 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001082 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 case 0:
1084 /* success */
1085 break;
1086 case -ECONNRESET:
1087 case -ENOENT:
1088 case -ESHUTDOWN:
1089 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001090 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001091 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 priv->write_urb_in_use = 0;
1093 return;
1094 default:
1095 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001096 dbg("%s - Overflow in write", __func__);
1097 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001098 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 port->write_urb->transfer_buffer_length = 1;
1100 port->write_urb->dev = port->serial->dev;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001101 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001103 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001104 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 else
1106 return;
1107 }
1108
1109 priv->write_urb_in_use = 0;
1110
1111 /* send any buffered data */
1112 pl2303_send(port);
1113}
1114
Thiago Galesi572d3132006-07-29 10:46:37 -03001115/* All of the device info needed for the PL2303 SIO serial converter */
1116static struct usb_serial_driver pl2303_device = {
1117 .driver = {
1118 .owner = THIS_MODULE,
1119 .name = "pl2303",
1120 },
1121 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001122 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001123 .num_ports = 1,
1124 .open = pl2303_open,
1125 .close = pl2303_close,
1126 .write = pl2303_write,
1127 .ioctl = pl2303_ioctl,
1128 .break_ctl = pl2303_break_ctl,
1129 .set_termios = pl2303_set_termios,
1130 .tiocmget = pl2303_tiocmget,
1131 .tiocmset = pl2303_tiocmset,
1132 .read_bulk_callback = pl2303_read_bulk_callback,
1133 .read_int_callback = pl2303_read_int_callback,
1134 .write_bulk_callback = pl2303_write_bulk_callback,
1135 .write_room = pl2303_write_room,
1136 .chars_in_buffer = pl2303_chars_in_buffer,
1137 .attach = pl2303_startup,
1138 .shutdown = pl2303_shutdown,
1139};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Thiago Galesi372db8a2006-07-31 15:39:27 -03001141static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
1143 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 retval = usb_serial_register(&pl2303_device);
1146 if (retval)
1147 goto failed_usb_serial_register;
1148 retval = usb_register(&pl2303_driver);
1149 if (retval)
1150 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001151 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 return 0;
1153failed_usb_register:
1154 usb_serial_deregister(&pl2303_device);
1155failed_usb_serial_register:
1156 return retval;
1157}
1158
Thiago Galesi372db8a2006-07-31 15:39:27 -03001159static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001161 usb_deregister(&pl2303_driver);
1162 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163}
1164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165module_init(pl2303_init);
1166module_exit(pl2303_exit);
1167
1168MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169MODULE_LICENSE("GPL");
1170
1171module_param(debug, bool, S_IRUGO | S_IWUSR);
1172MODULE_PARM_DESC(debug, "Debug enabled or not");
1173