blob: 73d5f346d3e07659ad585f89f1c3b93b97d6aba9 [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
Németh Márton7d40d7e2010-01-10 15:34:24 +010053static const struct usb_device_id id_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 { 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) },
Pawel Ludwikow35904e62009-08-27 14:15:50 +020099 { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 { } /* Terminating entry */
101};
102
Thiago Galesi372db8a2006-07-31 15:39:27 -0300103MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 .name = "pl2303",
107 .probe = usb_serial_probe,
108 .disconnect = usb_serial_disconnect,
109 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800110 .suspend = usb_serial_suspend,
111 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800112 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800113 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114};
115
116#define SET_LINE_REQUEST_TYPE 0x21
117#define SET_LINE_REQUEST 0x20
118
119#define SET_CONTROL_REQUEST_TYPE 0x21
120#define SET_CONTROL_REQUEST 0x22
121#define CONTROL_DTR 0x01
122#define CONTROL_RTS 0x02
123
124#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100125#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#define BREAK_ON 0xffff
127#define BREAK_OFF 0x0000
128
129#define GET_LINE_REQUEST_TYPE 0xa1
130#define GET_LINE_REQUEST 0x21
131
132#define VENDOR_WRITE_REQUEST_TYPE 0x40
133#define VENDOR_WRITE_REQUEST 0x01
134
135#define VENDOR_READ_REQUEST_TYPE 0xc0
136#define VENDOR_READ_REQUEST 0x01
137
138#define UART_STATE 0x08
139#define UART_STATE_TRANSIENT_MASK 0x74
140#define UART_DCD 0x01
141#define UART_DSR 0x02
142#define UART_BREAK_ERROR 0x04
143#define UART_RING 0x08
144#define UART_FRAME_ERROR 0x10
145#define UART_PARITY_ERROR 0x20
146#define UART_OVERRUN_ERROR 0x40
147#define UART_CTS 0x80
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150enum pl2303_type {
151 type_0, /* don't know the difference between type 0 and */
152 type_1, /* type 1, until someone from prolific tells us... */
153 HX, /* HX version of the pl2303 chip */
154};
155
156struct pl2303_private {
157 spinlock_t lock;
158 struct pl2303_buf *buf;
159 int write_urb_in_use;
160 wait_queue_head_t delta_msr_wait;
161 u8 line_control;
162 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 enum pl2303_type type;
164};
165
Thiago Galesi572d3132006-07-29 10:46:37 -0300166/*
167 * pl2303_buf_alloc
168 *
169 * Allocate a circular buffer and all associated memory.
170 */
171static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
172{
173 struct pl2303_buf *pb;
174
175 if (size == 0)
176 return NULL;
177
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800178 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300179 if (pb == NULL)
180 return NULL;
181
182 pb->buf_buf = kmalloc(size, GFP_KERNEL);
183 if (pb->buf_buf == NULL) {
184 kfree(pb);
185 return NULL;
186 }
187
188 pb->buf_size = size;
189 pb->buf_get = pb->buf_put = pb->buf_buf;
190
191 return pb;
192}
193
194/*
195 * pl2303_buf_free
196 *
197 * Free the buffer and all associated memory.
198 */
199static void pl2303_buf_free(struct pl2303_buf *pb)
200{
201 if (pb) {
202 kfree(pb->buf_buf);
203 kfree(pb);
204 }
205}
206
207/*
208 * pl2303_buf_clear
209 *
210 * Clear out all data in the circular buffer.
211 */
212static void pl2303_buf_clear(struct pl2303_buf *pb)
213{
214 if (pb != NULL)
215 pb->buf_get = pb->buf_put;
216 /* equivalent to a get of all data available */
217}
218
219/*
220 * pl2303_buf_data_avail
221 *
222 * Return the number of bytes of data available in the circular
223 * buffer.
224 */
225static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
226{
227 if (pb == NULL)
228 return 0;
229
Alan Cox3a0f43e2008-07-22 11:14:49 +0100230 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300231}
232
233/*
234 * pl2303_buf_space_avail
235 *
236 * Return the number of bytes of space available in the circular
237 * buffer.
238 */
239static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
240{
241 if (pb == NULL)
242 return 0;
243
Alan Cox3a0f43e2008-07-22 11:14:49 +0100244 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300245}
246
247/*
248 * pl2303_buf_put
249 *
250 * Copy data data from a user buffer and put it into the circular buffer.
251 * Restrict to the amount of space available.
252 *
253 * Return the number of bytes copied.
254 */
255static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
256 unsigned int count)
257{
258 unsigned int len;
259
260 if (pb == NULL)
261 return 0;
262
263 len = pl2303_buf_space_avail(pb);
264 if (count > len)
265 count = len;
266
267 if (count == 0)
268 return 0;
269
270 len = pb->buf_buf + pb->buf_size - pb->buf_put;
271 if (count > len) {
272 memcpy(pb->buf_put, buf, len);
273 memcpy(pb->buf_buf, buf+len, count - len);
274 pb->buf_put = pb->buf_buf + count - len;
275 } else {
276 memcpy(pb->buf_put, buf, count);
277 if (count < len)
278 pb->buf_put += count;
279 else /* count == len */
280 pb->buf_put = pb->buf_buf;
281 }
282
283 return count;
284}
285
286/*
287 * pl2303_buf_get
288 *
289 * Get data from the circular buffer and copy to the given buffer.
290 * Restrict to the amount of data available.
291 *
292 * Return the number of bytes copied.
293 */
294static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
295 unsigned int count)
296{
297 unsigned int len;
298
299 if (pb == NULL)
300 return 0;
301
302 len = pl2303_buf_data_avail(pb);
303 if (count > len)
304 count = len;
305
306 if (count == 0)
307 return 0;
308
309 len = pb->buf_buf + pb->buf_size - pb->buf_get;
310 if (count > len) {
311 memcpy(buf, pb->buf_get, len);
312 memcpy(buf+len, pb->buf_buf, count - len);
313 pb->buf_get = pb->buf_buf + count - len;
314 } else {
315 memcpy(buf, pb->buf_get, count);
316 if (count < len)
317 pb->buf_get += count;
318 else /* count == len */
319 pb->buf_get = pb->buf_buf;
320 }
321
322 return count;
323}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Sarah Sharpeb44da02007-12-14 14:08:00 -0800325static int pl2303_vendor_read(__u16 value, __u16 index,
326 struct usb_serial *serial, unsigned char *buf)
327{
328 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
329 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
330 value, index, buf, 1, 100);
331 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
332 VENDOR_READ_REQUEST, value, index, res, buf[0]);
333 return res;
334}
335
336static int pl2303_vendor_write(__u16 value, __u16 index,
337 struct usb_serial *serial)
338{
339 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
340 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
341 value, index, NULL, 0, 100);
342 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
343 VENDOR_WRITE_REQUEST, value, index, res);
344 return res;
345}
346
Thiago Galesi372db8a2006-07-31 15:39:27 -0300347static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
349 struct pl2303_private *priv;
350 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800351 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 int i;
353
Sarah Sharp3e152502007-12-14 14:08:35 -0800354 buf = kmalloc(10, GFP_KERNEL);
355 if (buf == NULL)
356 return -ENOMEM;
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (serial->dev->descriptor.bDeviceClass == 0x02)
359 type = type_0;
360 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
361 type = HX;
362 else if (serial->dev->descriptor.bDeviceClass == 0x00)
363 type = type_1;
364 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
365 type = type_1;
366 dbg("device type: %d", type);
367
368 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100369 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 if (!priv)
371 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 spin_lock_init(&priv->lock);
373 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
374 if (priv->buf == NULL) {
375 kfree(priv);
376 goto cleanup;
377 }
378 init_waitqueue_head(&priv->delta_msr_wait);
379 priv->type = type;
380 usb_set_serial_port_data(serial->port[i], priv);
381 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800382
383 pl2303_vendor_read(0x8484, 0, serial, buf);
384 pl2303_vendor_write(0x0404, 0, serial);
385 pl2303_vendor_read(0x8484, 0, serial, buf);
386 pl2303_vendor_read(0x8383, 0, serial, buf);
387 pl2303_vendor_read(0x8484, 0, serial, buf);
388 pl2303_vendor_write(0x0404, 1, serial);
389 pl2303_vendor_read(0x8484, 0, serial, buf);
390 pl2303_vendor_read(0x8383, 0, serial, buf);
391 pl2303_vendor_write(0, 1, serial);
392 pl2303_vendor_write(1, 0, serial);
393 if (type == HX)
394 pl2303_vendor_write(2, 0x44, serial);
395 else
396 pl2303_vendor_write(2, 0x24, serial);
397
398 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 return 0;
400
401cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800402 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100403 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 priv = usb_get_serial_port_data(serial->port[i]);
405 pl2303_buf_free(priv->buf);
406 kfree(priv);
407 usb_set_serial_port_data(serial->port[i], NULL);
408 }
409 return -ENOMEM;
410}
411
Thiago Galesi372db8a2006-07-31 15:39:27 -0300412static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
414 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100415
Thiago Galesi372db8a2006-07-31 15:39:27 -0300416 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
417 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
418 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800419 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return retval;
421}
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423static void pl2303_send(struct usb_serial_port *port)
424{
425 int count, result;
426 struct pl2303_private *priv = usb_get_serial_port_data(port);
427 unsigned long flags;
428
Harvey Harrison441b62c2008-03-03 16:08:34 -0800429 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431 spin_lock_irqsave(&priv->lock, flags);
432
433 if (priv->write_urb_in_use) {
434 spin_unlock_irqrestore(&priv->lock, flags);
435 return;
436 }
437
438 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300439 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441 if (count == 0) {
442 spin_unlock_irqrestore(&priv->lock, flags);
443 return;
444 }
445
446 priv->write_urb_in_use = 1;
447
448 spin_unlock_irqrestore(&priv->lock, flags);
449
Harvey Harrison441b62c2008-03-03 16:08:34 -0800450 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300451 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453 port->write_urb->transfer_buffer_length = count;
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;
Frank Schaefer25b82862009-08-18 20:15:07 +0200530 const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
531 4800, 7200, 9600, 14400, 19200, 28800, 38400,
532 57600, 115200, 230400, 460800, 614400,
533 921600, 1228800, 2457600, 3000000, 6000000 };
534 int baud_floor, baud_ceil;
535 int k;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Harvey Harrison441b62c2008-03-03 16:08:34 -0800537 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Alan Coxbf5e5832008-01-08 14:55:51 +0000539 /* The PL2303 is reported to lose bytes if you change
540 serial settings even to the same values as before. Thus
541 we actually need to filter in this specific case */
542
Alan Cox95da3102008-07-22 11:09:07 +0100543 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000544 return;
545
Alan Cox95da3102008-07-22 11:09:07 +0100546 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Thiago Galesi372db8a2006-07-31 15:39:27 -0300548 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800550 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100551 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100552 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 return;
554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Thiago Galesi372db8a2006-07-31 15:39:27 -0300556 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
557 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
558 0, 0, buf, 7, 100);
559 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
560 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 if (cflag & CSIZE) {
563 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100564 case CS5:
565 buf[6] = 5;
566 break;
567 case CS6:
568 buf[6] = 6;
569 break;
570 case CS7:
571 buf[6] = 7;
572 break;
573 default:
574 case CS8:
575 buf[6] = 8;
576 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800578 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
580
Frank Schaefer25b82862009-08-18 20:15:07 +0200581 /* For reference buf[0]:buf[3] baud rate value */
582 /* NOTE: Only the values defined in baud_sup are supported !
583 * => if unsupported values are set, the PL2303 seems to use
584 * 9600 baud (at least my PL2303X always does)
585 */
Alan Cox95da3102008-07-22 11:09:07 +0100586 baud = tty_get_baud_rate(tty);
Frank Schaefer25b82862009-08-18 20:15:07 +0200587 dbg("%s - baud requested = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 if (baud) {
Frank Schaefer25b82862009-08-18 20:15:07 +0200589 /* Set baudrate to nearest supported value */
590 for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
591 if (baud_sup[k] / baud) {
592 baud_ceil = baud_sup[k];
593 if (k==0) {
594 baud = baud_ceil;
595 } else {
596 baud_floor = baud_sup[k-1];
597 if ((baud_ceil % baud)
598 > (baud % baud_floor))
599 baud = baud_floor;
600 else
601 baud = baud_ceil;
602 }
603 break;
604 }
605 }
606 if (baud > 1228800) {
607 /* type_0, type_1 only support up to 1228800 baud */
608 if (priv->type != HX)
609 baud = 1228800;
610 else if (baud > 6000000)
611 baud = 6000000;
612 }
613 dbg("%s - baud set = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 buf[0] = baud & 0xff;
615 buf[1] = (baud >> 8) & 0xff;
616 buf[2] = (baud >> 16) & 0xff;
617 buf[3] = (baud >> 24) & 0xff;
618 }
619
620 /* For reference buf[4]=0 is 1 stop bits */
621 /* For reference buf[4]=1 is 1.5 stop bits */
622 /* For reference buf[4]=2 is 2 stop bits */
623 if (cflag & CSTOPB) {
Frank Schaefer29cf1b72009-08-18 20:34:24 +0200624 /* NOTE: Comply with "real" UARTs / RS232:
625 * use 1.5 instead of 2 stop bits with 5 data bits
626 */
627 if ((cflag & CSIZE) == CS5) {
628 buf[4] = 1;
629 dbg("%s - stop bits = 1.5", __func__);
630 } else {
631 buf[4] = 2;
632 dbg("%s - stop bits = 2", __func__);
633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 } else {
635 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800636 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 }
638
639 if (cflag & PARENB) {
640 /* For reference buf[5]=0 is none parity */
641 /* For reference buf[5]=1 is odd parity */
642 /* For reference buf[5]=2 is even parity */
643 /* For reference buf[5]=3 is mark parity */
644 /* For reference buf[5]=4 is space parity */
645 if (cflag & PARODD) {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200646 if (cflag & CMSPAR) {
647 buf[5] = 3;
648 dbg("%s - parity = mark", __func__);
649 } else {
650 buf[5] = 1;
651 dbg("%s - parity = odd", __func__);
652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 } else {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200654 if (cflag & CMSPAR) {
655 buf[5] = 4;
656 dbg("%s - parity = space", __func__);
657 } else {
658 buf[5] = 2;
659 dbg("%s - parity = even", __func__);
660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
662 } else {
663 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800664 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
666
Thiago Galesi372db8a2006-07-31 15:39:27 -0300667 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
668 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
669 0, 0, buf, 7, 100);
670 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 /* change control lines if we are switching to or from B0 */
673 spin_lock_irqsave(&priv->lock, flags);
674 control = priv->line_control;
675 if ((cflag & CBAUD) == B0)
676 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
677 else
678 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
679 if (control != priv->line_control) {
680 control = priv->line_control;
681 spin_unlock_irqrestore(&priv->lock, flags);
682 set_control_lines(serial->dev, control);
683 } else {
684 spin_unlock_irqrestore(&priv->lock, flags);
685 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
688
Thiago Galesi372db8a2006-07-31 15:39:27 -0300689 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
690 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
691 0, 0, buf, 7, 100);
692 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
694
695 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800697 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800699 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200700 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800701 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
703
Frank Schaefer25b82862009-08-18 20:15:07 +0200704 /* Save resulting baud rate */
Alan Coxdf64c472007-10-15 20:54:47 +0100705 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100706 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100707
Thiago Galesi372db8a2006-07-31 15:39:27 -0300708 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
710
Alan Cox335f8512009-06-11 12:26:29 +0100711static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
Thiago Galesi572d3132006-07-29 10:46:37 -0300712{
713 struct pl2303_private *priv = usb_get_serial_port_data(port);
714 unsigned long flags;
Alan Cox335f8512009-06-11 12:26:29 +0100715 u8 control;
716
717 spin_lock_irqsave(&priv->lock, flags);
718 /* Change DTR and RTS */
719 if (on)
720 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
721 else
722 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
723 control = priv->line_control;
724 spin_unlock_irqrestore(&priv->lock, flags);
725 set_control_lines(port->serial->dev, control);
726}
727
728static void pl2303_close(struct usb_serial_port *port)
729{
730 struct pl2303_private *priv = usb_get_serial_port_data(port);
731 unsigned long flags;
Thiago Galesi572d3132006-07-29 10:46:37 -0300732
Harvey Harrison441b62c2008-03-03 16:08:34 -0800733 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300734
Thiago Galesi572d3132006-07-29 10:46:37 -0300735 spin_lock_irqsave(&priv->lock, flags);
Thiago Galesi572d3132006-07-29 10:46:37 -0300736 /* clear out any remaining data in the buffer */
737 pl2303_buf_clear(priv->buf);
738 spin_unlock_irqrestore(&priv->lock, flags);
739
Thiago Galesi572d3132006-07-29 10:46:37 -0300740 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800741 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300742 usb_kill_urb(port->write_urb);
743 usb_kill_urb(port->read_urb);
744 usb_kill_urb(port->interrupt_in_urb);
745
Thiago Galesi572d3132006-07-29 10:46:37 -0300746}
747
Alan Coxa509a7e2009-09-19 13:13:26 -0700748static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Alan Cox606d0992006-12-08 02:38:45 -0800750 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 struct usb_serial *serial = port->serial;
752 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 int result;
754
Harvey Harrison441b62c2008-03-03 16:08:34 -0800755 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Dariusz M16948992005-07-28 18:06:13 +0200757 if (priv->type != HX) {
758 usb_clear_halt(serial->dev, port->write_urb->pipe);
759 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800760 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800762 pl2303_vendor_write(8, 0, serial);
763 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 }
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100767 if (tty)
768 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Harvey Harrison441b62c2008-03-03 16:08:34 -0800770 dbg("%s - submitting read urb", __func__);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300771 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300773 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800774 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100775 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return -EPROTO;
777 }
778
Harvey Harrison441b62c2008-03-03 16:08:34 -0800779 dbg("%s - submitting interrupt urb", __func__);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300780 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300782 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800783 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100784 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return -EPROTO;
786 }
Alan Cox335f8512009-06-11 12:26:29 +0100787 port->port.drain_delay = 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 return 0;
789}
790
Alan Cox95da3102008-07-22 11:09:07 +0100791static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300792 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
Alan Cox95da3102008-07-22 11:09:07 +0100794 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 struct pl2303_private *priv = usb_get_serial_port_data(port);
796 unsigned long flags;
797 u8 control;
798
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700799 if (!usb_get_intfdata(port->serial->interface))
800 return -ENODEV;
801
Thiago Galesi372db8a2006-07-31 15:39:27 -0300802 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (set & TIOCM_RTS)
804 priv->line_control |= CONTROL_RTS;
805 if (set & TIOCM_DTR)
806 priv->line_control |= CONTROL_DTR;
807 if (clear & TIOCM_RTS)
808 priv->line_control &= ~CONTROL_RTS;
809 if (clear & TIOCM_DTR)
810 priv->line_control &= ~CONTROL_DTR;
811 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300812 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Thiago Galesi372db8a2006-07-31 15:39:27 -0300814 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815}
816
Alan Cox95da3102008-07-22 11:09:07 +0100817static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
Alan Cox95da3102008-07-22 11:09:07 +0100819 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 struct pl2303_private *priv = usb_get_serial_port_data(port);
821 unsigned long flags;
822 unsigned int mcr;
823 unsigned int status;
824 unsigned int result;
825
Harvey Harrison441b62c2008-03-03 16:08:34 -0800826 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700828 if (!usb_get_intfdata(port->serial->interface))
829 return -ENODEV;
830
Thiago Galesi372db8a2006-07-31 15:39:27 -0300831 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 mcr = priv->line_control;
833 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300834 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
837 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
838 | ((status & UART_CTS) ? TIOCM_CTS : 0)
839 | ((status & UART_DSR) ? TIOCM_DSR : 0)
840 | ((status & UART_RING) ? TIOCM_RI : 0)
841 | ((status & UART_DCD) ? TIOCM_CD : 0);
842
Harvey Harrison441b62c2008-03-03 16:08:34 -0800843 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 return result;
846}
847
Alan Cox335f8512009-06-11 12:26:29 +0100848static int pl2303_carrier_raised(struct usb_serial_port *port)
849{
850 struct pl2303_private *priv = usb_get_serial_port_data(port);
851 if (priv->line_status & UART_DCD)
852 return 1;
853 return 0;
854}
855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
857{
858 struct pl2303_private *priv = usb_get_serial_port_data(port);
859 unsigned long flags;
860 unsigned int prevstatus;
861 unsigned int status;
862 unsigned int changed;
863
Thiago Galesi372db8a2006-07-31 15:39:27 -0300864 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300866 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 while (1) {
869 interruptible_sleep_on(&priv->delta_msr_wait);
870 /* see if a signal did it */
871 if (signal_pending(current))
872 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300873
874 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300876 spin_unlock_irqrestore(&priv->lock, flags);
877
Alan Cox3a0f43e2008-07-22 11:14:49 +0100878 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
881 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
882 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100883 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 return 0;
885 }
886 prevstatus = status;
887 }
888 /* NOTREACHED */
889 return 0;
890}
891
Alan Cox95da3102008-07-22 11:09:07 +0100892static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300893 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
John Tsiombikas67b99462010-02-25 17:09:08 +0200895 struct serial_struct ser;
Alan Cox95da3102008-07-22 11:09:07 +0100896 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800897 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
899 switch (cmd) {
John Tsiombikas67b99462010-02-25 17:09:08 +0200900 case TIOCGSERIAL:
901 memset(&ser, 0, sizeof ser);
902 ser.type = PORT_16654;
903 ser.line = port->serial->minor;
904 ser.port = port->number;
905 ser.baud_base = 460800;
906
907 if (copy_to_user((void __user *)arg, &ser, sizeof ser))
908 return -EFAULT;
909
910 return 0;
911
Alan Cox3a0f43e2008-07-22 11:14:49 +0100912 case TIOCMIWAIT:
913 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
914 return wait_modem_info(port, arg);
915 default:
916 dbg("%s not supported = 0x%04x", __func__, cmd);
917 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 return -ENOIOCTLCMD;
920}
921
Alan Cox95da3102008-07-22 11:09:07 +0100922static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
Alan Cox95da3102008-07-22 11:09:07 +0100924 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 struct usb_serial *serial = port->serial;
926 u16 state;
927 int result;
928
Harvey Harrison441b62c2008-03-03 16:08:34 -0800929 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 if (break_state == 0)
932 state = BREAK_OFF;
933 else
934 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100935 dbg("%s - turning break %s", __func__,
936 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Thiago Galesi372db8a2006-07-31 15:39:27 -0300938 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
939 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
940 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800942 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943}
944
Alan Sternf9c99bb2009-06-02 11:53:55 -0400945static void pl2303_release(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
947 int i;
948 struct pl2303_private *priv;
949
Harvey Harrison441b62c2008-03-03 16:08:34 -0800950 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 for (i = 0; i < serial->num_ports; ++i) {
953 priv = usb_get_serial_port_data(serial->port[i]);
954 if (priv) {
955 pl2303_buf_free(priv->buf);
956 kfree(priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700961static void pl2303_update_line_status(struct usb_serial_port *port,
962 unsigned char *data,
963 unsigned int actual_length)
964{
965
966 struct pl2303_private *priv = usb_get_serial_port_data(port);
967 unsigned long flags;
968 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200969 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300970 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700971
Thiago Galesi9c537612006-07-29 10:47:12 -0300972 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
973 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
974
975
976 if (idv == SIEMENS_VENDOR_ID) {
977 if (idp == SIEMENS_PRODUCT_ID_X65 ||
978 idp == SIEMENS_PRODUCT_ID_SX1 ||
979 idp == SIEMENS_PRODUCT_ID_X75) {
980
981 length = 1;
982 status_idx = 0;
983 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700984 }
985
986 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300987 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700988
Alan Cox3a0f43e2008-07-22 11:14:49 +0100989 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700990 spin_lock_irqsave(&priv->lock, flags);
991 priv->line_status = data[status_idx];
992 spin_unlock_irqrestore(&priv->lock, flags);
Jason Wessel430eb0d2009-05-29 13:34:16 -0500993 if (priv->line_status & UART_BREAK_ERROR)
994 usb_serial_handle_break(port);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300995 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700996}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
David Howells7d12e782006-10-05 14:55:46 +0100998static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
Ming Leicdc97792008-02-24 18:41:47 +08001000 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -07001002 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001003 int status = urb->status;
1004 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Harvey Harrison441b62c2008-03-03 16:08:34 -08001006 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001008 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 case 0:
1010 /* success */
1011 break;
1012 case -ECONNRESET:
1013 case -ENOENT:
1014 case -ESHUTDOWN:
1015 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001016 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001017 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return;
1019 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -08001020 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001021 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 goto exit;
1023 }
1024
Harvey Harrison441b62c2008-03-03 16:08:34 -08001025 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001026 urb->actual_length, urb->transfer_buffer);
1027
Flavio Leitner97bb13e2005-04-18 17:39:31 -07001028 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001031 retval = usb_submit_urb(urb, GFP_ATOMIC);
1032 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001033 dev_err(&urb->dev->dev,
1034 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001035 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036}
1037
Alan Coxd4fc4a72009-07-09 13:36:58 +01001038static void pl2303_push_data(struct tty_struct *tty,
1039 struct usb_serial_port *port, struct urb *urb,
1040 u8 line_status)
1041{
1042 unsigned char *data = urb->transfer_buffer;
1043 /* get tty_flag from status */
1044 char tty_flag = TTY_NORMAL;
1045 /* break takes precedence over parity, */
1046 /* which takes precedence over framing errors */
1047 if (line_status & UART_BREAK_ERROR)
1048 tty_flag = TTY_BREAK;
1049 else if (line_status & UART_PARITY_ERROR)
1050 tty_flag = TTY_PARITY;
1051 else if (line_status & UART_FRAME_ERROR)
1052 tty_flag = TTY_FRAME;
1053 dbg("%s - tty_flag = %d", __func__, tty_flag);
1054
Alan Coxd4fc4a72009-07-09 13:36:58 +01001055 /* overrun is special, not associated with a char */
1056 if (line_status & UART_OVERRUN_ERROR)
1057 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Johan Hovold9388e2e2009-10-08 11:36:46 +02001058
1059 if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq))
1060 tty_insert_flip_string(tty, data, urb->actual_length);
1061 else {
Alan Coxd4fc4a72009-07-09 13:36:58 +01001062 int i;
1063 for (i = 0; i < urb->actual_length; ++i)
1064 if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
1065 tty_insert_flip_char(tty, data[i], tty_flag);
Johan Hovold9388e2e2009-10-08 11:36:46 +02001066 }
Alan Coxd4fc4a72009-07-09 13:36:58 +01001067 tty_flip_buffer_push(tty);
1068}
1069
David Howells7d12e782006-10-05 14:55:46 +01001070static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
Ming Leicdc97792008-02-24 18:41:47 +08001072 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 struct pl2303_private *priv = usb_get_serial_port_data(port);
1074 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001077 int status = urb->status;
1078 u8 line_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 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001083 dbg("%s - urb status = %d", __func__, status);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001084 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001085 /* PL2303 mysteriously fails with -EPROTO reschedule
1086 * the read */
1087 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001088 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 result = usb_submit_urb(urb, GFP_ATOMIC);
1090 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001091 dev_err(&urb->dev->dev, "%s - failed"
1092 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001093 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 return;
1095 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001096 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return;
1098 }
1099
Harvey Harrison441b62c2008-03-03 16:08:34 -08001100 usb_serial_debug_data(debug, &port->dev, __func__,
Alan Coxd4fc4a72009-07-09 13:36:58 +01001101 urb->actual_length, urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001104 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1106 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001107 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Alan Cox4a90f092008-10-13 10:39:46 +01001109 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 if (tty && urb->actual_length) {
Alan Coxd4fc4a72009-07-09 13:36:58 +01001111 pl2303_push_data(tty, port, urb, line_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 }
Alan Cox4a90f092008-10-13 10:39:46 +01001113 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 /* Schedule the next read _if_ we are still open */
Alan Stern1f871582010-02-17 10:05:47 -05001115 result = usb_submit_urb(urb, GFP_ATOMIC);
1116 if (result && result != -EPERM)
1117 dev_err(&urb->dev->dev, "%s - failed resubmitting"
1118 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119}
1120
David Howells7d12e782006-10-05 14:55:46 +01001121static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
Ming Leicdc97792008-02-24 18:41:47 +08001123 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 struct pl2303_private *priv = usb_get_serial_port_data(port);
1125 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001126 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
Harvey Harrison441b62c2008-03-03 16:08:34 -08001128 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001130 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 case 0:
1132 /* success */
1133 break;
1134 case -ECONNRESET:
1135 case -ENOENT:
1136 case -ESHUTDOWN:
1137 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001138 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001139 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 priv->write_urb_in_use = 0;
1141 return;
1142 default:
1143 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001144 dbg("%s - Overflow in write", __func__);
1145 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001146 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 port->write_urb->transfer_buffer_length = 1;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001148 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001150 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001151 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 else
1153 return;
1154 }
1155
1156 priv->write_urb_in_use = 0;
1157
1158 /* send any buffered data */
1159 pl2303_send(port);
1160}
1161
Thiago Galesi572d3132006-07-29 10:46:37 -03001162/* All of the device info needed for the PL2303 SIO serial converter */
1163static struct usb_serial_driver pl2303_device = {
1164 .driver = {
1165 .owner = THIS_MODULE,
1166 .name = "pl2303",
1167 },
1168 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001169 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001170 .num_ports = 1,
1171 .open = pl2303_open,
1172 .close = pl2303_close,
Alan Cox335f8512009-06-11 12:26:29 +01001173 .dtr_rts = pl2303_dtr_rts,
1174 .carrier_raised = pl2303_carrier_raised,
Thiago Galesi572d3132006-07-29 10:46:37 -03001175 .write = pl2303_write,
1176 .ioctl = pl2303_ioctl,
1177 .break_ctl = pl2303_break_ctl,
1178 .set_termios = pl2303_set_termios,
1179 .tiocmget = pl2303_tiocmget,
1180 .tiocmset = pl2303_tiocmset,
1181 .read_bulk_callback = pl2303_read_bulk_callback,
1182 .read_int_callback = pl2303_read_int_callback,
1183 .write_bulk_callback = pl2303_write_bulk_callback,
1184 .write_room = pl2303_write_room,
1185 .chars_in_buffer = pl2303_chars_in_buffer,
1186 .attach = pl2303_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -04001187 .release = pl2303_release,
Thiago Galesi572d3132006-07-29 10:46:37 -03001188};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
Thiago Galesi372db8a2006-07-31 15:39:27 -03001190static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191{
1192 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 retval = usb_serial_register(&pl2303_device);
1195 if (retval)
1196 goto failed_usb_serial_register;
1197 retval = usb_register(&pl2303_driver);
1198 if (retval)
1199 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001200 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return 0;
1202failed_usb_register:
1203 usb_serial_deregister(&pl2303_device);
1204failed_usb_serial_register:
1205 return retval;
1206}
1207
Thiago Galesi372db8a2006-07-31 15:39:27 -03001208static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001210 usb_deregister(&pl2303_driver);
1211 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212}
1213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214module_init(pl2303_init);
1215module_exit(pl2303_exit);
1216
1217MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218MODULE_LICENSE("GPL");
1219
1220module_param(debug, bool, S_IRUGO | S_IWUSR);
1221MODULE_PARM_DESC(debug, "Debug enabled or not");
1222