pl2303.c 31.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
Linus Torvalds's avatar
Linus Torvalds committed
2
3
4
/*
 * Prolific PL2303 USB to serial adaptor driver
 *
5
 * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds's avatar
Linus Torvalds committed
6
7
8
9
 * Copyright (C) 2003 IBM Corp.
 *
 * Original driver for 2.2.x by anonymous
 *
10
 * See Documentation/usb/usb-serial.rst for more information on using this
Alan Cox's avatar
Alan Cox committed
11
 * driver
Linus Torvalds's avatar
Linus Torvalds committed
12
13
14
15
16
17
18
19
20
21
22
23
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
Alan Cox's avatar
Alan Cox committed
24
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
25
#include <linux/usb.h>
26
#include <linux/usb/serial.h>
27
#include <asm/unaligned.h>
Linus Torvalds's avatar
Linus Torvalds committed
28
29
#include "pl2303.h"

30
31

#define PL2303_QUIRK_UART_STATE_IDX0		BIT(0)
32
#define PL2303_QUIRK_LEGACY			BIT(1)
33
#define PL2303_QUIRK_ENDPOINT_HACK		BIT(2)
34

35
static const struct usb_device_id id_table[] = {
36
37
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID),
		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
Linus Torvalds's avatar
Linus Torvalds committed
38
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
39
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds's avatar
Linus Torvalds committed
40
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
41
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_CHILITAG) },
Linus Torvalds's avatar
Linus Torvalds committed
42
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnold's avatar
Max Arnold committed
43
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy's avatar
Steve Murphy committed
44
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
45
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
46
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
47
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
48
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) },
49
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) },
50
51
52
53
54
55
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GC) },
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GB) },
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GT) },
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GL) },
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GE) },
	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GS) },
Linus Torvalds's avatar
Linus Torvalds committed
56
	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
57
	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
58
59
	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID),
		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
60
61
	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC485),
		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
62
63
	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC232B),
		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
64
	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) },
Linus Torvalds's avatar
Linus Torvalds committed
65
66
67
68
	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
69
	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds's avatar
Linus Torvalds committed
70
71
72
73
74
75
76
	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
77
78
79
80
81
82
	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1),
		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65),
		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75),
		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
83
84
	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81),
		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
85
	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
86
	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
87
88
	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
89
	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
90
	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
91
	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
92
	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
93
	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
94
95
	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID),
		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
96
	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
97
	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
98
	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Matthew Arnold's avatar
Matthew Arnold committed
99
	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
100
	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
101
	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220TA_PRODUCT_ID) },
102
	{ USB_DEVICE(HP_VENDOR_ID, HP_LD381_PRODUCT_ID) },
103
	{ USB_DEVICE(HP_VENDOR_ID, HP_LD381GC_PRODUCT_ID) },
104
	{ USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) },
105
	{ USB_DEVICE(HP_VENDOR_ID, HP_LD960TA_PRODUCT_ID) },
106
107
	{ USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) },
	{ USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) },
108
109
110
	{ USB_DEVICE(HP_VENDOR_ID, HP_LM920_PRODUCT_ID) },
	{ USB_DEVICE(HP_VENDOR_ID, HP_LM940_PRODUCT_ID) },
	{ USB_DEVICE(HP_VENDOR_ID, HP_TD620_PRODUCT_ID) },
111
	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
112
	{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
113
	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
114
	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
115
	{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
116
	{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
117
	{ USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) },
Linus Torvalds's avatar
Linus Torvalds committed
118
119
120
	{ }					/* Terminating entry */
};

121
MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds's avatar
Linus Torvalds committed
122
123
124
125
126
127
128
129
130
131

#define SET_LINE_REQUEST_TYPE		0x21
#define SET_LINE_REQUEST		0x20

#define SET_CONTROL_REQUEST_TYPE	0x21
#define SET_CONTROL_REQUEST		0x22
#define CONTROL_DTR			0x01
#define CONTROL_RTS			0x02

#define BREAK_REQUEST_TYPE		0x21
Alan Cox's avatar
Alan Cox committed
132
#define BREAK_REQUEST			0x23
Linus Torvalds's avatar
Linus Torvalds committed
133
134
135
136
137
138
139
140
#define BREAK_ON			0xffff
#define BREAK_OFF			0x0000

#define GET_LINE_REQUEST_TYPE		0xa1
#define GET_LINE_REQUEST		0x21

#define VENDOR_WRITE_REQUEST_TYPE	0x40
#define VENDOR_WRITE_REQUEST		0x01
141
#define VENDOR_WRITE_NREQUEST		0x80
Linus Torvalds's avatar
Linus Torvalds committed
142
143
144

