blob: 77e968045f755f587a38683f18bcc7c02ba4671e [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) },
Simone Contini18344a12010-04-12 23:25:10 +020062 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090064 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
66 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
67 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
68 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
69 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080070 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
72 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
73 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
74 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
75 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
76 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
77 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
78 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080081 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020082 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Alan Cox912299f2009-04-06 17:35:12 +010083 { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070084 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010085 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
86 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010087 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010088 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080089 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040090 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100091 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020092 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090093 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090094 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050095 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Matthew Arnold7c992002008-12-13 22:42:53 +110096 { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
Mike Provencheraf4b8512008-12-16 14:30:14 -060097 { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
Gianpaolo Cugola8540d662009-06-05 22:57:52 +020098 { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
Khanh-Dang Nguyen Thu Lam49276562009-07-28 19:41:17 +020099 { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
Pawel Ludwikow35904e62009-08-27 14:15:50 +0200100 { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
Manuel Jander9a61d722010-03-29 23:51:57 +0200101 { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 { } /* Terminating entry */
103};
104
Thiago Galesi372db8a2006-07-31 15:39:27 -0300105MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 .name = "pl2303",
109 .probe = usb_serial_probe,
110 .disconnect = usb_serial_disconnect,
111 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800112 .suspend = usb_serial_suspend,
113 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800114 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800115 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116};
117
118#define SET_LINE_REQUEST_TYPE 0x21
119#define SET_LINE_REQUEST 0x20
120
121#define SET_CONTROL_REQUEST_TYPE 0x21
122#define SET_CONTROL_REQUEST 0x22
123#define CONTROL_DTR 0x01
124#define CONTROL_RTS 0x02
125
126#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100127#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128#define BREAK_ON 0xffff
129#define BREAK_OFF 0x0000
130
131#define GET_LINE_REQUEST_TYPE 0xa1
132#define GET_LINE_REQUEST 0x21
133
134#define VENDOR_WRITE_REQUEST_TYPE 0x40
135#define VENDOR_WRITE_REQUEST 0x01
136
137#define VENDOR_READ_REQUEST_TYPE 0xc0
138#define VENDOR_READ_REQUEST 0x01
139
140#define UART_STATE 0x08
141#define UART_STATE_TRANSIENT_MASK 0x74
142#define UART_DCD 0x01
143#define UART_DSR 0x02
144#define UART_BREAK_ERROR 0x04
145#define UART_RING 0x08
146#define UART_FRAME_ERROR 0x10
147#define UART_PARITY_ERROR 0x20
148#define UART_OVERRUN_ERROR 0x40
149#define UART_CTS 0x80
150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152enum pl2303_type {
153 type_0, /* don't know the difference between type 0 and */
154 type_1, /* type 1, until someone from prolific tells us... */
155 HX, /* HX version of the pl2303 chip */
156};
157
158struct pl2303_private {
159 spinlock_t lock;
160 struct pl2303_buf *buf;
161 int write_urb_in_use;
162 wait_queue_head_t delta_msr_wait;
163 u8 line_control;
164 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 enum pl2303_type type;
166};
167
Thiago Galesi572d3132006-07-29 10:46:37 -0300168/*
169 * pl2303_buf_alloc
170 *
171 * Allocate a circular buffer and all associated memory.
172 */
173static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
174{
175 struct pl2303_buf *pb;
176
177 if (size == 0)
178 return NULL;
179
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800180 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300181 if (pb == NULL)
182 return NULL;
183
184 pb->buf_buf = kmalloc(size, GFP_KERNEL);
185 if (pb->buf_buf == NULL) {
186 kfree(pb);
187 return NULL;
188 }
189
190 pb->buf_size = size;
191 pb->buf_get = pb->buf_put = pb->buf_buf;
192
193 return pb;
194}
195
196/*
197 * pl2303_buf_free
198 *
199 * Free the buffer and all associated memory.
200 */
201static void pl2303_buf_free(struct pl2303_buf *pb)
202{
203 if (pb) {
204 kfree(pb->buf_buf);
205 kfree(pb);
206 }
207}
208
209/*
210 * pl2303_buf_clear
211 *
212 * Clear out all data in the circular buffer.
213 */
214static void pl2303_buf_clear(struct pl2303_buf *pb)
215{
216 if (pb != NULL)
217 pb->buf_get = pb->buf_put;
218 /* equivalent to a get of all data available */
219}
220
221/*
222 * pl2303_buf_data_avail
223 *
224 * Return the number of bytes of data available in the circular
225 * buffer.
226 */
227static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
228{
229 if (pb == NULL)
230 return 0;
231
Alan Cox3a0f43e2008-07-22 11:14:49 +0100232 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300233}
234
235/*
236 * pl2303_buf_space_avail
237 *
238 * Return the number of bytes of space available in the circular
239 * buffer.
240 */
241static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
242{
243 if (pb == NULL)
244 return 0;
245
Alan Cox3a0f43e2008-07-22 11:14:49 +0100246 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300247}
248
249/*
250 * pl2303_buf_put
251 *
252 * Copy data data from a user buffer and put it into the circular buffer.
253 * Restrict to the amount of space available.
254 *
255 * Return the number of bytes copied.
256 */
257static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
258 unsigned int count)
259{
260 unsigned int len;
261
262 if (pb == NULL)
263 return 0;
264
265 len = pl2303_buf_space_avail(pb);
266 if (count > len)
267 count = len;
268
269 if (count == 0)
270 return 0;
271
272 len = pb->buf_buf + pb->buf_size - pb->buf_put;
273 if (count > len) {
274 memcpy(pb->buf_put, buf, len);
275 memcpy(pb->buf_buf, buf+len, count - len);
276 pb->buf_put = pb->buf_buf + count - len;
277 } else {
278 memcpy(pb->buf_put, buf, count);
279 if (count < len)
280 pb->buf_put += count;
281 else /* count == len */
282 pb->buf_put = pb->buf_buf;
283 }
284
285 return count;
286}
287
288/*
289 * pl2303_buf_get
290 *
291 * Get data from the circular buffer and copy to the given buffer.
292 * Restrict to the amount of data available.
293 *
294 * Return the number of bytes copied.
295 */
296static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
297 unsigned int count)
298{
299 unsigned int len;
300
301 if (pb == NULL)
302 return 0;
303
304 len = pl2303_buf_data_avail(pb);
305 if (count > len)
306 count = len;
307
308 if (count == 0)
309 return 0;
310
311 len = pb->buf_buf + pb->buf_size - pb->buf_get;
312 if (count > len) {
313 memcpy(buf, pb->buf_get, len);
314 memcpy(buf+len, pb->buf_buf, count - len);
315 pb->buf_get = pb->buf_buf + count - len;
316 } else {
317 memcpy(buf, pb->buf_get, count);
318 if (count < len)
319 pb->buf_get += count;
320 else /* count == len */
321 pb->buf_get = pb->buf_buf;
322 }
323
324 return count;
325}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Sarah Sharpeb44da02007-12-14 14:08:00 -0800327static int pl2303_vendor_read(__u16 value, __u16 index,
328 struct usb_serial *serial, unsigned char *buf)
329{
330 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
331 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
332 value, index, buf, 1, 100);
333 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
334 VENDOR_READ_REQUEST, value, index, res, buf[0]);
335 return res;
336}
337
338static int pl2303_vendor_write(__u16 value, __u16 index,
339 struct usb_serial *serial)
340{
341 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
342 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
343 value, index, NULL, 0, 100);
344 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
345 VENDOR_WRITE_REQUEST, value, index, res);
346 return res;
347}
348
Thiago Galesi372db8a2006-07-31 15:39:27 -0300349static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 struct pl2303_private *priv;
352 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800353 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 int i;
355
Sarah Sharp3e152502007-12-14 14:08:35 -0800356 buf = kmalloc(10, GFP_KERNEL);
357 if (buf == NULL)
358 return -ENOMEM;
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 if (serial->dev->descriptor.bDeviceClass == 0x02)
361 type = type_0;
362 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
363 type = HX;
364 else if (serial->dev->descriptor.bDeviceClass == 0x00)
365 type = type_1;
366 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
367 type = type_1;
368 dbg("device type: %d", type);
369
370 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100371 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 if (!priv)
373 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 spin_lock_init(&priv->lock);
375 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
376 if (priv->buf == NULL) {
377 kfree(priv);
378 goto cleanup;
379 }
380 init_waitqueue_head(&priv->delta_msr_wait);
381 priv->type = type;
382 usb_set_serial_port_data(serial->port[i], priv);
383 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800384
385 pl2303_vendor_read(0x8484, 0, serial, buf);
386 pl2303_vendor_write(0x0404, 0, serial);
387 pl2303_vendor_read(0x8484, 0, serial, buf);
388 pl2303_vendor_read(0x8383, 0, serial, buf);
389 pl2303_vendor_read(0x8484, 0, serial, buf);
390 pl2303_vendor_write(0x0404, 1, serial);
391 pl2303_vendor_read(0x8484, 0, serial, buf);
392 pl2303_vendor_read(0x8383, 0, serial, buf);
393 pl2303_vendor_write(0, 1, serial);
394 pl2303_vendor_write(1, 0, serial);
395 if (type == HX)
396 pl2303_vendor_write(2, 0x44, serial);
397 else
398 pl2303_vendor_write(2, 0x24, serial);
399
400 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return 0;
402
403cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800404 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100405 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 priv = usb_get_serial_port_data(serial->port[i]);
407 pl2303_buf_free(priv->buf);
408 kfree(priv);
409 usb_set_serial_port_data(serial->port[i], NULL);
410 }
411 return -ENOMEM;
412}
413
Thiago Galesi372db8a2006-07-31 15:39:27 -0300414static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100417
Thiago Galesi372db8a2006-07-31 15:39:27 -0300418 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
419 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
420 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800421 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return retval;
423}
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425static void pl2303_send(struct usb_serial_port *port)
426{
427 int count, result;
428 struct pl2303_private *priv = usb_get_serial_port_data(port);
429 unsigned long flags;
430
Harvey Harrison441b62c2008-03-03 16:08:34 -0800431 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 spin_lock_irqsave(&priv->lock, flags);
434
435 if (priv->write_urb_in_use) {
436 spin_unlock_irqrestore(&priv->lock, flags);
437 return;
438 }
439
440 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300441 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 if (count == 0) {
444 spin_unlock_irqrestore(&priv->lock, flags);
445 return;
446 }
447
448 priv->write_urb_in_use = 1;
449
450 spin_unlock_irqrestore(&priv->lock, flags);
451
Harvey Harrison441b62c2008-03-03 16:08:34 -0800452 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300453 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 port->write_urb->transfer_buffer_length = count;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300456 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300458 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800459 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100461 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 }
463
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700464 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465}
466
Alan Cox95da3102008-07-22 11:09:07 +0100467static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
468 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300469{
470 struct pl2303_private *priv = usb_get_serial_port_data(port);
471 unsigned long flags;
472
Harvey Harrison441b62c2008-03-03 16:08:34 -0800473 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300474
475 if (!count)
476 return count;
477
478 spin_lock_irqsave(&priv->lock, flags);
479 count = pl2303_buf_put(priv->buf, buf, count);
480 spin_unlock_irqrestore(&priv->lock, flags);
481
482 pl2303_send(port);
483
484 return count;
485}
486
Alan Cox95da3102008-07-22 11:09:07 +0100487static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
Alan Cox95da3102008-07-22 11:09:07 +0100489 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 struct pl2303_private *priv = usb_get_serial_port_data(port);
491 int room = 0;
492 unsigned long flags;
493
Harvey Harrison441b62c2008-03-03 16:08:34 -0800494 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 spin_lock_irqsave(&priv->lock, flags);
497 room = pl2303_buf_space_avail(priv->buf);
498 spin_unlock_irqrestore(&priv->lock, flags);
499
Harvey Harrison441b62c2008-03-03 16:08:34 -0800500 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 return room;
502}
503
Alan Cox95da3102008-07-22 11:09:07 +0100504static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
Alan Cox95da3102008-07-22 11:09:07 +0100506 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 struct pl2303_private *priv = usb_get_serial_port_data(port);
508 int chars = 0;
509 unsigned long flags;
510
Harvey Harrison441b62c2008-03-03 16:08:34 -0800511 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 spin_lock_irqsave(&priv->lock, flags);
514 chars = pl2303_buf_data_avail(priv->buf);
515 spin_unlock_irqrestore(&priv->lock, flags);
516
Harvey Harrison441b62c2008-03-03 16:08:34 -0800517 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 return chars;
519}
520
Alan Cox95da3102008-07-22 11:09:07 +0100521static void pl2303_set_termios(struct tty_struct *tty,
522 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523{
524 struct usb_serial *serial = port->serial;
525 struct pl2303_private *priv = usb_get_serial_port_data(port);
526 unsigned long flags;
527 unsigned int cflag;
528 unsigned char *buf;
529 int baud;
530 int i;
531 u8 control;
Frank Schaefer25b82862009-08-18 20:15:07 +0200532 const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
533 4800, 7200, 9600, 14400, 19200, 28800, 38400,
534 57600, 115200, 230400, 460800, 614400,
535 921600, 1228800, 2457600, 3000000, 6000000 };
536 int baud_floor, baud_ceil;
537 int k;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Harvey Harrison441b62c2008-03-03 16:08:34 -0800539 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Alan Coxbf5e5832008-01-08 14:55:51 +0000541 /* The PL2303 is reported to lose bytes if you change
542 serial settings even to the same values as before. Thus
543 we actually need to filter in this specific case */
544
Alan Cox95da3102008-07-22 11:09:07 +0100545 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000546 return;
547
Alan Cox95da3102008-07-22 11:09:07 +0100548 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Thiago Galesi372db8a2006-07-31 15:39:27 -0300550 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800552 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100553 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100554 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 return;
556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
Thiago Galesi372db8a2006-07-31 15:39:27 -0300558 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
559 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
560 0, 0, buf, 7, 100);
561 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
562 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
564 if (cflag & CSIZE) {
565 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100566 case CS5:
567 buf[6] = 5;
568 break;
569 case CS6:
570 buf[6] = 6;
571 break;
572 case CS7:
573 buf[6] = 7;
574 break;
575 default:
576 case CS8:
577 buf[6] = 8;
578 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800580 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 }
582
Frank Schaefer25b82862009-08-18 20:15:07 +0200583 /* For reference buf[0]:buf[3] baud rate value */
584 /* NOTE: Only the values defined in baud_sup are supported !
585 * => if unsupported values are set, the PL2303 seems to use
586 * 9600 baud (at least my PL2303X always does)
587 */
Alan Cox95da3102008-07-22 11:09:07 +0100588 baud = tty_get_baud_rate(tty);
Frank Schaefer25b82862009-08-18 20:15:07 +0200589 dbg("%s - baud requested = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (baud) {
Frank Schaefer25b82862009-08-18 20:15:07 +0200591 /* Set baudrate to nearest supported value */
592 for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
593 if (baud_sup[k] / baud) {
594 baud_ceil = baud_sup[k];
595 if (k==0) {
596 baud = baud_ceil;
597 } else {
598 baud_floor = baud_sup[k-1];
599 if ((baud_ceil % baud)
600 > (baud % baud_floor))
601 baud = baud_floor;
602 else
603 baud = baud_ceil;
604 }
605 break;
606 }
607 }
608 if (baud > 1228800) {
609 /* type_0, type_1 only support up to 1228800 baud */
610 if (priv->type != HX)
611 baud = 1228800;
612 else if (baud > 6000000)
613 baud = 6000000;
614 }
615 dbg("%s - baud set = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 buf[0] = baud & 0xff;
617 buf[1] = (baud >> 8) & 0xff;
618 buf[2] = (baud >> 16) & 0xff;
619 buf[3] = (baud >> 24) & 0xff;
620 }
621
622 /* For reference buf[4]=0 is 1 stop bits */
623 /* For reference buf[4]=1 is 1.5 stop bits */
624 /* For reference buf[4]=2 is 2 stop bits */
625 if (cflag & CSTOPB) {
Frank Schaefer29cf1b72009-08-18 20:34:24 +0200626 /* NOTE: Comply with "real" UARTs / RS232:
627 * use 1.5 instead of 2 stop bits with 5 data bits
628 */
629 if ((cflag & CSIZE) == CS5) {
630 buf[4] = 1;
631 dbg("%s - stop bits = 1.5", __func__);
632 } else {
633 buf[4] = 2;
634 dbg("%s - stop bits = 2", __func__);
635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 } else {
637 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800638 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 }
640
641 if (cflag & PARENB) {
642 /* For reference buf[5]=0 is none parity */
643 /* For reference buf[5]=1 is odd parity */
644 /* For reference buf[5]=2 is even parity */
645 /* For reference buf[5]=3 is mark parity */
646 /* For reference buf[5]=4 is space parity */
647 if (cflag & PARODD) {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200648 if (cflag & CMSPAR) {
649 buf[5] = 3;
650 dbg("%s - parity = mark", __func__);
651 } else {
652 buf[5] = 1;
653 dbg("%s - parity = odd", __func__);
654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 } else {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200656 if (cflag & CMSPAR) {
657 buf[5] = 4;
658 dbg("%s - parity = space", __func__);
659 } else {
660 buf[5] = 2;
661 dbg("%s - parity = even", __func__);
662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
664 } else {
665 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800666 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
668
Thiago Galesi372db8a2006-07-31 15:39:27 -0300669 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
670 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
671 0, 0, buf, 7, 100);
672 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 /* change control lines if we are switching to or from B0 */
675 spin_lock_irqsave(&priv->lock, flags);
676 control = priv->line_control;
677 if ((cflag & CBAUD) == B0)
678 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
679 else
680 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
681 if (control != priv->line_control) {
682 control = priv->line_control;
683 spin_unlock_irqrestore(&priv->lock, flags);
684 set_control_lines(serial->dev, control);
685 } else {
686 spin_unlock_irqrestore(&priv->lock, flags);
687 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
690
Thiago Galesi372db8a2006-07-31 15:39:27 -0300691 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
692 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
693 0, 0, buf, 7, 100);
694 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
696
697 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800699 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800701 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200702 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800703 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 }
705
Frank Schaefer25b82862009-08-18 20:15:07 +0200706 /* Save resulting baud rate */
Alan Coxdf64c472007-10-15 20:54:47 +0100707 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100708 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100709
Thiago Galesi372db8a2006-07-31 15:39:27 -0300710 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
Alan Cox335f8512009-06-11 12:26:29 +0100713static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
Thiago Galesi572d3132006-07-29 10:46:37 -0300714{
715 struct pl2303_private *priv = usb_get_serial_port_data(port);
716 unsigned long flags;
Alan Cox335f8512009-06-11 12:26:29 +0100717 u8 control;
718
719 spin_lock_irqsave(&priv->lock, flags);
720 /* Change DTR and RTS */
721 if (on)
722 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
723 else
724 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
725 control = priv->line_control;
726 spin_unlock_irqrestore(&priv->lock, flags);
727 set_control_lines(port->serial->dev, control);
728}
729
730static void pl2303_close(struct usb_serial_port *port)
731{
732 struct pl2303_private *priv = usb_get_serial_port_data(port);
733 unsigned long flags;
Thiago Galesi572d3132006-07-29 10:46:37 -0300734
Harvey Harrison441b62c2008-03-03 16:08:34 -0800735 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300736
Thiago Galesi572d3132006-07-29 10:46:37 -0300737 spin_lock_irqsave(&priv->lock, flags);
Thiago Galesi572d3132006-07-29 10:46:37 -0300738 /* clear out any remaining data in the buffer */
739 pl2303_buf_clear(priv->buf);
740 spin_unlock_irqrestore(&priv->lock, flags);
741
Thiago Galesi572d3132006-07-29 10:46:37 -0300742 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800743 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300744 usb_kill_urb(port->write_urb);
745 usb_kill_urb(port->read_urb);
746 usb_kill_urb(port->interrupt_in_urb);
747
Thiago Galesi572d3132006-07-29 10:46:37 -0300748}
749
Alan Coxa509a7e2009-09-19 13:13:26 -0700750static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Alan Cox606d0992006-12-08 02:38:45 -0800752 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 struct usb_serial *serial = port->serial;
754 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 int result;
756
Harvey Harrison441b62c2008-03-03 16:08:34 -0800757 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Dariusz M16948992005-07-28 18:06:13 +0200759 if (priv->type != HX) {
760 usb_clear_halt(serial->dev, port->write_urb->pipe);
761 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800762 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800764 pl2303_vendor_write(8, 0, serial);
765 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100769 if (tty)
770 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Harvey Harrison441b62c2008-03-03 16:08:34 -0800772 dbg("%s - submitting read urb", __func__);
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100773 result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 if (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
Johan Hovoldf08e07a2010-03-17 23:05:58 +01001038static void pl2303_process_read_urb(struct urb *urb)
Alan Coxd4fc4a72009-07-09 13:36:58 +01001039{
Johan Hovoldf08e07a2010-03-17 23:05:58 +01001040 struct usb_serial_port *port = urb->context;
1041 struct pl2303_private *priv = usb_get_serial_port_data(port);
1042 struct tty_struct *tty;
Alan Coxd4fc4a72009-07-09 13:36:58 +01001043 unsigned char *data = urb->transfer_buffer;
Alan Coxd4fc4a72009-07-09 13:36:58 +01001044 char tty_flag = TTY_NORMAL;
Johan Hovoldf08e07a2010-03-17 23:05:58 +01001045 unsigned long flags;
1046 u8 line_status;
1047 int i;
1048
1049 /* update line status */
1050 spin_lock_irqsave(&priv->lock, flags);
1051 line_status = priv->line_status;
1052 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1053 spin_unlock_irqrestore(&priv->lock, flags);
1054 wake_up_interruptible(&priv->delta_msr_wait);
1055
1056 if (!urb->actual_length)
1057 return;
1058
1059 tty = tty_port_tty_get(&port->port);
1060 if (!tty)
1061 return;
1062
Alan Coxd4fc4a72009-07-09 13:36:58 +01001063 /* break takes precedence over parity, */
1064 /* which takes precedence over framing errors */
1065 if (line_status & UART_BREAK_ERROR)
1066 tty_flag = TTY_BREAK;
1067 else if (line_status & UART_PARITY_ERROR)
1068 tty_flag = TTY_PARITY;
1069 else if (line_status & UART_FRAME_ERROR)
1070 tty_flag = TTY_FRAME;
1071 dbg("%s - tty_flag = %d", __func__, tty_flag);
1072
Alan Coxd4fc4a72009-07-09 13:36:58 +01001073 /* overrun is special, not associated with a char */
1074 if (line_status & UART_OVERRUN_ERROR)
1075 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Johan Hovold9388e2e2009-10-08 11:36:46 +02001076
Jason Wesselbd5afa92010-03-08 21:50:12 -06001077 if (tty_flag == TTY_NORMAL && !(port->port.console && port->sysrq))
Johan Hovold9388e2e2009-10-08 11:36:46 +02001078 tty_insert_flip_string(tty, data, urb->actual_length);
1079 else {
Alan Coxd4fc4a72009-07-09 13:36:58 +01001080 for (i = 0; i < urb->actual_length; ++i)
1081 if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
1082 tty_insert_flip_char(tty, data[i], tty_flag);
Johan Hovold9388e2e2009-10-08 11:36:46 +02001083 }
Johan Hovoldf08e07a2010-03-17 23:05:58 +01001084
Alan Coxd4fc4a72009-07-09 13:36:58 +01001085 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +01001086 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087}
1088
David Howells7d12e782006-10-05 14:55:46 +01001089static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090{
Ming Leicdc97792008-02-24 18:41:47 +08001091 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 struct pl2303_private *priv = usb_get_serial_port_data(port);
1093 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001094 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Harvey Harrison441b62c2008-03-03 16:08:34 -08001096 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001098 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 case 0:
1100 /* success */
1101 break;
1102 case -ECONNRESET:
1103 case -ENOENT:
1104 case -ESHUTDOWN:
1105 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001106 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001107 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 priv->write_urb_in_use = 0;
1109 return;
1110 default:
1111 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001112 dbg("%s - Overflow in write", __func__);
1113 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001114 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 port->write_urb->transfer_buffer_length = 1;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001116 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001118 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001119 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 else
1121 return;
1122 }
1123
1124 priv->write_urb_in_use = 0;
1125
1126 /* send any buffered data */
1127 pl2303_send(port);
1128}
1129
Thiago Galesi572d3132006-07-29 10:46:37 -03001130/* All of the device info needed for the PL2303 SIO serial converter */
1131static struct usb_serial_driver pl2303_device = {
1132 .driver = {
1133 .owner = THIS_MODULE,
1134 .name = "pl2303",
1135 },
1136 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001137 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001138 .num_ports = 1,
Johan Hovold7919c2f2010-03-17 23:00:41 +01001139 .bulk_in_size = 256,
Johan Hovold3efeaff2010-03-17 23:00:40 +01001140 .bulk_out_size = 256,
Thiago Galesi572d3132006-07-29 10:46:37 -03001141 .open = pl2303_open,
1142 .close = pl2303_close,
Alan Cox335f8512009-06-11 12:26:29 +01001143 .dtr_rts = pl2303_dtr_rts,
1144 .carrier_raised = pl2303_carrier_raised,
Thiago Galesi572d3132006-07-29 10:46:37 -03001145 .write = pl2303_write,
1146 .ioctl = pl2303_ioctl,
1147 .break_ctl = pl2303_break_ctl,
1148 .set_termios = pl2303_set_termios,
1149 .tiocmget = pl2303_tiocmget,
1150 .tiocmset = pl2303_tiocmset,
Johan Hovoldf08e07a2010-03-17 23:05:58 +01001151 .process_read_urb = pl2303_process_read_urb,
Thiago Galesi572d3132006-07-29 10:46:37 -03001152 .read_int_callback = pl2303_read_int_callback,
1153 .write_bulk_callback = pl2303_write_bulk_callback,
1154 .write_room = pl2303_write_room,
1155 .chars_in_buffer = pl2303_chars_in_buffer,
1156 .attach = pl2303_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -04001157 .release = pl2303_release,
Thiago Galesi572d3132006-07-29 10:46:37 -03001158};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Thiago Galesi372db8a2006-07-31 15:39:27 -03001160static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161{
1162 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 retval = usb_serial_register(&pl2303_device);
1165 if (retval)
1166 goto failed_usb_serial_register;
1167 retval = usb_register(&pl2303_driver);
1168 if (retval)
1169 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001170 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 return 0;
1172failed_usb_register:
1173 usb_serial_deregister(&pl2303_device);
1174failed_usb_serial_register:
1175 return retval;
1176}
1177
Thiago Galesi372db8a2006-07-31 15:39:27 -03001178static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001180 usb_deregister(&pl2303_driver);
1181 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182}
1183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184module_init(pl2303_init);
1185module_exit(pl2303_exit);
1186
1187MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188MODULE_LICENSE("GPL");
1189
1190module_param(debug, bool, S_IRUGO | S_IWUSR);
1191MODULE_PARM_DESC(debug, "Debug enabled or not");
1192