blob: 13b8dd6481f565bd421a0a504b15d449ecbc3d72 [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
Németh Márton7d40d7e2010-01-10 15:34:24 +010041static const struct usb_device_id id_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
43 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100044 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
46 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070047 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053048 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050049 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Simone Contini18344a12010-04-12 23:25:10 +020050 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
Dario Lombardo96a3e792011-01-21 15:35:19 +010051 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090053 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
55 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
56 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
57 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
58 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080059 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
61 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
62 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
63 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
64 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
65 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
66 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
67 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080068 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080070 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020071 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Alan Cox912299f2009-04-06 17:35:12 +010072 { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070073 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010074 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
75 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010076 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010077 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080078 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040079 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100080 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020081 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090082 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090083 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050084 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Matthew Arnold7c992002008-12-13 22:42:53 +110085 { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
Mike Provencheraf4b8512008-12-16 14:30:14 -060086 { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
Gianpaolo Cugola8540d662009-06-05 22:57:52 +020087 { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
Jef Driesenf36ecd52010-08-09 15:55:32 +020088 { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
Khanh-Dang Nguyen Thu Lam49276562009-07-28 19:41:17 +020089 { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
Pawel Ludwikow35904e62009-08-27 14:15:50 +020090 { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
Manuel Jander9a61d722010-03-29 23:51:57 +020091 { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
Eric Benoit598f0b72011-09-24 02:04:50 -040092 { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 { } /* Terminating entry */
94};
95
Thiago Galesi372db8a2006-07-31 15:39:27 -030096MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Linus Torvalds1da177e2005-04-16 15:20:36 -070098#define SET_LINE_REQUEST_TYPE 0x21
99#define SET_LINE_REQUEST 0x20
100
101#define SET_CONTROL_REQUEST_TYPE 0x21
102#define SET_CONTROL_REQUEST 0x22
103#define CONTROL_DTR 0x01
104#define CONTROL_RTS 0x02
105
106#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100107#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108#define BREAK_ON 0xffff
109#define BREAK_OFF 0x0000
110
111#define GET_LINE_REQUEST_TYPE 0xa1
112#define GET_LINE_REQUEST 0x21
113
114#define VENDOR_WRITE_REQUEST_TYPE 0x40
115#define VENDOR_WRITE_REQUEST 0x01
116
117#define VENDOR_READ_REQUEST_TYPE 0xc0
118#define VENDOR_READ_REQUEST 0x01
119
120#define UART_STATE 0x08
121#define UART_STATE_TRANSIENT_MASK 0x74
122#define UART_DCD 0x01
123#define UART_DSR 0x02
124#define UART_BREAK_ERROR 0x04
125#define UART_RING 0x08
126#define UART_FRAME_ERROR 0x10
127#define UART_PARITY_ERROR 0x20
128#define UART_OVERRUN_ERROR 0x40
129#define UART_CTS 0x80
130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132enum pl2303_type {
133 type_0, /* don't know the difference between type 0 and */
134 type_1, /* type 1, until someone from prolific tells us... */
135 HX, /* HX version of the pl2303 chip */
136};
137
138struct pl2303_private {
139 spinlock_t lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 wait_queue_head_t delta_msr_wait;
141 u8 line_control;
142 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 enum pl2303_type type;
144};
145
Sarah Sharpeb44da02007-12-14 14:08:00 -0800146static int pl2303_vendor_read(__u16 value, __u16 index,
147 struct usb_serial *serial, unsigned char *buf)
148{
149 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
150 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
151 value, index, buf, 1, 100);
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700152 dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n",
153 VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
154 res, buf[0]);
Sarah Sharpeb44da02007-12-14 14:08:00 -0800155 return res;
156}
157
158static int pl2303_vendor_write(__u16 value, __u16 index,
159 struct usb_serial *serial)
160{
161 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
162 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
163 value, index, NULL, 0, 100);
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700164 dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n",
165 VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
166 res);
Sarah Sharpeb44da02007-12-14 14:08:00 -0800167 return res;
168}
169
Thiago Galesi372db8a2006-07-31 15:39:27 -0300170static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
172 struct pl2303_private *priv;
173 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800174 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 int i;
176
Sarah Sharp3e152502007-12-14 14:08:35 -0800177 buf = kmalloc(10, GFP_KERNEL);
178 if (buf == NULL)
179 return -ENOMEM;
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 if (serial->dev->descriptor.bDeviceClass == 0x02)
182 type = type_0;
183 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
184 type = HX;
185 else if (serial->dev->descriptor.bDeviceClass == 0x00)
186 type = type_1;
187 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
188 type = type_1;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700189 dev_dbg(&serial->interface->dev, "device type: %d\n", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100192 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 if (!priv)
194 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 spin_lock_init(&priv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 init_waitqueue_head(&priv->delta_msr_wait);
197 priv->type = type;
198 usb_set_serial_port_data(serial->port[i], priv);
199 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800200
201 pl2303_vendor_read(0x8484, 0, serial, buf);
202 pl2303_vendor_write(0x0404, 0, serial);
203 pl2303_vendor_read(0x8484, 0, serial, buf);
204 pl2303_vendor_read(0x8383, 0, serial, buf);
205 pl2303_vendor_read(0x8484, 0, serial, buf);
206 pl2303_vendor_write(0x0404, 1, serial);
207 pl2303_vendor_read(0x8484, 0, serial, buf);
208 pl2303_vendor_read(0x8383, 0, serial, buf);
209 pl2303_vendor_write(0, 1, serial);
210 pl2303_vendor_write(1, 0, serial);
211 if (type == HX)
212 pl2303_vendor_write(2, 0x44, serial);
213 else
214 pl2303_vendor_write(2, 0x24, serial);
215
216 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return 0;
218
219cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800220 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100221 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 priv = usb_get_serial_port_data(serial->port[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 kfree(priv);
224 usb_set_serial_port_data(serial->port[i], NULL);
225 }
226 return -ENOMEM;
227}
228
Thiago Galesi372db8a2006-07-31 15:39:27 -0300229static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
231 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100232
Thiago Galesi372db8a2006-07-31 15:39:27 -0300233 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
234 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
235 value, 0, NULL, 0, 100);
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700236 dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
237 value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 return retval;
239}
240
Alan Cox95da3102008-07-22 11:09:07 +0100241static void pl2303_set_termios(struct tty_struct *tty,
242 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
244 struct usb_serial *serial = port->serial;
245 struct pl2303_private *priv = usb_get_serial_port_data(port);
246 unsigned long flags;
247 unsigned int cflag;
248 unsigned char *buf;
249 int baud;
250 int i;
251 u8 control;
Frank Schaefer25b82862009-08-18 20:15:07 +0200252 const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
253 4800, 7200, 9600, 14400, 19200, 28800, 38400,
254 57600, 115200, 230400, 460800, 614400,
255 921600, 1228800, 2457600, 3000000, 6000000 };
256 int baud_floor, baud_ceil;
257 int k;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Alan Coxbf5e5832008-01-08 14:55:51 +0000259 /* The PL2303 is reported to lose bytes if you change
260 serial settings even to the same values as before. Thus
261 we actually need to filter in this specific case */
262
Alan Cox95da3102008-07-22 11:09:07 +0100263 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000264 return;
265
Alan Cox95da3102008-07-22 11:09:07 +0100266 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Thiago Galesi372db8a2006-07-31 15:39:27 -0300268 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800270 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100271 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100272 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return;
274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Thiago Galesi372db8a2006-07-31 15:39:27 -0300276 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
277 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
278 0, 0, buf, 7, 100);
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700279 dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300280 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282 if (cflag & CSIZE) {
283 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100284 case CS5:
285 buf[6] = 5;
286 break;
287 case CS6:
288 buf[6] = 6;
289 break;
290 case CS7:
291 buf[6] = 7;
292 break;
293 default:
294 case CS8:
295 buf[6] = 8;
296 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700298 dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300
Frank Schaefer25b82862009-08-18 20:15:07 +0200301 /* For reference buf[0]:buf[3] baud rate value */
302 /* NOTE: Only the values defined in baud_sup are supported !
303 * => if unsupported values are set, the PL2303 seems to use
304 * 9600 baud (at least my PL2303X always does)
305 */
Alan Cox95da3102008-07-22 11:09:07 +0100306 baud = tty_get_baud_rate(tty);
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700307 dev_dbg(&port->dev, "baud requested = %d\n", baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (baud) {
Frank Schaefer25b82862009-08-18 20:15:07 +0200309 /* Set baudrate to nearest supported value */
310 for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
311 if (baud_sup[k] / baud) {
312 baud_ceil = baud_sup[k];
313 if (k==0) {
314 baud = baud_ceil;
315 } else {
316 baud_floor = baud_sup[k-1];
317 if ((baud_ceil % baud)
318 > (baud % baud_floor))
319 baud = baud_floor;
320 else
321 baud = baud_ceil;
322 }
323 break;
324 }
325 }
326 if (baud > 1228800) {
327 /* type_0, type_1 only support up to 1228800 baud */
328 if (priv->type != HX)
329 baud = 1228800;
330 else if (baud > 6000000)
331 baud = 6000000;
332 }
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700333 dev_dbg(&port->dev, "baud set = %d\n", baud);
Michał Sroczyński8d48fdf2011-07-05 21:53:35 +0200334 if (baud <= 115200) {
335 buf[0] = baud & 0xff;
336 buf[1] = (baud >> 8) & 0xff;
337 buf[2] = (baud >> 16) & 0xff;
338 buf[3] = (baud >> 24) & 0xff;
339 } else {
340 /* apparently the formula for higher speeds is:
341 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
342 */
343 unsigned tmp = 12*1000*1000*32 / baud;
344 buf[3] = 0x80;
345 buf[2] = 0;
346 buf[1] = (tmp >= 256);
347 while (tmp >= 256) {
348 tmp >>= 2;
349 buf[1] <<= 1;
350 }
Michał Sroczyński8d48fdf2011-07-05 21:53:35 +0200351 buf[0] = tmp;
352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 }
354
355 /* For reference buf[4]=0 is 1 stop bits */
356 /* For reference buf[4]=1 is 1.5 stop bits */
357 /* For reference buf[4]=2 is 2 stop bits */
358 if (cflag & CSTOPB) {
Frank Schaefer29cf1b72009-08-18 20:34:24 +0200359 /* NOTE: Comply with "real" UARTs / RS232:
360 * use 1.5 instead of 2 stop bits with 5 data bits
361 */
362 if ((cflag & CSIZE) == CS5) {
363 buf[4] = 1;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700364 dev_dbg(&port->dev, "stop bits = 1.5\n");
Frank Schaefer29cf1b72009-08-18 20:34:24 +0200365 } else {
366 buf[4] = 2;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700367 dev_dbg(&port->dev, "stop bits = 2\n");
Frank Schaefer29cf1b72009-08-18 20:34:24 +0200368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 } else {
370 buf[4] = 0;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700371 dev_dbg(&port->dev, "stop bits = 1\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 }
373
374 if (cflag & PARENB) {
375 /* For reference buf[5]=0 is none parity */
376 /* For reference buf[5]=1 is odd parity */
377 /* For reference buf[5]=2 is even parity */
378 /* For reference buf[5]=3 is mark parity */
379 /* For reference buf[5]=4 is space parity */
380 if (cflag & PARODD) {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200381 if (cflag & CMSPAR) {
382 buf[5] = 3;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700383 dev_dbg(&port->dev, "parity = mark\n");
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200384 } else {
385 buf[5] = 1;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700386 dev_dbg(&port->dev, "parity = odd\n");
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 } else {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200389 if (cflag & CMSPAR) {
390 buf[5] = 4;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700391 dev_dbg(&port->dev, "parity = space\n");
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200392 } else {
393 buf[5] = 2;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700394 dev_dbg(&port->dev, "parity = even\n");
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 }
397 } else {
398 buf[5] = 0;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700399 dev_dbg(&port->dev, "parity = none\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401
Thiago Galesi372db8a2006-07-31 15:39:27 -0300402 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
403 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
404 0, 0, buf, 7, 100);
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700405 dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407 /* change control lines if we are switching to or from B0 */
408 spin_lock_irqsave(&priv->lock, flags);
409 control = priv->line_control;
410 if ((cflag & CBAUD) == B0)
411 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
Johan Hovoldce5c9852012-03-23 15:23:18 +0100412 else if ((old_termios->c_cflag & CBAUD) == B0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
414 if (control != priv->line_control) {
415 control = priv->line_control;
416 spin_unlock_irqrestore(&priv->lock, flags);
417 set_control_lines(serial->dev, control);
418 } else {
419 spin_unlock_irqrestore(&priv->lock, flags);
420 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
423
Thiago Galesi372db8a2006-07-31 15:39:27 -0300424 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
425 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
426 0, 0, buf, 7, 100);
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700427 dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
429
430 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800432 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800434 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200435 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800436 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
438
Frank Schaefer25b82862009-08-18 20:15:07 +0200439 /* Save resulting baud rate */
Alan Coxdf64c472007-10-15 20:54:47 +0100440 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100441 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100442
Thiago Galesi372db8a2006-07-31 15:39:27 -0300443 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444}
445
Alan Cox335f8512009-06-11 12:26:29 +0100446static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
Thiago Galesi572d3132006-07-29 10:46:37 -0300447{
448 struct pl2303_private *priv = usb_get_serial_port_data(port);
449 unsigned long flags;
Alan Cox335f8512009-06-11 12:26:29 +0100450 u8 control;
451
452 spin_lock_irqsave(&priv->lock, flags);
453 /* Change DTR and RTS */
454 if (on)
455 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
456 else
457 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
458 control = priv->line_control;
459 spin_unlock_irqrestore(&priv->lock, flags);
460 set_control_lines(port->serial->dev, control);
461}
462
463static void pl2303_close(struct usb_serial_port *port)
464{
Johan Hovold8b0127b2010-03-17 23:06:04 +0100465 usb_serial_generic_close(port);
Thiago Galesi572d3132006-07-29 10:46:37 -0300466 usb_kill_urb(port->interrupt_in_urb);
Thiago Galesi572d3132006-07-29 10:46:37 -0300467}
468
Alan Coxa509a7e2009-09-19 13:13:26 -0700469static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
Alan Cox606d0992006-12-08 02:38:45 -0800471 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 struct usb_serial *serial = port->serial;
473 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 int result;
475
Dariusz M16948992005-07-28 18:06:13 +0200476 if (priv->type != HX) {
477 usb_clear_halt(serial->dev, port->write_urb->pipe);
478 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800479 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800481 pl2303_vendor_write(8, 0, serial);
482 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100486 if (tty)
487 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Thiago Galesi372db8a2006-07-31 15:39:27 -0300489 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300491 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800492 " error %d\n", __func__, result);
Johan Hovolddb6e9182011-11-06 19:06:34 +0100493 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 }
Johan Hovoldd4691c32011-11-06 19:06:35 +0100495
Johan Hovoldf5230a52011-11-06 19:06:36 +0100496 result = usb_serial_generic_open(tty, port);
Johan Hovoldd4691c32011-11-06 19:06:35 +0100497 if (result) {
498 usb_kill_urb(port->interrupt_in_urb);
499 return result;
500 }
501
Alan Cox335f8512009-06-11 12:26:29 +0100502 port->port.drain_delay = 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 return 0;
504}
505
Alan Cox20b9d172011-02-14 16:26:50 +0000506static int pl2303_tiocmset(struct tty_struct *tty,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300507 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
Alan Cox95da3102008-07-22 11:09:07 +0100509 struct usb_serial_port *port = tty->driver_data;
Johan Hovold6f1efd62012-04-25 15:56:31 +0200510 struct usb_serial *serial = port->serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 struct pl2303_private *priv = usb_get_serial_port_data(port);
512 unsigned long flags;
513 u8 control;
Johan Hovold6f1efd62012-04-25 15:56:31 +0200514 int ret;
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700515
Thiago Galesi372db8a2006-07-31 15:39:27 -0300516 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 if (set & TIOCM_RTS)
518 priv->line_control |= CONTROL_RTS;
519 if (set & TIOCM_DTR)
520 priv->line_control |= CONTROL_DTR;
521 if (clear & TIOCM_RTS)
522 priv->line_control &= ~CONTROL_RTS;
523 if (clear & TIOCM_DTR)
524 priv->line_control &= ~CONTROL_DTR;
525 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300526 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Johan Hovold6f1efd62012-04-25 15:56:31 +0200528 mutex_lock(&serial->disc_mutex);
529 if (!serial->disconnected)
530 ret = set_control_lines(serial->dev, control);
531 else
532 ret = -ENODEV;
533 mutex_unlock(&serial->disc_mutex);
534
535 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536}
537
Alan Cox60b33c12011-02-14 16:26:14 +0000538static int pl2303_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
Alan Cox95da3102008-07-22 11:09:07 +0100540 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 struct pl2303_private *priv = usb_get_serial_port_data(port);
542 unsigned long flags;
543 unsigned int mcr;
544 unsigned int status;
545 unsigned int result;
546
Thiago Galesi372db8a2006-07-31 15:39:27 -0300547 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 mcr = priv->line_control;
549 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300550 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
553 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
554 | ((status & UART_CTS) ? TIOCM_CTS : 0)
555 | ((status & UART_DSR) ? TIOCM_DSR : 0)
556 | ((status & UART_RING) ? TIOCM_RI : 0)
557 | ((status & UART_DCD) ? TIOCM_CD : 0);
558
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700559 dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
561 return result;
562}
563
Alan Cox335f8512009-06-11 12:26:29 +0100564static int pl2303_carrier_raised(struct usb_serial_port *port)
565{
566 struct pl2303_private *priv = usb_get_serial_port_data(port);
567 if (priv->line_status & UART_DCD)
568 return 1;
569 return 0;
570}
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
573{
574 struct pl2303_private *priv = usb_get_serial_port_data(port);
575 unsigned long flags;
576 unsigned int prevstatus;
577 unsigned int status;
578 unsigned int changed;
579
Thiago Galesi372db8a2006-07-31 15:39:27 -0300580 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300582 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
584 while (1) {
585 interruptible_sleep_on(&priv->delta_msr_wait);
586 /* see if a signal did it */
587 if (signal_pending(current))
588 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300589
590 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300592 spin_unlock_irqrestore(&priv->lock, flags);
593
Alan Cox3a0f43e2008-07-22 11:14:49 +0100594 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300595
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
597 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
598 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100599 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 return 0;
601 }
602 prevstatus = status;
603 }
604 /* NOTREACHED */
605 return 0;
606}
607
Alan Cox00a0d0d2011-02-14 16:27:06 +0000608static int pl2303_ioctl(struct tty_struct *tty,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300609 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
John Tsiombikas67b99462010-02-25 17:09:08 +0200611 struct serial_struct ser;
Alan Cox95da3102008-07-22 11:09:07 +0100612 struct usb_serial_port *port = tty->driver_data;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700613
614 dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 switch (cmd) {
John Tsiombikas67b99462010-02-25 17:09:08 +0200617 case TIOCGSERIAL:
618 memset(&ser, 0, sizeof ser);
619 ser.type = PORT_16654;
620 ser.line = port->serial->minor;
621 ser.port = port->number;
622 ser.baud_base = 460800;
623
624 if (copy_to_user((void __user *)arg, &ser, sizeof ser))
625 return -EFAULT;
626
627 return 0;
628
Alan Cox3a0f43e2008-07-22 11:14:49 +0100629 case TIOCMIWAIT:
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700630 dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100631 return wait_modem_info(port, arg);
632 default:
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700633 dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100634 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return -ENOIOCTLCMD;
637}
638
Alan Cox95da3102008-07-22 11:09:07 +0100639static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
Alan Cox95da3102008-07-22 11:09:07 +0100641 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 struct usb_serial *serial = port->serial;
643 u16 state;
644 int result;
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 if (break_state == 0)
647 state = BREAK_OFF;
648 else
649 state = BREAK_ON;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700650 dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
Alan Cox3a0f43e2008-07-22 11:14:49 +0100651 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Thiago Galesi372db8a2006-07-31 15:39:27 -0300653 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
654 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
655 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 if (result)
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700657 dev_err(&port->dev, "error sending break = %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
659
Alan Sternf9c99bb2009-06-02 11:53:55 -0400660static void pl2303_release(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661{
662 int i;
663 struct pl2303_private *priv;
664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 for (i = 0; i < serial->num_ports; ++i) {
666 priv = usb_get_serial_port_data(serial->port[i]);
Johan Hovold684c6e32010-03-17 23:06:03 +0100667 kfree(priv);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700671static void pl2303_update_line_status(struct usb_serial_port *port,
672 unsigned char *data,
673 unsigned int actual_length)
674{
675
676 struct pl2303_private *priv = usb_get_serial_port_data(port);
Libor Pechacekd14fc1a2011-01-14 14:30:21 +0100677 struct tty_struct *tty;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700678 unsigned long flags;
679 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200680 u8 length = UART_STATE + 1;
Libor Pechacekd14fc1a2011-01-14 14:30:21 +0100681 u8 prev_line_status;
Thiago Galesi9c537612006-07-29 10:47:12 -0300682 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700683
Thiago Galesi9c537612006-07-29 10:47:12 -0300684 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
685 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
686
687
688 if (idv == SIEMENS_VENDOR_ID) {
689 if (idp == SIEMENS_PRODUCT_ID_X65 ||
690 idp == SIEMENS_PRODUCT_ID_SX1 ||
691 idp == SIEMENS_PRODUCT_ID_X75) {
692
693 length = 1;
694 status_idx = 0;
695 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700696 }
697
698 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300699 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700700
Alan Cox3a0f43e2008-07-22 11:14:49 +0100701 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700702 spin_lock_irqsave(&priv->lock, flags);
Libor Pechacekd14fc1a2011-01-14 14:30:21 +0100703 prev_line_status = priv->line_status;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700704 priv->line_status = data[status_idx];
705 spin_unlock_irqrestore(&priv->lock, flags);
Jason Wessel430eb0d2009-05-29 13:34:16 -0500706 if (priv->line_status & UART_BREAK_ERROR)
707 usb_serial_handle_break(port);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300708 wake_up_interruptible(&priv->delta_msr_wait);
Libor Pechacekd14fc1a2011-01-14 14:30:21 +0100709
710 tty = tty_port_tty_get(&port->port);
711 if (!tty)
712 return;
713 if ((priv->line_status ^ prev_line_status) & UART_DCD)
714 usb_serial_handle_dcd_change(port, tty,
715 priv->line_status & UART_DCD);
716 tty_kref_put(tty);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700717}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
David Howells7d12e782006-10-05 14:55:46 +0100719static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
Ming Leicdc97792008-02-24 18:41:47 +0800721 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700723 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700724 int status = urb->status;
725 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700727 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 case 0:
729 /* success */
730 break;
731 case -ECONNRESET:
732 case -ENOENT:
733 case -ESHUTDOWN:
734 /* this urb is terminated, clean up */
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700735 dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
736 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return;
738 default:
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700739 dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
740 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 goto exit;
742 }
743
Harvey Harrison441b62c2008-03-03 16:08:34 -0800744 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300745 urb->actual_length, urb->transfer_buffer);
746
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700747 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -0700750 retval = usb_submit_urb(urb, GFP_ATOMIC);
751 if (retval)
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700752 dev_err(&port->dev,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300753 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800754 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755}
756
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100757static void pl2303_process_read_urb(struct urb *urb)
Alan Coxd4fc4a72009-07-09 13:36:58 +0100758{
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100759 struct usb_serial_port *port = urb->context;
760 struct pl2303_private *priv = usb_get_serial_port_data(port);
761 struct tty_struct *tty;
Alan Coxd4fc4a72009-07-09 13:36:58 +0100762 unsigned char *data = urb->transfer_buffer;
Alan Coxd4fc4a72009-07-09 13:36:58 +0100763 char tty_flag = TTY_NORMAL;
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100764 unsigned long flags;
765 u8 line_status;
766 int i;
767
768 /* update line status */
769 spin_lock_irqsave(&priv->lock, flags);
770 line_status = priv->line_status;
771 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
772 spin_unlock_irqrestore(&priv->lock, flags);
773 wake_up_interruptible(&priv->delta_msr_wait);
774
775 if (!urb->actual_length)
776 return;
777
778 tty = tty_port_tty_get(&port->port);
779 if (!tty)
780 return;
781
Alan Coxd4fc4a72009-07-09 13:36:58 +0100782 /* break takes precedence over parity, */
783 /* which takes precedence over framing errors */
784 if (line_status & UART_BREAK_ERROR)
785 tty_flag = TTY_BREAK;
786 else if (line_status & UART_PARITY_ERROR)
787 tty_flag = TTY_PARITY;
788 else if (line_status & UART_FRAME_ERROR)
789 tty_flag = TTY_FRAME;
Greg Kroah-Hartmand8789b22012-05-03 16:39:27 -0700790 dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
Alan Coxd4fc4a72009-07-09 13:36:58 +0100791
Alan Coxd4fc4a72009-07-09 13:36:58 +0100792 /* overrun is special, not associated with a char */
793 if (line_status & UART_OVERRUN_ERROR)
794 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Johan Hovold9388e2e2009-10-08 11:36:46 +0200795
Johan Hovoldd45cc8d2010-05-08 15:18:41 +0200796 if (port->port.console && port->sysrq) {
Alan Coxd4fc4a72009-07-09 13:36:58 +0100797 for (i = 0; i < urb->actual_length; ++i)
Dmitry Torokhov6ee9f4b2010-08-17 21:15:47 -0700798 if (!usb_serial_handle_sysrq_char(port, data[i]))
Alan Coxd4fc4a72009-07-09 13:36:58 +0100799 tty_insert_flip_char(tty, data[i], tty_flag);
Johan Hovoldd45cc8d2010-05-08 15:18:41 +0200800 } else {
801 tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
802 urb->actual_length);
Johan Hovold9388e2e2009-10-08 11:36:46 +0200803 }
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100804
Alan Coxd4fc4a72009-07-09 13:36:58 +0100805 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100806 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807}
808
Thiago Galesi572d3132006-07-29 10:46:37 -0300809/* All of the device info needed for the PL2303 SIO serial converter */
810static struct usb_serial_driver pl2303_device = {
811 .driver = {
812 .owner = THIS_MODULE,
813 .name = "pl2303",
814 },
815 .id_table = id_table,
Thiago Galesi572d3132006-07-29 10:46:37 -0300816 .num_ports = 1,
Johan Hovold7919c2f2010-03-17 23:00:41 +0100817 .bulk_in_size = 256,
Johan Hovold3efeaff2010-03-17 23:00:40 +0100818 .bulk_out_size = 256,
Thiago Galesi572d3132006-07-29 10:46:37 -0300819 .open = pl2303_open,
820 .close = pl2303_close,
Alan Cox335f8512009-06-11 12:26:29 +0100821 .dtr_rts = pl2303_dtr_rts,
822 .carrier_raised = pl2303_carrier_raised,
Thiago Galesi572d3132006-07-29 10:46:37 -0300823 .ioctl = pl2303_ioctl,
824 .break_ctl = pl2303_break_ctl,
825 .set_termios = pl2303_set_termios,
826 .tiocmget = pl2303_tiocmget,
827 .tiocmset = pl2303_tiocmset,
Johan Hovoldf08e07a2010-03-17 23:05:58 +0100828 .process_read_urb = pl2303_process_read_urb,
Thiago Galesi572d3132006-07-29 10:46:37 -0300829 .read_int_callback = pl2303_read_int_callback,
Thiago Galesi572d3132006-07-29 10:46:37 -0300830 .attach = pl2303_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -0400831 .release = pl2303_release,
Thiago Galesi572d3132006-07-29 10:46:37 -0300832};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Alan Sternf667dda2012-02-23 14:57:18 -0500834static struct usb_serial_driver * const serial_drivers[] = {
835 &pl2303_device, NULL
836};
837
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700838module_usb_serial_driver(serial_drivers, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841MODULE_LICENSE("GPL");
842
843module_param(debug, bool, S_IRUGO | S_IWUSR);
844MODULE_PARM_DESC(debug, "Debug enabled or not");
845