#define VENDOR_READ_REQUEST_TYPE	0xc0
#define VENDOR_READ_REQUEST		0x01
145
#define VENDOR_READ_NREQUEST		0x81
Linus Torvalds's avatar
Linus Torvalds committed
146

147
#define UART_STATE_INDEX		8
148
#define UART_STATE_MSR_MASK		0x8b
Linus Torvalds's avatar
Linus Torvalds committed
149
150
151
152
153
154
155
156
157
158
#define UART_STATE_TRANSIENT_MASK	0x74
#define UART_DCD			0x01
#define UART_DSR			0x02
#define UART_BREAK_ERROR		0x04
#define UART_RING			0x08
#define UART_FRAME_ERROR		0x10
#define UART_PARITY_ERROR		0x20
#define UART_OVERRUN_ERROR		0x40
#define UART_CTS			0x80

159
160
#define PL2303_FLOWCTRL_MASK		0xf0

161
162
163
164
165
166
167
168
169
170
171
172
#define PL2303_READ_TYPE_HX_STATUS	0x8080

#define PL2303_HXN_RESET_REG		0x07
#define PL2303_HXN_RESET_UPSTREAM_PIPE	0x02
#define PL2303_HXN_RESET_DOWNSTREAM_PIPE	0x01

#define PL2303_HXN_FLOWCTRL_REG		0x0a
#define PL2303_HXN_FLOWCTRL_MASK	0x1c
#define PL2303_HXN_FLOWCTRL_NONE	0x1c
#define PL2303_HXN_FLOWCTRL_RTS_CTS	0x18
#define PL2303_HXN_FLOWCTRL_XON_XOFF	0x0c

173
static void pl2303_set_break(struct usb_serial_port *port, bool enable);
Linus Torvalds's avatar
Linus Torvalds committed
174
175

enum pl2303_type {
176
	TYPE_H,
177
178
179
180
181
	TYPE_HX,
	TYPE_TA,
	TYPE_TB,
	TYPE_HXD,
	TYPE_HXN,
182
183
184
185
186
187
	TYPE_COUNT
};

struct pl2303_type_data {
	speed_t max_baud_rate;
	unsigned long quirks;
188
	unsigned int no_autoxonxoff:1;
189
	unsigned int no_divisors:1;
Linus Torvalds's avatar
Linus Torvalds committed
190
191
};

192
struct pl2303_serial_private {
193
	const struct pl2303_type_data *type;
194
	unsigned long quirks;
195
196
};

Linus Torvalds's avatar
Linus Torvalds committed
197
198
199
200
struct pl2303_private {
	spinlock_t lock;
	u8 line_control;
	u8 line_status;
201
202

	u8 line_settings[7];
Linus Torvalds's avatar
Linus Torvalds committed
203
204
};

205
static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
206
	[TYPE_H] = {
207
208
209
		.max_baud_rate		= 1228800,
		.quirks			= PL2303_QUIRK_LEGACY,
		.no_autoxonxoff		= true,
210
	},
211
	[TYPE_HX] = {
212
213
214
215
216
217
218
219
220
		.max_baud_rate		= 6000000,
	},
	[TYPE_TA] = {
		.max_baud_rate		= 6000000,
	},
	[TYPE_TB] = {
		.max_baud_rate		= 12000000,
	},
	[TYPE_HXD] = {
221
		.max_baud_rate		= 12000000,
222
	},
223
224
	[TYPE_HXN] = {
		.max_baud_rate		= 12000000,
225
		.no_divisors		= true,
226
	},
227
228
};

229
230
static int pl2303_vendor_read(struct usb_serial *serial, u16 value,
							unsigned char buf[1])
231
{
232
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
233
	struct device *dev = &serial->interface->dev;
234
	u8 request;
235
236
	int res;

237
238
239
240
241
	if (spriv->type == &pl2303_type_data[TYPE_HXN])
		request = VENDOR_READ_NREQUEST;
	else
		request = VENDOR_READ_REQUEST;

242
	res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
243
			request, VENDOR_READ_REQUEST_TYPE,
244
245
246
247
248
249
250
251
252
			value, 0, buf, 1, 100);
	if (res != 1) {
		dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__,
								value, res);
		if (res >= 0)
			res = -EIO;

		return res;
	}
253

254
	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]);
255

256
	return 0;
257
258
}

259
static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
260
{
261
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
262
	struct device *dev = &serial->interface->dev;
263
	u8 request;
264
265
	int res;

266
267
	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index);

268
269
270
271
272
	if (spriv->type == &pl2303_type_data[TYPE_HXN])
		request = VENDOR_WRITE_NREQUEST;
	else
		request = VENDOR_WRITE_REQUEST;

