pl2303.c revision c82c6d45a2fc882fedfde517ba86690b2d5ed555
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prolific PL2303 USB to serial adaptor driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
44d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 IBM Corp.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Original driver for 2.2.x by anonymous
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
94d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman *	This program is free software; you can redistribute it and/or
104d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman *	modify it under the terms of the GNU General Public License version
114d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman *	2 as published by the Free Software Foundation.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
133a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox * See Documentation/usb/usb-serial.txt for more information on using this
143a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox * driver
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
283a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#include <linux/uaccess.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
30a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h>
31b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold#include <asm/unaligned.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h"
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
35228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold#define PL2303_QUIRK_UART_STATE_IDX0		BIT(0)
3623c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold#define PL2303_QUIRK_LEGACY			BIT(1)
37228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
387d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = {
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
413d861494729c70d9ebeb7d93caa107897925c355Peter Moulder	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
44b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
454be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
46727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
4718344a1cd5889d48dac67229fcf024ed300030d5Simone Contini	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
4896a3e79edff6f41b0f115a82f1a39d66218077a7Dario Lombardo	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
508a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
5658381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
65228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1),
66228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
67228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65),
68228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
69228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75),
70228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
71e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
72912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
73acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
74c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
75c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
766cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
77c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
78491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
793b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
80b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
818fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
822d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
839e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
84cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
857c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
86af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
878540d66615c39010168ab97eaafb476ec2851298Gianpaolo Cugola	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
88f36ecd5de93e4c85a9e3d25100c6e233155b12e5Jef Driesen	{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
8949276560c9004fce24c42e3c0ad75f34d956fc63Khanh-Dang Nguyen Thu Lam	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
9035904e6b5106fda51b04c8b8080c04466865415fPawel Ludwikow	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
919a61d72602771906e11a5944e8571f8006387b39Manuel Jander	{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
92598f0b703506da841d3459dc0c48506be14d1778Eric Benoit	{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
96372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1073a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST			0x23
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
120228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold#define UART_STATE_INDEX		8
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1337f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	TYPE_01,	/* Type 0 and 1 (difference unknown) */
1347f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	TYPE_HX,	/* HX version of the pl2303 chip */
135359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	TYPE_COUNT
136359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold};
137359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold
138359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovoldstruct pl2303_type_data {
139359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	speed_t max_baud_rate;
140359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	unsigned long quirks;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1438bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstruct pl2303_serial_private {
144359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	struct pl2303_type_data *type;
145228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	unsigned long quirks;
1468bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold};
1478bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
152623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold
153623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	u8 line_settings[7];
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovoldstatic struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
157359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	[TYPE_01] = {
158359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold		.max_baud_rate =	1228800,
159359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold		.quirks =		PL2303_QUIRK_LEGACY,
160359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	},
161359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold};
162359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold
163362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_read(struct usb_serial *serial, u16 value,
164362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold							unsigned char buf[1])
165eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
166362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	struct device *dev = &serial->interface->dev;
167ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	int res;
168ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
169ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
170eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
171362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			value, 0, buf, 1, 100);
172362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	if (res != 1) {
173362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__,
174362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold								value, res);
175362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		if (res >= 0)
176362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			res = -EIO;
177362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold
178362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		return res;
179362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	}
180ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
181362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]);
182ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
183362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	return 0;
184eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
185eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
186362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
187eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
188362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	struct device *dev = &serial->interface->dev;
189ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	int res;
190ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
191362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index);
192362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold
193ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
194eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
195eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
196362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	if (res) {
197362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__,
198362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold								value, res);
199362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		return res;
200362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	}
201ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
202362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	return 0;
203eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
204eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
205228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovoldstatic int pl2303_probe(struct usb_serial *serial,
206228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold					const struct usb_device_id *id)
207228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold{
208228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	usb_set_serial_data(serial, (void *)id->driver_info);
209228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
210228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	return 0;
211228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold}
212228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
213372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2158bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv;
2167f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	enum pl2303_type type = TYPE_01;
2173e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	unsigned char *buf;
2188bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2198bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
2208bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!spriv)
2218bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	buf = kmalloc(1, GFP_KERNEL);
2248bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!buf) {
2258bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		kfree(spriv);
2263e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		return -ENOMEM;
2278bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	}
2283e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
229b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	if (serial->dev->descriptor.bDeviceClass == 0x02)
2307f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 0 */
231b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
2327f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_HX;
233281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman	else if (serial->dev->descriptor.bDeviceClass == 0x00)
2347f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 1 */
235281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
2367f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 1 */
237b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	dev_dbg(&serial->interface->dev, "device type: %d\n", type);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
239359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	spriv->type = &pl2303_type_data[type];
240228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	spriv->quirks = (unsigned long)usb_get_serial_data(serial);
241359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	spriv->quirks |= spriv->type->quirks;
242228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
2438bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_data(serial, spriv);
2443e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
245362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
246362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0x0404, 0);
247362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
248362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8383, buf);
249362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
250362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0x0404, 1);
251362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
252362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8383, buf);
253362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0, 1);
254362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 1, 0);
25523c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold	if (spriv->quirks & PL2303_QUIRK_LEGACY)
256362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 2, 0x24);
2577f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	else
2587f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		pl2303_vendor_write(serial, 2, 0x44);
2593e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2603e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
261ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2638bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2658bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic void pl2303_release(struct usb_serial *serial)
2668bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
267ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
2688bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2698bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(spriv);
2708bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2718bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2728bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_probe(struct usb_serial_port *port)
2738bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2748bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_private *priv;
2758bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2768bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2778bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!priv)
2788bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
2798bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2808bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spin_lock_init(&priv->lock);
2818bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2828bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_port_data(port, priv);
2838bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
284d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold	port->port.drain_delay = 256;
285d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold
2868bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2878bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2888bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2898bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_remove(struct usb_serial_port *port)
2908bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
291ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
2928bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2938bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(priv);
2948bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2958bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
298f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovoldstatic int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
300f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	struct usb_device *dev = port->serial->dev;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
3023a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox
303a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold	dev_dbg(&port->dev, "%s - %02x\n", __func__, value);
304a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold
305372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
306372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
307372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
308a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold	if (retval)
309a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, retval);
310ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold/*
31559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold * Returns the nearest supported baud rate.
31659afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold */
31759afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovoldstatic speed_t pl2303_get_supported_baud_rate(speed_t baud)
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
31959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	static const speed_t baud_sup[] = {
32059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold		75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600,
32159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold		14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800,
32259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold		500000, 614400, 921600, 1228800, 2457600, 3000000, 6000000
32359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	};
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	unsigned i;
326692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
3277e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
3287e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		if (baud_sup[i] > baud)
3297e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman			break;
3307e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	}
331692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
3327e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	if (i == ARRAY_SIZE(baud_sup))
3337e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i - 1];
3347e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
3357e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i - 1];
3367e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	else
3377e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i];
338692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
33959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	return baud;
34059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold}
34159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold
342c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovoldstatic speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
343c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold								speed_t baud)
344c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold{
345c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	unsigned int tmp;
346c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold
347c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	/*
348c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	 * Apparently the formula is:
349c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
350c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	 */
351c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	tmp = 12000000 * 32 / baud;
352c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	buf[3] = 0x80;
353c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	buf[2] = 0;
354c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	buf[1] = (tmp >= 256);
355c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	while (tmp >= 256) {
356c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold		tmp >>= 2;
357c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold		buf[1] <<= 1;
358c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	}
359c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	buf[0] = tmp;
360c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold
361c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	return baud;
362c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold}
363c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold
36459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovoldstatic void pl2303_encode_baud_rate(struct tty_struct *tty,
36559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold					struct usb_serial_port *port,
36659afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold					u8 buf[4])
36759afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold{
36859afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	struct usb_serial *serial = port->serial;
36959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
37059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	speed_t baud;
37159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold
37259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	baud = tty_get_baud_rate(tty);
37359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	dev_dbg(&port->dev, "baud requested = %u\n", baud);
37459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	if (!baud)
37559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold		return;
376871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold
377871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold	if (spriv->type->max_baud_rate)
378871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold		baud = min_t(speed_t, baud, spriv->type->max_baud_rate);
37959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	/*
38059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	 * Set baud rate to nearest supported value.
38159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	 *
38259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	 * NOTE: If unsupported values are set directly, the PL2303 seems to
38359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	 *       use 9600 baud.
38459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	 */
38559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	baud = pl2303_get_supported_baud_rate(baud);
38659afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold
387c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	if (baud <= 115200)
388692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman		put_unaligned_le32(baud, buf);
389c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	else
390c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold		baud = pl2303_encode_baud_rate_divisor(buf, baud);
391692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
39215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	/* Save resulting baud rate */
393b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold	tty_encode_baud_rate(tty, baud, baud);
394f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold	dev_dbg(&port->dev, "baud set = %u\n", baud);
39515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold}
39615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
397383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_get_line_request(struct usb_serial_port *port,
398383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold							unsigned char buf[7])
399383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{
400383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	struct usb_device *udev = port->serial->dev;
401383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
402383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
403383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
404383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
405383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				0, 0, buf, 7, 100);
406383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	if (ret != 7) {
407383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
408383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
409383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (ret > 0)
410383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold			ret = -EIO;
411383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
412383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		return ret;
413383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	}
414383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
415383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);
416383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
417383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	return 0;
418383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold}
419383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
420383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_set_line_request(struct usb_serial_port *port,
421383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold							unsigned char buf[7])
422383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{
423383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	struct usb_device *udev = port->serial->dev;
424383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
425383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
426383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
427383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
428383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				0, 0, buf, 7, 100);
429383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	if (ret != 7) {
430383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
431383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
432383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (ret > 0)
433383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold			ret = -EIO;
434383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
435383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		return ret;
436383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	}
437383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
438383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);
439383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
440383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	return 0;
441383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold}
442383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
44315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_set_termios(struct tty_struct *tty,
44415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		struct usb_serial_port *port, struct ktermios *old_termios)
44515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold{
44615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct usb_serial *serial = port->serial;
44715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
44815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
44915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	unsigned long flags;
45015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	unsigned char *buf;
451383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
45215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	u8 control;
45315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
45415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
45515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		return;
45615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
45715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	buf = kzalloc(7, GFP_KERNEL);
45815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	if (!buf) {
45915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		/* Report back no change occurred */
46015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		if (old_termios)
46115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			tty->termios = *old_termios;
46215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		return;
46315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	}
46415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
465383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	pl2303_get_line_request(port, buf);
46615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
467a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	switch (C_CSIZE(tty)) {
468a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS5:
469a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 5;
470a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
471a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS6:
472a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 6;
473a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
474a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS7:
475a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 7;
476a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
477a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	default:
478a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS8:
479a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 8;
48015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	}
481a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
48215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
483692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman	/* For reference buf[0]:buf[3] baud rate value */
48479816824c1ae73542d9523283ce353142b67563eJohan Hovold	pl2303_encode_baud_rate(tty, port, &buf[0]);
48515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
48987265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CSTOPB(tty)) {
49087265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		/*
49187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		 * NOTE: Comply with "real" UARTs / RS232:
49229cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 *       use 1.5 instead of 2 stop bits with 5 data bits
49329cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 */
49487265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		if (C_CSIZE(tty) == CS5) {
49529cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 1;
496d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 1.5\n");
49729cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		} else {
49829cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 2;
499d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 2\n");
50029cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		}
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
503d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "stop bits = 1\n");
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
50687265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_PARENB(tty)) {
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
51287265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		if (C_PARODD(tty)) {
51387265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold			if (tty->termios.c_cflag & CMSPAR) {
5146dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 3;
515d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = mark\n");
5166dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
5176dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 1;
518d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = odd\n");
5196dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
52187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold			if (tty->termios.c_cflag & CMSPAR) {
5226dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 4;
523d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = space\n");
5246dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
5256dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 2;
526d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = even\n");
5276dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
531d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "parity = none\n");
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
534623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	/*
535623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * Some PL2303 are known to lose bytes if you change serial settings
536623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * even to the same values as before. Thus we actually need to filter
537623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * in this specific case.
538623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *
539623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * Note that the tty_termios_hw_change check above is not sufficient
540623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * as a previously requested baud rate may differ from the one
541623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * actually used (and stored in old_termios).
542623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *
543623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * NOTE: No additional locking needed for line_settings as it is
544623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *       only used in set_termios, which is serialised against itself.
545623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 */
546623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	if (!old_termios || memcmp(buf, priv->line_settings, 7)) {
547383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		ret = pl2303_set_line_request(port, buf);
548383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (!ret)
549623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold			memcpy(priv->line_settings, buf, 7);
550623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	}
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
55587265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_BAUD(tty) == B0)
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
5572d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
562f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold		pl2303_set_control_lines(port, control);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
566372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
56787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CRTSCTS(tty)) {
56823c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold		if (spriv->quirks & PL2303_QUIRK_LEGACY)
569362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			pl2303_vendor_write(serial, 0x0, 0x41);
5707f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		else
5717f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold			pl2303_vendor_write(serial, 0x0, 0x61);
572715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
573362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 0x0, 0x0);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
575572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
576572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
577572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
578572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
579335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on)
580335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
581335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
582335f8514f200e63d689113d29cb7253a5c282967Alan Cox	unsigned long flags;
583335f8514f200e63d689113d29cb7253a5c282967Alan Cox	u8 control;
584335f8514f200e63d689113d29cb7253a5c282967Alan Cox
585335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_lock_irqsave(&priv->lock, flags);
586335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (on)
587335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
588335f8514f200e63d689113d29cb7253a5c282967Alan Cox	else
589335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
590335f8514f200e63d689113d29cb7253a5c282967Alan Cox	control = priv->line_control;
591335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_unlock_irqrestore(&priv->lock, flags);
592ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
593f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	pl2303_set_control_lines(port, control);
594335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
595335f8514f200e63d689113d29cb7253a5c282967Alan Cox
596335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port)
597572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
5988b0127b2082601e40295045414a8318f2c8ee5a0Johan Hovold	usb_serial_generic_close(port);
599572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
602a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
6058bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60823c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold	if (spriv->quirks & PL2303_QUIRK_LEGACY) {
6091694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
6101694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
6113e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	} else {
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
613362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 8, 0);
614362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 9, 0);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
61895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (tty)
6192d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold		pl2303_set_termios(tty, port, NULL);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
623ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold		dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
624ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold			result);
625db6e9186c90188edea20aaa5161ea073440cc2a1Johan Hovold		return result;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
627d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
628f5230a53c1d551811b077ccad219105786da1becJohan Hovold	result = usb_serial_generic_open(tty, port);
629d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	if (result) {
630d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		usb_kill_urb(port->interrupt_in_urb);
631d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		return result;
632d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	}
633d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63720b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty,
638372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
64095da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
6446f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	int ret;
6456fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
646372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
656372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6585ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	ret = pl2303_set_control_lines(port, control);
6595ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	if (ret)
6605ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold		return usb_translate_errors(ret);
6616f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold
6625ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	return 0;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66560b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int pl2303_tiocmget(struct tty_struct *tty)
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
66795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
674372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
677372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
686d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port)
692335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
693335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
694ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
695335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (priv->line_status & UART_DCD)
696335f8514f200e63d689113d29cb7253a5c282967Alan Cox		return 1;
697ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
698335f8514f200e63d689113d29cb7253a5c282967Alan Cox	return 0;
699335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
700335f8514f200e63d689113d29cb7253a5c282967Alan Cox
701824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovoldstatic int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg)
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
703824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold	struct usb_serial_port *port = tty->driver_data;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
710372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
712372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
7156d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold		interruptible_sleep_on(&port->port.delta_msr_wait);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
719372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
72040509ca982c00c4b70fc00be887509feca0bff15Johan Hovold		if (port->serial->disconnected)
72140509ca982c00c4b70fc00be887509feca0bff15Johan Hovold			return -EIO;
72240509ca982c00c4b70fc00be887509feca0bff15Johan Hovold
723372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
725372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
726372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
7273a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		changed = prevstatus ^ status;
728372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
7323a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
74100a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int pl2303_ioctl(struct tty_struct *tty,
742372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
74467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	struct serial_struct ser;
74595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
746d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
74867b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	case TIOCGSERIAL:
74967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		memset(&ser, 0, sizeof ser);
75067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.type = PORT_16654;
751e5b1e2062e0535e8ffef79bb34d857e21380d101Greg Kroah-Hartman		ser.line = port->minor;
7521143832eca8f1d64da7d85642c956ae9d25c69e1Greg Kroah-Hartman		ser.port = port->port_number;
75367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.baud_base = 460800;
75467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
75567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		if (copy_to_user((void __user *)arg, &ser, sizeof ser))
75667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas			return -EFAULT;
75767b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
75867b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		return 0;
7593a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	default:
7603a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		break;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
762ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76695da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state)
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
76895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
777ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
778d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
7793a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			state == BREAK_OFF ? "off" : "on");
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
782372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
783372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
785d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev, "error sending break = %d\n", result);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
78897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
78997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
79097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
79197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
792228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	struct usb_serial *serial = port->serial;
793228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
79497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
795d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	struct tty_struct *tty;
79697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
797228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	unsigned int status_idx = UART_STATE_INDEX;
798d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	u8 prev_line_status;
79997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
800228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0)
801228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		status_idx = 0;
80297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
803228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	if (actual_length < status_idx + 1)
804a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
80597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
8063a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	/* Save off the uart status for others to look at */
80797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
808d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	prev_line_status = priv->line_status;
80997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
81097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
811ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
812430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel	if (priv->line_status & UART_BREAK_ERROR)
813430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel		usb_serial_handle_break(port);
814ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
8156d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold	wake_up_interruptible(&port->port.delta_msr_wait);
816d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek
817d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty = tty_port_tty_get(&port->port);
818d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if (!tty)
819d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		return;
820d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if ((priv->line_status ^ prev_line_status) & UART_DCD)
821d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		usb_serial_handle_dcd_change(port, tty,
822d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek				priv->line_status & UART_DCD);
823d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty_kref_put(tty);
82497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8267d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
828cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
83097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
831461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
832461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
834461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
842d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
843d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
846d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
847d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
85159d33f2fc2d63796296b1b76143e039d6e7cf532Greg Kroah-Hartman	usb_serial_debug_data(&port->dev, __func__,
852372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
853372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
85497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
857461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
858ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	if (retval) {
859d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev,
860372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
861441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, retval);
862ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	}
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
865f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovoldstatic void pl2303_process_read_urb(struct urb *urb)
866d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{
867f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct usb_serial_port *port = urb->context;
868f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
869d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	unsigned char *data = urb->transfer_buffer;
870d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	char tty_flag = TTY_NORMAL;
871f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	unsigned long flags;
872f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	u8 line_status;
873f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	int i;
874f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
875f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	/* update line status */
876f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_lock_irqsave(&priv->lock, flags);
877f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	line_status = priv->line_status;
878f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
879f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_unlock_irqrestore(&priv->lock, flags);
880f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
881f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	if (!urb->actual_length)
882f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold		return;
883f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
884ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	/*
885ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 * Break takes precedence over parity, which takes precedence over
886ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 * framing errors.
887ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 */
888d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_BREAK_ERROR)
889d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_BREAK;
890d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_PARITY_ERROR)
891d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_PARITY;
892d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_FRAME_ERROR)
893d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_FRAME;
894d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox
8953ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold	if (tty_flag != TTY_NORMAL)
8963ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold		dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
8973ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold								tty_flag);
898d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* overrun is special, not associated with a char */
899d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_OVERRUN_ERROR)
90092a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby		tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
9019388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold
902d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	if (port->port.console && port->sysrq) {
903d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		for (i = 0; i < urb->actual_length; ++i)
9046ee9f4b4affe751d313d2538999aeec134d413a6Dmitry Torokhov			if (!usb_serial_handle_sysrq_char(port, data[i]))
90592a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby				tty_insert_flip_char(&port->port, data[i],
90692a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby						tty_flag);
907d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	} else {
9082f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby		tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
909d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold							urb->actual_length);
9109388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold	}
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9122e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	tty_flip_buffer_push(&port->port);
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
915572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
916572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
917572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
918572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
919572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
920572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
921572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
9227919c2fd9e07276403b9a4d9ae52305e0d70f923Johan Hovold	.bulk_in_size =		256,
9233efeaff6298290b36499532f0b4c87aa4bae8aefJohan Hovold	.bulk_out_size =	256,
924572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
925572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
926ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	.dtr_rts =		pl2303_dtr_rts,
927335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.carrier_raised =	pl2303_carrier_raised,
928572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
929572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
930572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
931572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
932572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
933824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold	.tiocmiwait =		pl2303_tiocmiwait,
934f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	.process_read_urb =	pl2303_process_read_urb,
935572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
936228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	.probe =		pl2303_probe,
937572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
938f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =		pl2303_release,
9398bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_probe =		pl2303_port_probe,
9408bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_remove =		pl2303_port_remove,
941572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
943f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = {
944f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern	&pl2303_device, NULL
945f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern};
946f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern
94768e24113457e437b1576670f2419b77ed0531e9eGreg Kroah-Hartmanmodule_usb_serial_driver(serial_drivers, id_table);
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
949ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan HovoldMODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver");
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
951