blob: b9f6d1a91f03432dbd3b067b9d59965596e7a0ab [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
Rusty Russell90ab5ee2012-01-13 09:32:20 +103039static bool debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41#define PL2303_CLOSING_WAIT (30*HZ)
42
Németh Márton7d40d7e2010-01-10 15:34:24 +010043static const struct usb_device_id id_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
45 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100046 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
48 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070049 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053050 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050051 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Simone Contini18344a12010-04-12 23:25:10 +020052 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
Dario Lombardo96a3e792011-01-21 15:35:19 +010053 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090055 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
57 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
58 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
59 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
60 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080061 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
63 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
64 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
65 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
66 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
67 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
68 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
69 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080070 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080072 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020073 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Alan Cox912299f2009-04-06 17:35:12 +010074 { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070075 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010076 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
77 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010078 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010079 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080080 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040081 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100082 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020083 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090084 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090085 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050086 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Matthew Arnold7c992002008-12-13 22:42:53 +110087 { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
Mike Provencheraf4b8512008-12-16 14:30:14 -060088 { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
Gianpaolo Cugola8540d662009-06-05 22:57:52 +020089 { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
Jef Driesenf36ecd52010-08-09 15:55:32 +020090 { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
Khanh-Dang Nguyen Thu Lam49276562009-07-28 19:41:17 +020091 { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
Pawel Ludwikow35904e62009-08-27 14:15:50 +020092 { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
Manuel Jander9a61d722010-03-29 23:51:57 +020093 { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
Eric Benoit598f0b72011-09-24 02:04:50 -040094 { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 { } /* Terminating entry */
96};
97
Thiago Galesi372db8a2006-07-31 15:39:27 -030098MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 .name = "pl2303",
102 .probe = usb_serial_probe,
103 .disconnect = usb_serial_disconnect,
104 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800105 .suspend = usb_serial_suspend,
106 .resume = usb_serial_resume,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800107 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110#define SET_LINE_REQUEST_TYPE 0x21
111#define SET_LINE_REQUEST 0x20
112
113#define SET_CONTROL_REQUEST_TYPE 0x21
114#define SET_CONTROL_REQUEST 0x22
115#define CONTROL_DTR 0x01
116#define CONTROL_RTS 0x02
117
118#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100119#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#define BREAK_ON 0xffff
121#define BREAK_OFF 0x0000
122
123#define GET_LINE_REQUEST_TYPE 0xa1
124#define GET_LINE_REQUEST 0x21
125
126#define VENDOR_WRITE_REQUEST_TYPE 0x40
127#define VENDOR_WRITE_REQUEST 0x01
128
129#define VENDOR_READ_REQUEST_TYPE 0xc0
130#define VENDOR_READ_REQUEST 0x01
131
132#define UART_STATE 0x08
133#define UART_STATE_TRANSIENT_MASK 0x74
134#define UART_DCD 0x01
135#define UART_DSR 0x02
136#define UART_BREAK_ERROR 0x04
137#define UART_RING 0x08
138#define UART_FRAME_ERROR 0x10
139#define UART_PARITY_ERROR 0x20
140#define UART_OVERRUN_ERROR 0x40
141#define UART_CTS 0x80
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144enum pl2303_type {
145 type_0, /* don't know the difference between type 0 and */
146 type_1, /* type 1, until someone from prolific tells us... */
147 HX, /* HX version of the pl2303 chip */
148};
149
150struct pl2303_private {
151 spinlock_t lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 u8 line_control;
153 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 enum pl2303_type type;
155};
156
Sarah Sharpeb44da02007-12-14 14:08:00 -0800157static int pl2303_vendor_read(__u16 value, __u16 index,
158 struct usb_serial *serial, unsigned char *buf)
159{
160 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
161 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
162 value, index, buf, 1, 100);
163 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
164 VENDOR_READ_REQUEST, value, index, res, buf[0]);
165 return res;
166}
167
168static int pl2303_vendor_write(__u16 value, __u16 index,
169 struct usb_serial *serial)
170{
171 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
172 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
173 value, index, NULL, 0, 100);
174 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
175 VENDOR_WRITE_REQUEST, value, index, res);
176 return res;
177}
178
Thiago Galesi372db8a2006-07-31 15:39:27 -0300179static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180{
181 struct pl2303_private *priv;
182 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800183 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 int i;
185
Sarah Sharp3e152502007-12-14 14:08:35 -0800186 buf = kmalloc(10, GFP_KERNEL);
187 if (buf == NULL)
188 return -ENOMEM;
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 if (serial->dev->descriptor.bDeviceClass == 0x02)
191 type = type_0;
192 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
193 type = HX;
194 else if (serial->dev->descriptor.bDeviceClass == 0x00)
195 type = type_1;
196 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
197 type = type_1;
198 dbg("device type: %d", type);
199
200 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100201 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 if (!priv)
203 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 spin_lock_init(&priv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 priv->type = type;
206 usb_set_serial_port_data(serial->port[i], priv);
207 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800208
209 pl2303_vendor_read(0x8484, 0, serial, buf);
210 pl2303_vendor_write(0x0404, 0, serial);
211 pl2303_vendor_read(0x8484, 0, serial, buf);
212 pl2303_vendor_read(0x8383, 0, serial, buf);
213 pl2303_vendor_read(0x8484, 0, serial, buf);
214 pl2303_vendor_write(0x0404, 1, serial);
215 pl2303_vendor_read(0x8484, 0, serial, buf);
216 pl2303_vendor_read(0x8383, 0, serial, buf);
217 pl2303_vendor_write(0, 1, serial);
218 pl2303_vendor_write(1, 0, serial);
219 if (type == HX)
220 pl2303_vendor_write(2, 0x44, serial);
221 else
222 pl2303_vendor_write(2, 0x24, serial);
223
224 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 return 0;
226
227cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800228 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100229 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 priv = usb_get_serial_port_data(serial->port[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 kfree(priv);
232 usb_set_serial_port_data(serial->port[i], NULL);
233 }
234 return -ENOMEM;
235}
236
Thiago Galesi372db8a2006-07-31 15:39:27 -0300237static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238{
239 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100240
Thiago Galesi372db8a2006-07-31 15:39:27 -0300241 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
242 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
243 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800244 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 return retval;
246}
247
Alan Cox95da3102008-07-22 11:09:07 +0100248static void pl2303_set_termios(struct tty_struct *tty,
249 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
251 struct usb_serial *serial = port->serial;
252 struct pl2303_private *priv = usb_get_serial_port_data(port);
253 unsigned long flags;
254 unsigned int cflag;
255 unsigned char *buf;
256 int baud;
257 int i;
258 u8 control;
Frank Schaefer25b82862009-08-18 20:15:07 +0200259 const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
260 4800, 7200, 9600, 14400, 19200, 28800, 38400,
261 57600, 115200, 230400, 460800, 614400,
262 921600, 1228800, 2457600, 3000000, 6000000 };
263 int baud_floor, baud_ceil;
264 int k;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Harvey Harrison441b62c2008-03-03 16:08:34 -0800266 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Alan Coxbf5e5832008-01-08 14:55:51 +0000268 /* The PL2303 is reported to lose bytes if you change
269 serial settings even to the same values as before. Thus
270 we actually need to filter in this specific case */
271
Johan Hovold8dc18302013-06-10 18:29:38 +0200272 if (old_termios && !tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000273 return;
274
Alan Cox95da3102008-07-22 11:09:07 +0100275 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Thiago Galesi372db8a2006-07-31 15:39:27 -0300277 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800279 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100280 /* Report back no change occurred */
Johan Hovold8dc18302013-06-10 18:29:38 +0200281 if (old_termios)
282 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 return;
284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Thiago Galesi372db8a2006-07-31 15:39:27 -0300286 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
287 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
288 0, 0, buf, 7, 100);
289 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
290 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Colin Leitnerdb2cbb52013-11-04 19:40:43 +0100292 switch (cflag & CSIZE) {
293 case CS5:
294 buf[6] = 5;
295 break;
296 case CS6:
297 buf[6] = 6;
298 break;
299 case CS7:
300 buf[6] = 7;
301 break;
302 default:
303 case CS8:
304 buf[6] = 8;
305 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
Colin Leitnerdb2cbb52013-11-04 19:40:43 +0100307 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Frank Schaefer25b82862009-08-18 20:15:07 +0200309 /* For reference buf[0]:buf[3] baud rate value */
310 /* NOTE: Only the values defined in baud_sup are supported !
311 * => if unsupported values are set, the PL2303 seems to use
312 * 9600 baud (at least my PL2303X always does)
313 */
Alan Cox95da3102008-07-22 11:09:07 +0100314 baud = tty_get_baud_rate(tty);
Frank Schaefer25b82862009-08-18 20:15:07 +0200315 dbg("%s - baud requested = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 if (baud) {
Frank Schaefer25b82862009-08-18 20:15:07 +0200317 /* Set baudrate to nearest supported value */
318 for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
319 if (baud_sup[k] / baud) {
320 baud_ceil = baud_sup[k];
321 if (k==0) {
322 baud = baud_ceil;
323 } else {
324 baud_floor = baud_sup[k-1];
325 if ((baud_ceil % baud)
326 > (baud % baud_floor))
327 baud = baud_floor;
328 else
329 baud = baud_ceil;
330 }
331 break;
332 }
333 }
334 if (baud > 1228800) {
335 /* type_0, type_1 only support up to 1228800 baud */
336 if (priv->type != HX)
337 baud = 1228800;
338 else if (baud > 6000000)
339 baud = 6000000;
340 }
341 dbg("%s - baud set = %d", __func__, baud);
Michał Sroczyński8d48fdf2011-07-05 21:53:35 +0200342 if (baud <= 115200) {
343 buf[0] = baud & 0xff;
344 buf[1] = (baud >> 8) & 0xff;
345 buf[2] = (baud >> 16) & 0xff;
346 buf[3] = (baud >> 24) & 0xff;
347 } else {
348 /* apparently the formula for higher speeds is:
349 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
350 */
351 unsigned tmp = 12*1000*1000*32 / baud;
352 buf[3] = 0x80;
353 buf[2] = 0;
354 buf[1] = (tmp >= 256);
355 while (tmp >= 256) {
356 tmp >>= 2;
357 buf[1] <<= 1;
358 }
Michał Sroczyński8d48fdf2011-07-05 21:53:35 +0200359 buf[0] = tmp;
360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 }
362
363 /* For reference buf[4]=0 is 1 stop bits */
364 /* For reference buf[4]=1 is 1.5 stop bits */
365 /* For reference buf[4]=2 is 2 stop bits */
366 if (cflag & CSTOPB) {
Frank Schaefer29cf1b72009-08-18 20:34:24 +0200367 /* NOTE: Comply with "real" UARTs / RS232:
368 * use 1.5 instead of 2 stop bits with 5 data bits
369 */
370 if ((cflag & CSIZE) == CS5) {
371 buf[4] = 1;
372 dbg("%s - stop bits = 1.5", __func__);
373 } else {
374 buf[4] = 2;
375 dbg("%s - stop bits = 2", __func__);
376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 } else {
378 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800379 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381
382 if (cflag & PARENB) {
383 /* For reference buf[5]=0 is none parity */
384 /* For reference buf[5]=1 is odd parity */
385 /* For reference buf[5]=2 is even parity */
386 /* For reference buf[5]=3 is mark parity */
387 /* For reference buf[5]=4 is space parity */
388 if (cflag & PARODD) {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200389 if (cflag & CMSPAR) {
390 buf[5] = 3;
391 dbg("%s - parity = mark", __func__);
392 } else {
393 buf[5] = 1;
394 dbg("%s - parity = odd", __func__);
395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 } else {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200397 if (cflag & CMSPAR) {
398 buf[5] = 4;
399 dbg("%s - parity = space", __func__);
400 } else {
401 buf[5] = 2;
402 dbg("%s - parity = even", __func__);
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405 } else {
406 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800407 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 }
409
Thiago Galesi372db8a2006-07-31 15:39:27 -0300410 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
411 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
412 0, 0, buf, 7, 100);
413 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 /* change control lines if we are switching to or from B0 */
416 spin_lock_irqsave(&priv->lock, flags);
417 control = priv->line_control;
418 if ((cflag & CBAUD) == B0)
419 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
Johan Hovold8dc18302013-06-10 18:29:38 +0200420 else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
422 if (control != priv->line_control) {
423 control = priv->line_control;
424 spin_unlock_irqrestore(&priv->lock, flags);
425 set_control_lines(serial->dev, control);
426 } else {
427 spin_unlock_irqrestore(&priv->lock, flags);
428 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
431
Thiago Galesi372db8a2006-07-31 15:39:27 -0300432 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
433 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
434 0, 0, buf, 7, 100);
435 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
437
438 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800440 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800442 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200443 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800444 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
446
Frank Schaefer25b82862009-08-18 20:15:07 +0200447 /* Save resulting baud rate */
Alan Coxdf64c472007-10-15 20:54:47 +0100448 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100449 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100450
Thiago Galesi372db8a2006-07-31 15:39:27 -0300451 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
Alan Cox335f8512009-06-11 12:26:29 +0100454static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
Thiago Galesi572d3132006-07-29 10:46:37 -0300455{
456 struct pl2303_private *priv = usb_get_serial_port_data(port);
457 unsigned long flags;
Alan Cox335f8512009-06-11 12:26:29 +0100458 u8 control;
459
460 spin_lock_irqsave(&priv->lock, flags);
461 /* Change DTR and RTS */
462 if (on)
463 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
464 else
465 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
466 control = priv->line_control;
467 spin_unlock_irqrestore(&priv->lock, flags);
468 set_control_lines(port->serial->dev, control);
469}
470
471static void pl2303_close(struct usb_serial_port *port)
472{
Harvey Harrison441b62c2008-03-03 16:08:34 -0800473 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300474
Johan Hovold8b0127b2010-03-17 23:06:04 +0100475 usb_serial_generic_close(port);
Thiago Galesi572d3132006-07-29 10:46:37 -0300476 usb_kill_urb(port->interrupt_in_urb);
Thiago Galesi572d3132006-07-29 10:46:37 -0300477}
478
Alan Coxa509a7e2009-09-19 13:13:26 -0700479static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 struct usb_serial *serial = port->serial;
482 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 int result;
484
Harvey Harrison441b62c2008-03-03 16:08:34 -0800485 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Dariusz M16948992005-07-28 18:06:13 +0200487 if (priv->type != HX) {
488 usb_clear_halt(serial->dev, port->write_urb->pipe);
489 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800490 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800492 pl2303_vendor_write(8, 0, serial);
493 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 }
495
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100497 if (tty)
Johan Hovold8dc18302013-06-10 18:29:38 +0200498 pl2303_set_termios(tty, port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Harvey Harrison441b62c2008-03-03 16:08:34 -0800500 dbg("%s - submitting interrupt urb", __func__);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300501 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300503 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800504 " error %d\n", __func__, result);
Johan Hovolddb6e9182011-11-06 19:06:34 +0100505 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
Johan Hovoldd4691c32011-11-06 19:06:35 +0100507
Johan Hovoldf5230a52011-11-06 19:06:36 +0100508 result = usb_serial_generic_open(tty, port);
Johan Hovoldd4691c32011-11-06 19:06:35 +0100509 if (result) {
510 usb_kill_urb(port->interrupt_in_urb);
511 return result;
512 }
513
Alan Cox335f8512009-06-11 12:26:29 +0100514 port->port.drain_delay = 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 return 0;
516}
517
Alan Cox20b9d172011-02-14 16:26:50 +0000518static int pl2303_tiocmset(struct tty_struct *tty,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300519 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
Alan Cox95da3102008-07-22 11:09:07 +0100521 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 struct pl2303_private *priv = usb_get_serial_port_data(port);
523 unsigned long flags;
524 u8 control;
525
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700526 if (!usb_get_intfdata(port->serial->interface))
527 return -ENODEV;
528
Thiago Galesi372db8a2006-07-31 15:39:27 -0300529 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if (set & TIOCM_RTS)
531 priv->line_control |= CONTROL_RTS;
532 if (set & TIOCM_DTR)
533 priv->line_control |= CONTROL_DTR;
534 if (clear & TIOCM_RTS)
535 priv->line_control &= ~CONTROL_RTS;
536 if (clear & TIOCM_DTR)
537 priv->line_control &= ~CONTROL_DTR;
538 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300539 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Thiago Galesi372db8a2006-07-31 15:39:27 -0300541 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542}
543
Alan Cox60b33c12011-02-14 16:26:14 +0000544static int pl2303_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545{
Alan Cox95da3102008-07-22 11:09:07 +0100546 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 struct pl2303_private *priv = usb_get_serial_port_data(port);
548 unsigned long flags;
549 unsigned int mcr;
550 unsigned int status;
551 unsigned int result;
552
Harvey Harrison441b62c2008-03-03 16:08:34 -0800553 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700555 if (!usb_get_intfdata(port->serial->interface))
556 return -ENODEV;
557
Thiago Galesi372db8a2006-07-31 15:39:27 -0300558 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 mcr = priv->line_control;
560 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300561 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
564 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
565 | ((status & UART_CTS) ? TIOCM_CTS : 0)
566 | ((status & UART_DSR) ? TIOCM_DSR : 0)
567 | ((status & UART_RING) ? TIOCM_RI : 0)
568 | ((status & UART_DCD) ? TIOCM_CD : 0);
569
Harvey Harrison441b62c2008-03-03 16:08:34 -0800570 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572 return result;
573}
574
Alan Cox335f8512009-06-11 12:26:29 +0100575static int pl2303_carrier_raised(struct usb_serial_port *port)
576{
577 struct pl2303_private *priv = usb_get_serial_port_data(port);
578 if (priv->line_status & UART_DCD)
579 return 1;
580 return 0;
581}
582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
584{
585 struct pl2303_private *priv = usb_get_serial_port_data(port);
586 unsigned long flags;
587 unsigned int prevstatus;
588 unsigned int status;
589 unsigned int changed;
590
Thiago Galesi372db8a2006-07-31 15:39:27 -0300591 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300593 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
595 while (1) {
Johan Hovoldefa1c862013-03-19 09:21:22 +0100596 interruptible_sleep_on(&port->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 /* see if a signal did it */
598 if (signal_pending(current))
599 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300600
Johan Hovoldefa1c862013-03-19 09:21:22 +0100601 if (port->serial->disconnected)
602 return -EIO;
603
Thiago Galesi372db8a2006-07-31 15:39:27 -0300604 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300606 spin_unlock_irqrestore(&priv->lock, flags);
607
Alan Cox3a0f43e2008-07-22 11:14:49 +0100608 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
611 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
612 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100613 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 return 0;
615 }
616 prevstatus = status;
617 }
618 /* NOTREACHED */
619 return 0;
620}
621
Alan Cox00a0d0d2011-02-14 16:27:06 +0000622static int pl2303_ioctl(struct tty_struct *tty,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300623 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
John Tsiombikas67b99462010-02-25 17:09:08 +0200625 struct serial_struct ser;
Alan Cox95da3102008-07-22 11:09:07 +0100626 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800627 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 switch (cmd) {
John Tsiombikas67b99462010-02-25 17:09:08 +0200630 case TIOCGSERIAL:
631 memset(&ser, 0, sizeof ser);
632 ser.type = PORT_16654;
633 ser.line = port->serial->minor;
634 ser.port = port->number;
635 ser.baud_base = 460800;
636
637 if (copy_to_user((void __user *)arg, &ser, sizeof ser))
638 return -EFAULT;
639
640 return 0;
641
Alan Cox3a0f43e2008-07-22 11:14:49 +0100642 case TIOCMIWAIT:
643 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
644 return wait_modem_info(port, arg);
645 default:
646 dbg("%s not supported = 0x%04x", __func__, cmd);
647 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 return -ENOIOCTLCMD;
650}
651
Alan Cox95da3102008-07-22 11:09:07 +0100652static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653{
Alan Cox95da3102008-07-22 11:09:07 +0100654 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 struct usb_serial *serial = port->serial;
656 u16 state;
657 int result;
658
Harvey Harrison441b62c2008-03-03 16:08:34 -0800659 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661 if (break_state == 0)
662 state = BREAK_OFF;
663 else
664 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100665 dbg("%s - turning break %s", __func__,
666 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Thiago Galesi372db8a2006-07-31 15:39:27 -0300668 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
669 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
670 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800672 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673}
674
Alan Sternf9c99bb2009-06-02 11:53:55 -0400675static void pl2303_release(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
677 int i;
678 struct pl2303_private *priv;
679
Harvey Harrison441b62c2008-03-03 16:08:34 -0800680 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 for (i = 0; i < serial->num_ports; ++i) {
683 priv = usb_get_serial_port_data(serial->port[i]);
Johan Hovold684c6e32010-03-17 23:06:03 +0100684 kfree(priv);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686}
687
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700688static void pl2303_update_line_status(struct usb_serial_port *port,
689 unsigned char *data,
690 unsigned int actual_length)
691{
692
693 struct pl2303_private *priv = usb_get_serial_port_data(port);
Libor Pechacekd14fc1a2011-01-14 14:30:21 +0100694 struct tty_struct *tty;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700695 unsigned long flags;
696 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200697 u8 length = UART_STATE + 1;
Libor Pechacekd14fc1a2011-01-14 14:30:21 +0100698 u8 prev_line_status;
Thiago Galesi9c537612006-07-29 10:47:12 -0300699 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700700
Thiago Galesi9c537612006-07-29 10:47:12 -0300701 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
702 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
703
704
705 if (idv == SIEMENS_VENDOR_ID) {
706 if (idp == SIEMENS_PRODUCT_ID_X65 ||
707 idp == SIEMENS_PRODUCT_ID_SX1 ||
708 idp == SIEMENS_PRODUCT_ID_X75) {
709
710 length = 1;
711 status_idx = 0;
712 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700713 }
714
715 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300716 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700717
Alan Cox3a0f43e2008-07-22 11:14:49 +0100718 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700719 spin_lock_irqsave(&priv->lock, flags);
Libor Pechacekd14fc1a2011-01-14 14:30:21 +0100720 prev_line_status = priv->line_status;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700721 priv->line_status = data[status_idx];
722 spin_unlock_irqrestore(&priv->lock, flags);
Jason Wessel430eb0d2009-05-29 13:34:16 -0500723 if (priv->line_status & UART_BREAK_ERROR)
724 usb_serial_handle_break(port);
Johan Hovoldefa1c862013-03-19 09:21:22 +0100725 wake_up_interruptible(&port->delta_msr_wait);
Libor Pechacekd14fc1a2011-01-14 14:30:21 +0100726
727 tty = tty_port_tty_get(&port->port);
728 if (!tty)
729 return;
730 if ((priv->line_status ^ prev_line_status) & UART_DCD)
731 usb_serial_handle_dcd_change(port, tty,
732 priv->line_status & UART_DCD);
733 tty_kref_put(tty);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700734}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
David Howells7d12e782006-10-05 14:55:46 +0100736static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Ming Leicdc97792008-02-24 18:41:47 +0800738 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700740 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700741 int status = urb->status;
742 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Harvey Harrison441b62c2008-03-03 16:08:34 -0800744 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700746 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 case 0:
748 /* success */
749 break;
750 case -ECONNRESET:
751 case -ENOENT:
752 case -ESHUTDOWN:
753 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800754 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700755 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 return;
757 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800758 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700759 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 goto exit;
761 }
762
Harvey Harrison441b62c2008-03-03 16:08:34 -0800763 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300764 urb->actual_length, urb->transfer_buffer);
765
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700766 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700769 retval = usb_submit_urb(urb, GFP_ATOMIC);
770 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -0300771 dev_err(&urb->dev->dev,
772 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800773 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774}
775
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100776static void pl2303_process_read_urb(struct urb *urb)
Alan Coxd4fc4a72009-07-09 13:36:58 +0100777{
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100778 struct usb_serial_port *port = urb->context;
779 struct pl2303_private *priv = usb_get_serial_port_data(port);
780 struct tty_struct *tty;
Alan Coxd4fc4a72009-07-09 13:36:58 +0100781 unsigned char *data = urb->transfer_buffer;
Alan Coxd4fc4a72009-07-09 13:36:58 +0100782 char tty_flag = TTY_NORMAL;
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100783 unsigned long flags;
784 u8 line_status;
785 int i;
786
787 /* update line status */
788 spin_lock_irqsave(&priv->lock, flags);
789 line_status = priv->line_status;
790 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
791 spin_unlock_irqrestore(&priv->lock, flags);
Johan Hovoldefa1c862013-03-19 09:21:22 +0100792 wake_up_interruptible(&port->delta_msr_wait);
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100793
794 if (!urb->actual_length)
795 return;
796
797 tty = tty_port_tty_get(&port->port);
798 if (!tty)
799 return;
800
Alan Coxd4fc4a72009-07-09 13:36:58 +0100801 /* break takes precedence over parity, */
802 /* which takes precedence over framing errors */
803 if (line_status & UART_BREAK_ERROR)
804 tty_flag = TTY_BREAK;
805 else if (line_status & UART_PARITY_ERROR)
806 tty_flag = TTY_PARITY;
807 else if (line_status & UART_FRAME_ERROR)
808 tty_flag = TTY_FRAME;
809 dbg("%s - tty_flag = %d", __func__, tty_flag);
810
Alan Coxd4fc4a72009-07-09 13:36:58 +0100811 /* overrun is special, not associated with a char */
812 if (line_status & UART_OVERRUN_ERROR)
813 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Johan Hovold9388e2e2009-10-08 11:36:46 +0200814
Johan Hovoldd45cc8d2010-05-08 15:18:41 +0200815 if (port->port.console && port->sysrq) {
Alan Coxd4fc4a72009-07-09 13:36:58 +0100816 for (i = 0; i < urb->actual_length; ++i)
Dmitry Torokhov6ee9f4b2010-08-17 21:15:47 -0700817 if (!usb_serial_handle_sysrq_char(port, data[i]))
Alan Coxd4fc4a72009-07-09 13:36:58 +0100818 tty_insert_flip_char(tty, data[i], tty_flag);
Johan Hovoldd45cc8d2010-05-08 15:18:41 +0200819 } else {
820 tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
821 urb->actual_length);
Johan Hovold9388e2e2009-10-08 11:36:46 +0200822 }
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100823
Alan Coxd4fc4a72009-07-09 13:36:58 +0100824 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100825 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826}
827
Thiago Galesi572d3132006-07-29 10:46:37 -0300828/* All of the device info needed for the PL2303 SIO serial converter */
829static struct usb_serial_driver pl2303_device = {
830 .driver = {
831 .owner = THIS_MODULE,
832 .name = "pl2303",
833 },
834 .id_table = id_table,
Thiago Galesi572d3132006-07-29 10:46:37 -0300835 .num_ports = 1,
Johan Hovold7919c2f2010-03-17 23:00:41 +0100836 .bulk_in_size = 256,
Johan Hovold3efeaff2010-03-17 23:00:40 +0100837 .bulk_out_size = 256,
Thiago Galesi572d3132006-07-29 10:46:37 -0300838 .open = pl2303_open,
839 .close = pl2303_close,
Alan Cox335f8512009-06-11 12:26:29 +0100840 .dtr_rts = pl2303_dtr_rts,
841 .carrier_raised = pl2303_carrier_raised,
Thiago Galesi572d3132006-07-29 10:46:37 -0300842 .ioctl = pl2303_ioctl,
843 .break_ctl = pl2303_break_ctl,
844 .set_termios = pl2303_set_termios,
845 .tiocmget = pl2303_tiocmget,
846 .tiocmset = pl2303_tiocmset,
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100847 .process_read_urb = pl2303_process_read_urb,
Thiago Galesi572d3132006-07-29 10:46:37 -0300848 .read_int_callback = pl2303_read_int_callback,
Thiago Galesi572d3132006-07-29 10:46:37 -0300849 .attach = pl2303_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -0400850 .release = pl2303_release,
Thiago Galesi572d3132006-07-29 10:46:37 -0300851};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Alan Sternf667dda2012-02-23 14:57:18 -0500853static struct usb_serial_driver * const serial_drivers[] = {
854 &pl2303_device, NULL
855};
856
Greg KHd1cddb42012-02-24 15:38:14 -0800857module_usb_serial_driver(pl2303_driver, serial_drivers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
859MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860MODULE_LICENSE("GPL");
861
862module_param(debug, bool, S_IRUGO | S_IWUSR);
863MODULE_PARM_DESC(debug, "Debug enabled or not");
864