273
	res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
274
			request, VENDOR_WRITE_REQUEST_TYPE,
275
			value, index, NULL, 0, 100);
276
277
278
279
280
	if (res) {
		dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__,
								value, res);
		return res;
	}
281

282
	return 0;
283
284
}

285
286
static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val)
{
287
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
288
289
290
291
292
293
294
	int ret = 0;
	u8 *buf;

	buf = kmalloc(1, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

295
296
297
298
299
	if (spriv->type == &pl2303_type_data[TYPE_HXN])
		ret = pl2303_vendor_read(serial, reg, buf);
	else
		ret = pl2303_vendor_read(serial, reg | 0x80, buf);

300
301
302
303
304
305
306
307
308
309
310
311
312
	if (ret)
		goto out_free;

	*buf &= ~mask;
	*buf |= val & mask;

	ret = pl2303_vendor_write(serial, reg, *buf);
out_free:
	kfree(buf);

	return ret;
}

313
314
315
316
317
318
319
320
static int pl2303_probe(struct usb_serial *serial,
					const struct usb_device_id *id)
{
	usb_set_serial_data(serial, (void *)id->driver_info);

	return 0;
}

321
322
323
324
325
326
/*
 * Use interrupt endpoint from first interface if available.
 *
 * This is needed due to the looney way its endpoints are set up.
 */
static int pl2303_endpoint_hack(struct usb_serial *serial,
327
328
329
330
331
332
333
334
335
					struct usb_serial_endpoints *epds)
{
	struct usb_interface *interface = serial->interface;
	struct usb_device *dev = serial->dev;
	struct device *ddev = &interface->dev;
	struct usb_host_interface *iface_desc;
	struct usb_endpoint_descriptor *endpoint;
	unsigned int i;

336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
	if (interface == dev->actconfig->interface[0])
		return 0;

	/* check out the endpoints of the other interface */
	iface_desc = dev->actconfig->interface[0]->cur_altsetting;

	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		endpoint = &iface_desc->endpoint[i].desc;

		if (!usb_endpoint_is_int_in(endpoint))
			continue;

		dev_dbg(ddev, "found interrupt in on separate interface\n");
		if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in))
			epds->interrupt_in[epds->num_interrupt_in++] = endpoint;
	}

	return 0;
}

static int pl2303_calc_num_ports(struct usb_serial *serial,
					struct usb_serial_endpoints *epds)
{
	unsigned long quirks = (unsigned long)usb_get_serial_data(serial);
	struct device *dev = &serial->interface->dev;
	int ret;

	if (quirks & PL2303_QUIRK_ENDPOINT_HACK) {
		ret = pl2303_endpoint_hack(serial, epds);
		if (ret)
			return ret;
367
368
369
	}

	if (epds->num_interrupt_in < 1) {
370
		dev_err(dev, "required interrupt-in endpoint missing\n");
371
372
373
374
375
376
		return -ENODEV;
	}

	return 1;
}

377
378
379
380
381
382
383
384
385
386
387
388
static bool pl2303_supports_hx_status(struct usb_serial *serial)
{
	int ret;
	u8 buf;

	ret = usb_control_msg_recv(serial->dev, 0, VENDOR_READ_REQUEST,
			VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS,
			0, &buf, 1, 100, GFP_KERNEL);

	return ret == 0;
}

389
static int pl2303_detect_type(struct usb_serial *serial)
390
391
{
	struct usb_device_descriptor *desc = &serial->dev->descriptor;
392
	u16 bcdDevice, bcdUSB;
393
394

	/*
395
	 * Legacy PL2303H, variants 0 and 1 (difference unknown).
396
397
	 */
	if (desc->bDeviceClass == 0x02)
398
		return TYPE_H;		/* variant 0 */
399
400
401

	if (desc->bMaxPacketSize0 != 0x40) {
		if (desc->bDeviceClass == 0x00 || desc->bDeviceClass == 0xff)
402
			return TYPE_H;	/* variant 1 */
403

404
		return TYPE_H;		/* variant 0 */
405
406
	}

407
408
409
410
	bcdDevice = le16_to_cpu(desc->bcdDevice);
	bcdUSB = le16_to_cpu(desc->bcdUSB);

	switch (bcdDevice) {
411
412
413
414
415
416
417
418
	case 0x100:
		/*
		 * Assume it's an HXN-type if the device doesn't support the old read
		 * request value.
		 */
		if (bcdUSB == 0x200 && !pl2303_supports_hx_status(serial))
			return TYPE_HXN;
		break;
419
420
421
422
423
424
425
426
427
428
429
430
431
432
	case 0x300:
		if (bcdUSB == 0x200)
			return TYPE_TA;

		return TYPE_HX;
	case 0x400:
		return TYPE_HXD;
	case 0x500:
		return TYPE_TB;
	}

	dev_err(&serial->interface->dev,
			"unknown device type, please report to linux-usb@vger.kernel.org\n");
	return -ENODEV;
433
434
}

435
static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds's avatar
Linus Torvalds committed
436
{
437
	struct pl2303_serial_private *spriv;
438
	enum pl2303_type type;
439
	unsigned char *buf;
440
441
442
443
444
445
446
447
	int ret;

	ret = pl2303_detect_type(serial);
	if (ret < 0)
		return ret;

	type = ret;
	dev_dbg(&serial->interface->dev, "device type: %d\n", type);
448
449
450
451

	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
	if (!spriv)
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
452

453
	spriv->type = &pl2303_type_data[type];
454
	spriv->quirks = (unsigned long)usb_get_serial_data(serial);
455
	spriv->quirks |= spriv->type->quirks;
456

457
	usb_set_serial_data(serial, spriv);
458

459
	if (type != TYPE_HXN) {
460
461
462
463
464
465
		buf = kmalloc(1, GFP_KERNEL);
		if (!buf) {
			kfree(spriv);
			return -ENOMEM;
		}

466
467
468
469
470
471
472
473
474
475
476
477
478
479
		pl2303_vendor_read(serial, 0x8484, buf);
		pl2303_vendor_write(serial, 0x0404, 0);
		pl2303_vendor_read(serial, 0x8484, buf);
		pl2303_vendor_read(serial, 0x8383, buf);
		pl2303_vendor_read(serial, 0x8484, buf);
		pl2303_vendor_write(serial, 0x0404, 1);
		pl2303_vendor_read(serial, 0x8484, buf);
		pl2303_vendor_read(serial, 0x8383, buf);
		pl2303_vendor_write(serial, 0, 1);
		pl2303_vendor_write(serial, 1, 0);
		if (spriv->quirks & PL2303_QUIRK_LEGACY)
			pl2303_vendor_write(serial, 2, 0x24);
		else
			pl2303_vendor_write(serial, 2, 0x44);
480

481
482
		kfree(buf);
	}
483

Linus Torvalds's avatar
Linus Torvalds committed
484
	return 0;
485
}
Linus Torvalds's avatar
Linus Torvalds committed
486

487
488
static void pl2303_release(struct usb_serial *serial)
{
489
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505

	kfree(spriv);
}

static int pl2303_port_probe(struct usb_serial_port *port)
{
	struct pl2303_private *priv;

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	spin_lock_init(&priv->lock);

	usb_set_serial_port_data(port, priv);

506
507
	port->port.drain_delay = 256;

508
509
510
	return 0;
}

511
static void pl2303_port_remove(struct usb_serial_port *port)
512
{
513
	struct pl2303_private *priv = usb_get_serial_port_data(port);
514
515

	kfree(priv);
Linus Torvalds's avatar
Linus Torvalds committed
516
517
}

518
static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
Linus Torvalds's avatar
Linus Torvalds committed
519
{
520
	struct usb_device *dev = port->serial->dev;
Linus Torvalds's avatar
Linus Torvalds committed
521
	int retval;
Alan Cox's avatar
Alan Cox committed
522

523
524
	dev_dbg(&port->dev, "%s - %02x\n", __func__, value);

525
526
527
	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
				 value, 0, NULL, 0, 100);
528
529
	if (retval)
		dev_err(&port->dev, "%s - failed: %d\n", __func__, retval);
530

Linus Torvalds's avatar
Linus Torvalds committed
531
532
533
	return retval;
}

534
/*
535
536
 * Returns the nearest supported baud rate that can be set directly without
 * using divisors.
537
538
 */
static speed_t pl2303_get_supported_baud_rate(speed_t baud)
Linus Torvalds's avatar
Linus Torvalds committed
539
{
540
541
542
	static const speed_t baud_sup[] = {
		75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600,
		14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800,
543
		614400, 921600, 1228800, 2457600, 3000000, 6000000
544
	};
Linus Torvalds's avatar
Linus Torvalds committed
545

546
	unsigned i;
547

548
549
550
551
	for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
		if (baud_sup[i] > baud)
			break;
	}
552

553
554
555
556
557
558
	if (i == ARRAY_SIZE(baud_sup))
		baud = baud_sup[i - 1];
	else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
		baud = baud_sup[i - 1];
	else
		baud = baud_sup[i];
559

560
561
562
	return baud;
}

563
564
565
566
567
568
569
570
571
572
573
574
/*
 * NOTE: If unsupported baud rates are set directly, the PL2303 seems to
 *       use 9600 baud.
 */
static speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4],
								speed_t baud)
{
	put_unaligned_le32(baud, buf);

	return baud;
}

575
576
577
static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
								speed_t baud)
{
578
	unsigned int baseline, mantissa, exponent;
579
580
581

	/*
	 * Apparently the formula is:
582
583
584
585
	 *   baudrate = 12M * 32 / (mantissa * 4^exponent)
	 * where
	 *   mantissa = buf[8:0]
	 *   exponent = buf[11:9]
586
	 */
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
	baseline = 12000000 * 32;
	mantissa = baseline / baud;
	if (mantissa == 0)
		mantissa = 1;	/* Avoid dividing by zero if baud > 32*12M. */
	exponent = 0;
	while (mantissa >= 512) {
		if (exponent < 7) {
			mantissa >>= 2;	/* divide by 4 */
			exponent++;
		} else {
			/* Exponent is maxed. Trim mantissa and leave. */
			mantissa = 511;
			break;
		}
	}

603
604
	buf[3] = 0x80;
	buf[2] = 0;
605
606
607
608
609
	buf[1] = exponent << 1 | mantissa >> 8;
	buf[0] = mantissa & 0xff;

	/* Calculate and return the exact baud rate. */
	baud = (baseline / mantissa) >> (exponent << 1);
610
611
612
613

	return baud;
}

614
615
616
617
618
619
static void pl2303_encode_baud_rate(struct tty_struct *tty,
					struct usb_serial_port *port,
					u8 buf[4])
{
	struct usb_serial *serial = port->serial;
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
620
	speed_t	baud_sup;
621
622
623
624
625
626
	speed_t baud;

	baud = tty_get_baud_rate(tty);
	dev_dbg(&port->dev, "baud requested = %u\n", baud);
	if (!baud)
		return;
627
628
629

	if (spriv->type->max_baud_rate)
		baud = min_t(speed_t, baud, spriv->type->max_baud_rate);
630
	/*
631
	 * Use direct method for supported baud rates, otherwise use divisors.
632
	 * Newer chip types do not support divisor encoding.
633
	 */
634
635
636
637
	if (spriv->type->no_divisors)
		baud_sup = baud;
	else
		baud_sup = pl2303_get_supported_baud_rate(baud);
638

639
640
	if (baud == baud_sup)
		baud = pl2303_encode_baud_rate_direct(buf, baud);
641
	else
642
		baud = pl2303_encode_baud_rate_divisor(buf, baud);
643

644
	/* Save resulting baud rate */
645
	tty_encode_baud_rate(tty, baud, baud);
646
	dev_dbg(&port->dev, "baud set = %u\n", baud);
647
648
}

649
650
651
652
653
654
655
656
657
658
659
660
static int pl2303_get_line_request(struct usb_serial_port *port,
							unsigned char buf[7])
{
	struct usb_device *udev = port->serial->dev;
	int ret;

	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
				GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
				0, 0, buf, 7, 100);
	if (ret != 7) {
		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);

661
		if (ret >= 0)
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
			ret = -EIO;

		return ret;
	}

	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);

	return 0;
}

static int pl2303_set_line_request(struct usb_serial_port *port,
							unsigned char buf[7])
{
	struct usb_device *udev = port->serial->dev;
	int ret;

	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
				SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
				0, 0, buf, 7, 100);
681
	if (ret < 0) {
682
683
684
685
686
687
688
689
690
		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
		return ret;
	}

	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);

	return 0;
}

691
692
693
694
695
696
697
698
699
700
701
static bool pl2303_termios_change(const struct ktermios *a, const struct ktermios *b)
{
	bool ixon_change;

	ixon_change = ((a->c_iflag ^ b->c_iflag) & (IXON | IXANY)) ||
			a->c_cc[VSTART] != b->c_cc[VSTART] ||
			a->c_cc[VSTOP] != b->c_cc[VSTOP];

	return tty_termios_hw_change(a, b) || ixon_change;
}

702
703
704
705
706
707
708
709
710
711
712
713
714
715
static bool pl2303_enable_xonxoff(struct tty_struct *tty, const struct pl2303_type_data *type)
{
	if (!I_IXON(tty) || I_IXANY(tty))
		return false;

	if (START_CHAR(tty) != 0x11 || STOP_CHAR(tty) != 0x13)
		return false;

	if (type->no_autoxonxoff)
		return false;

	return true;
}

716
717
718
719
720
721
722
723
static void pl2303_set_termios(struct tty_struct *tty,
		struct usb_serial_port *port, struct ktermios *old_termios)
{
	struct usb_serial *serial = port->serial;
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
	struct pl2303_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	unsigned char *buf;
724
	int ret;
725
726
	u8 control;

727
	if (old_termios && !pl2303_termios_change(&tty->termios, old_termios))
728
729
730
731
732
733
734
735
736
737
		return;

	buf = kzalloc(7, GFP_KERNEL);
	if (!buf) {
		/* Report back no change occurred */
		if (old_termios)
			tty->termios = *old_termios;
		return;
	}

738
	pl2303_get_line_request(port, buf);
739

740
741
742
743
744
745
746
747
748
749
750
751
752
	switch (C_CSIZE(tty)) {
	case CS5:
		buf[6] = 5;
		break;
	case CS6:
		buf[6] = 6;
		break;
	case CS7:
		buf[6] = 7;
		break;
	default:
	case CS8:
		buf[6] = 8;
753
	}
754
	dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
755

756
	/* For reference buf[0]:buf[3] baud rate value */
757
	pl2303_encode_baud_rate(tty, port, &buf[0]);
758

Linus Torvalds's avatar
Linus Torvalds committed
759
760
761
	/* For reference buf[4]=0 is 1 stop bits */
	/* For reference buf[4]=1 is 1.5 stop bits */
	/* For reference buf[4]=2 is 2 stop bits */
762
763
764
	if (C_CSTOPB(tty)) {
		/*
		 * NOTE: Comply with "real" UARTs / RS232:
765
766
		 *       use 1.5 instead of 2 stop bits with 5 data bits
		 */
767
		if (C_CSIZE(tty) == CS5) {
768
			buf[4] = 1;
769
			dev_dbg(&port->dev, "stop bits = 1.5\n");
770
771
		} else {
			buf[4] = 2;
772
			dev_dbg(&port->dev, "stop bits = 2\n");
773
		}
Linus Torvalds's avatar
Linus Torvalds committed
774
775
	} else {
		buf[4] = 0;
776
		dev_dbg(&port->dev, "stop bits = 1\n");
Linus Torvalds's avatar
Linus Torvalds committed
777
778
	}

779
	if (C_PARENB(tty)) {
Linus Torvalds's avatar
Linus Torvalds committed
780
781
782
783
784
		/* For reference buf[5]=0 is none parity */
		/* For reference buf[5]=1 is odd parity */
		/* For reference buf[5]=2 is even parity */
		/* For reference buf[5]=3 is mark parity */
		/* For reference buf[5]=4 is space parity */
785
		if (C_PARODD(tty)) {
Johan Hovold's avatar
Johan Hovold committed
786
			if (C_CMSPAR(tty)) {
787
				buf[5] = 3;
788
				dev_dbg(&port->dev, "parity = mark\n");
789
790
			} else {
				buf[5] = 1;
791
				dev_dbg(&port->dev, "parity = odd\n");
792
			}
Linus Torvalds's avatar
Linus Torvalds committed
793
		} else {
Johan Hovold's avatar
Johan Hovold committed
794
			if (C_CMSPAR(tty)) {
795
				buf[5] = 4;
796
				dev_dbg(&port->dev, "parity = space\n");
797
798
			} else {
				buf[5] = 2;
799
				dev_dbg(&port->dev, "parity = even\n");
800
			}
Linus Torvalds's avatar
Linus Torvalds committed
801
802
803
		}
	} else {
		buf[5] = 0;
804
		dev_dbg(&port->dev, "parity = none\n");
Linus Torvalds's avatar
Linus Torvalds committed
805
806
	}

807
808
809
810
811
812
813
814
815
816
817
818
819
	/*
	 * Some PL2303 are known to lose bytes if you change serial settings
	 * even to the same values as before. Thus we actually need to filter
	 * in this specific case.
	 *
	 * Note that the tty_termios_hw_change check above is not sufficient
	 * as a previously requested baud rate may differ from the one
	 * actually used (and stored in old_termios).
	 *
	 * NOTE: No additional locking needed for line_settings as it is
	 *       only used in set_termios, which is serialised against itself.
	 */
	if (!old_termios || memcmp(buf, priv->line_settings, 7)) {
820
821
		ret = pl2303_set_line_request(port, buf);
		if (!ret)
822
823
			memcpy(priv->line_settings, buf, 7);
	}
Linus Torvalds's avatar
Linus Torvalds committed
824
825
826
827

	/* change control lines if we are switching to or from B0 */
	spin_lock_irqsave(&priv->lock, flags);
	control = priv->line_control;
828
	if (C_BAUD(tty) == B0)
Linus Torvalds's avatar
Linus Torvalds committed
829
		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
830
	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
Linus Torvalds's avatar
Linus Torvalds committed
831
832
833
834
		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
	if (control != priv->line_control) {
		control = priv->line_control;
		spin_unlock_irqrestore(&priv->lock, flags);
835
		pl2303_set_control_lines(port, control);
Linus Torvalds's avatar
Linus Torvalds committed
836
837
838
	} else {
		spin_unlock_irqrestore(&priv->lock, flags);
	}
839

840
	if (C_CRTSCTS(tty)) {
841
		if (spriv->quirks & PL2303_QUIRK_LEGACY) {
842
			pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40);
843
844
845
846
847
		} else if (spriv->type == &pl2303_type_data[TYPE_HXN]) {
			pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
					PL2303_HXN_FLOWCTRL_MASK,
					PL2303_HXN_FLOWCTRL_RTS_CTS);
		} else {
848
			pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60);
849
		}
850
	} else if (pl2303_enable_xonxoff(tty, spriv->type)) {
851
852
853
854
855
856
857
		if (spriv->type == &pl2303_type_data[TYPE_HXN]) {
			pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
					PL2303_HXN_FLOWCTRL_MASK,
					PL2303_HXN_FLOWCTRL_XON_XOFF);
		} else {
			pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0);
		}
t.sefzick's avatar
t.sefzick committed
858
	} else {
859
860
861
862
863
864
865
		if (spriv->type == &pl2303_type_data[TYPE_HXN]) {
			pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
					PL2303_HXN_FLOWCTRL_MASK,
					PL2303_HXN_FLOWCTRL_NONE);
		} else {
			pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
		}
Linus Torvalds's avatar
Linus Torvalds committed
866
	}
867
868
869
870

	kfree(buf);
}

871
872
873
874
875
876
877
878
879
880
881
882
883
static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
{
	struct pl2303_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	u8 control;

	spin_lock_irqsave(&priv->lock, flags);
	if (on)
		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
	else
		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
	control = priv->line_control;
	spin_unlock_irqrestore(&priv->lock, flags);
884

885
	pl2303_set_control_lines(port, control);
886
887
888
}

static void pl2303_close(struct usb_serial_port *port)
889
{
Johan Hovold's avatar
Johan Hovold committed
890
	usb_serial_generic_close(port);
891
	usb_kill_urb(port->interrupt_in_urb);
892
	pl2303_set_break(port, false);
Linus Torvalds's avatar
Linus Torvalds committed
893
894
}

895
static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds's avatar
Linus Torvalds committed
896
897
{
	struct usb_serial *serial = port->serial;
898
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
Linus Torvalds's avatar
Linus Torvalds committed
899
900
	int result;

901
	if (spriv->quirks & PL2303_QUIRK_LEGACY) {
902
903
		usb_clear_halt(serial->dev, port->write_urb->pipe);
		usb_clear_halt(serial->dev, port->read_urb->pipe);
904
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
905
		/* reset upstream data pipes */
906
907
908
909
910
911
912
913
		if (spriv->type == &pl2303_type_data[TYPE_HXN]) {
			pl2303_vendor_write(serial, PL2303_HXN_RESET_REG,
					PL2303_HXN_RESET_UPSTREAM_PIPE |
					PL2303_HXN_RESET_DOWNSTREAM_PIPE);
		} else {
			pl2303_vendor_write(serial, 8, 0);
			pl2303_vendor_write(serial, 9, 0);
		}
Linus Torvalds's avatar
Linus Torvalds committed
914
915
916
	}

	/* Setup termios */
Alan Cox's avatar
Alan Cox committed
917
	if (tty)
918
		pl2303_set_termios(tty, port, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
919

920
	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
921
	if (result) {
922
923
		dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
			result);
924
		return result;
Linus Torvalds's avatar
Linus Torvalds committed
925
	}
926

927
	result = usb_serial_generic_open(tty, port);
928
929
930
931
932
	if (result) {
		usb_kill_urb(port->interrupt_in_urb);
		return result;
	}

Linus Torvalds's avatar
Linus Torvalds committed
933
934
935
	return 0;
}

936
static int pl2303_tiocmset(struct tty_struct *tty,
937
			   unsigned int set, unsigned int clear)
Linus Torvalds's avatar
Linus Torvalds committed
938
{
Alan Cox's avatar
Alan Cox committed
939
	struct usb_serial_port *port = tty->driver_data;
Linus Torvalds's avatar
Linus Torvalds committed
940
941
942
	struct pl2303_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	u8 control;
943
	int ret;
944

945
	spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
946
947
948
949
950
951
952
953
954
	if (set & TIOCM_RTS)
		priv->line_control |= CONTROL_RTS;
	if (set & TIOCM_DTR)
		priv->line_control |= CONTROL_DTR;
	if (clear & TIOCM_RTS)
		priv->line_control &= ~CONTROL_RTS;
	if (clear & TIOCM_DTR)
		priv->line_control &= ~CONTROL_DTR;
	control = priv->line_control;
955
	spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
956

957
958
959
	ret = pl2303_set_control_lines(port, control);
	if (ret)
		return usb_translate_errors(ret);
960

961
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
962
963
}

964
static int pl2303_tiocmget(struct tty_struct *tty)
Linus Torvalds's avatar
Linus Torvalds committed
965
{
Alan Cox's avatar
Alan Cox committed
966
	struct usb_serial_port *port = tty->driver_data;
Linus Torvalds's avatar
Linus Torvalds committed
967
968
969
970
971
972
	struct pl2303_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	unsigned int mcr;
	unsigned int status;
	unsigned int result;

973
	spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
974
975
	mcr = priv->line_control;
	status = priv->line_status;
976
	spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
977
978
979
980
981
982
983
984

	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
		  | ((status & UART_RING)	? TIOCM_RI  : 0)
		  | ((status & UART_DCD)	? TIOCM_CD  : 0);

985
	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
Linus Torvalds's avatar
Linus Torvalds committed
986
987
988
989

	return result;
}

990
991
992
static int pl2303_carrier_raised(struct usb_serial_port *port)
{
	struct pl2303_private *priv = usb_get_serial_port_data(port);
993

994
995
	if (priv->line_status & UART_DCD)
		return 1;
996

997
998
999
	return 0;
}

Al Viro's avatar
Al Viro committed
1000
1001
static int pl2303_get_serial(struct tty_struct *tty,
			struct serial_struct *ss)
Linus Torvalds's avatar
Linus Torvalds committed
1002
{
Alan Cox's avatar
Alan Cox committed
1003
	struct usb_serial_port *port = tty->driver_data;
1004

Al Viro's avatar
Al Viro committed
1005
1006
1007
1008
1009
	ss->type = PORT_16654;
	ss->line = port->minor;
	ss->port = port->port_number;
	ss->baud_base = 460800;
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1010
1011
}

1012
static void pl2303_set_break(struct usb_serial_port *port, bool enable)
Linus Torvalds's avatar
Linus Torvalds committed
1013
1014
1015
1016
1017
{
	struct usb_serial *serial = port->serial;
	u16 state;
	int result;

1018
	if (enable)
Linus Torvalds's avatar
Linus Torvalds committed
1019
		state = BREAK_ON;
1020
1021
	else
		state = BREAK_OFF;
1022

1023
	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
Alan Cox's avatar
Alan Cox committed
1024
			state == BREAK_OFF ? "off" : "on");
Linus Torvalds's avatar
Linus Torvalds committed
1025

1026
1027
1028
	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
				 0, NULL, 0, 100);
Linus Torvalds's avatar
Linus Torvalds committed
1029
	if (result)
1030
		dev_err(&port->dev, "error sending break = %d\n", result);
Linus Torvalds's avatar
Linus Torvalds committed
1031
1032
}

1033
1034
1035
1036
1037
1038
1039
static void pl2303_break_ctl(struct tty_struct *tty, int state)
{
	struct usb_serial_port *port = tty->driver_data;

	pl2303_set_break(port, state);
}

Flavio Leitner's avatar
Flavio Leitner committed
1040
1041
1042
1043
static void pl2303_update_line_status(struct usb_serial_port *port,
				      unsigned char *data,
				      unsigned int actual_length)
{
1044
1045
	struct usb_serial *serial = port->serial;
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
Flavio Leitner's avatar
Flavio Leitner committed
1046
	struct pl2303_private *priv = usb_get_serial_port_data(port);
1047
	struct tty_struct *tty;
Flavio Leitner's avatar
Flavio Leitner committed
1048
	unsigned long flags;
1049
	unsigned int status_idx = UART_STATE_INDEX;
1050
1051
	u8 status;
	u8 delta;
Flavio Leitner's avatar
Flavio Leitner committed
1052

1053
1054
	if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0)
		status_idx = 0;
Flavio Leitner's avatar
Flavio Leitner committed
1055

1056
	if (actual_length < status_idx + 1)
1057
		return;
Flavio Leitner's avatar
Flavio Leitner committed
1058

1059
1060
	status = data[status_idx];

Alan Cox's avatar
Alan Cox committed
1061
	/* Save off the uart status for others to look at */