pl2303.c revision 7f966ac7a939633ff6fa8cec58982676c243b4f8
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)
36228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
377d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = {
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
403d861494729c70d9ebeb7d93caa107897925c355Peter Moulder	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
43b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
444be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
45727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
4618344a1cd5889d48dac67229fcf024ed300030d5Simone Contini	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
4796a3e79edff6f41b0f115a82f1a39d66218077a7Dario Lombardo	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
498a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
5558381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
64228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1),
65228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
66228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65),
67228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
68228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75),
69228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
70e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
71912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
72acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
73c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
74c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
756cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
76c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
77491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
783b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
79b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
808fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
812d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
829e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
83cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
847c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
85af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
868540d66615c39010168ab97eaafb476ec2851298Gianpaolo Cugola	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
87f36ecd5de93e4c85a9e3d25100c6e233155b12e5Jef Driesen	{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
8849276560c9004fce24c42e3c0ad75f34d956fc63Khanh-Dang Nguyen Thu Lam	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
8935904e6b5106fda51b04c8b8080c04466865415fPawel Ludwikow	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
909a61d72602771906e11a5944e8571f8006387b39Manuel Jander	{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
91598f0b703506da841d3459dc0c48506be14d1778Eric Benoit	{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1063a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST			0x23
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
119228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold#define UART_STATE_INDEX		8
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1327f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	TYPE_01,	/* Type 0 and 1 (difference unknown) */
1337f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	TYPE_HX,	/* HX version of the pl2303 chip */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1368bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstruct pl2303_serial_private {
1378bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	enum pl2303_type type;
138228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	unsigned long quirks;
1398bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold};
1408bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
145623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold
146623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	u8 line_settings[7];
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
149362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_read(struct usb_serial *serial, u16 value,
150362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold							unsigned char buf[1])
151eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
152362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	struct device *dev = &serial->interface->dev;
153ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	int res;
154ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
155ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
156eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
157362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			value, 0, buf, 1, 100);
158362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	if (res != 1) {
159362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__,
160362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold								value, res);
161362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		if (res >= 0)
162362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			res = -EIO;
163362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold
164362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		return res;
165362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	}
166ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
167362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]);
168ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
169362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	return 0;
170eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
171eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
172362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
173eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
174362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	struct device *dev = &serial->interface->dev;
175ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	int res;
176ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
177362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index);
178362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold
179ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
180eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
181eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
182362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	if (res) {
183362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__,
184362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold								value, res);
185362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		return res;
186362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	}
187ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
188362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	return 0;
189eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
190eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
191228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovoldstatic int pl2303_probe(struct usb_serial *serial,
192228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold					const struct usb_device_id *id)
193228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold{
194228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	usb_set_serial_data(serial, (void *)id->driver_info);
195228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
196228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	return 0;
197228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold}
198228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
199372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2018bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv;
2027f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	enum pl2303_type type = TYPE_01;
2033e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	unsigned char *buf;
2048bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2058bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
2068bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!spriv)
2078bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
209362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	buf = kmalloc(1, GFP_KERNEL);
2108bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!buf) {
2118bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		kfree(spriv);
2123e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		return -ENOMEM;
2138bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	}
2143e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
215b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	if (serial->dev->descriptor.bDeviceClass == 0x02)
2167f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 0 */
217b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
2187f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_HX;
219281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman	else if (serial->dev->descriptor.bDeviceClass == 0x00)
2207f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 1 */
221281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
2227f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 1 */
223b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	dev_dbg(&serial->interface->dev, "device type: %d\n", type);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2258bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv->type = type;
226228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	spriv->quirks = (unsigned long)usb_get_serial_data(serial);
227228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
2288bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_data(serial, spriv);
2293e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
230362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
231362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0x0404, 0);
232362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
233362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8383, buf);
234362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
235362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0x0404, 1);
236362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
237362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8383, buf);
238362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0, 1);
239362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 1, 0);
2407f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	if (type == TYPE_01)
241362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 2, 0x24);
2427f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	else
2437f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		pl2303_vendor_write(serial, 2, 0x44);
2443e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2453e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
246ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2488bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2508bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic void pl2303_release(struct usb_serial *serial)
2518bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
252ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
2538bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2548bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(spriv);
2558bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2568bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2578bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_probe(struct usb_serial_port *port)
2588bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2598bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_private *priv;
2608bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2618bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2628bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!priv)
2638bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
2648bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2658bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spin_lock_init(&priv->lock);
2668bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2678bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_port_data(port, priv);
2688bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
269d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold	port->port.drain_delay = 256;
270d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold
2718bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2728bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2738bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2748bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_remove(struct usb_serial_port *port)
2758bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
276ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
2778bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2788bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(priv);
2798bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2808bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
283f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovoldstatic int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
285f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	struct usb_device *dev = port->serial->dev;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
2873a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox
288a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold	dev_dbg(&port->dev, "%s - %02x\n", __func__, value);
289a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold
290372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
291372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
292372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
293a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold	if (retval)
294a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, retval);
295ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_encode_baudrate(struct tty_struct *tty,
30015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold					struct usb_serial_port *port,
30115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold					u8 buf[4])
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
303f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold	const speed_t baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
3047e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	                         4800, 7200, 9600, 14400, 19200, 28800, 38400,
3057e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	                         57600, 115200, 230400, 460800, 500000, 614400,
3067e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	                         921600, 1228800, 2457600, 3000000, 6000000 };
3077e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman
308692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman	struct usb_serial *serial = port->serial;
309692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
310f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold	speed_t baud;
3117e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	int i;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3137e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	/*
3147e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	 * NOTE: Only the values defined in baud_sup are supported!
3157e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	 *       => if unsupported values are set, the PL2303 seems to use
3167e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	 *          9600 baud (at least my PL2303X always does)
3177e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	 */
31895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	baud = tty_get_baud_rate(tty);
319f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold	dev_dbg(&port->dev, "baud requested = %u\n", baud);
320b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold	if (!baud)
321b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold		return;
322692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
3237e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	/* Set baudrate to nearest supported value */
3247e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
3257e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		if (baud_sup[i] > baud)
3267e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman			break;
3277e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	}
328692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
3297e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	if (i == ARRAY_SIZE(baud_sup))
3307e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i - 1];
3317e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
3327e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i - 1];
3337e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	else
3347e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i];
335692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
3367e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	/* type_0, type_1 only support up to 1228800 baud */
3377f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	if (spriv->type == TYPE_01)
338f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold		baud = min_t(speed_t, baud, 1228800);
339692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
34054dc5792ea933a3ff8c62a1f9ea9e4e6cbdd324aGreg Kroah-Hartman	if (baud <= 115200) {
341692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman		put_unaligned_le32(baud, buf);
342692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman	} else {
343692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman		/*
3441796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman		 * Apparently the formula for higher speeds is:
3451796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman		 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
346692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman		 */
3471796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman		unsigned tmp = 12000000 * 32 / baud;
3481796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman		buf[3] = 0x80;
349692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman		buf[2] = 0;
3501796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman		buf[1] = (tmp >= 256);
3511796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman		while (tmp >= 256) {
3521796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman			tmp >>= 2;
3531796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman			buf[1] <<= 1;
3541796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman		}
3551796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman		buf[0] = tmp;
356692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman	}
357692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
35815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	/* Save resulting baud rate */
359b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold	tty_encode_baud_rate(tty, baud, baud);
360f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold	dev_dbg(&port->dev, "baud set = %u\n", baud);
36115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold}
36215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
363383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_get_line_request(struct usb_serial_port *port,
364383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold							unsigned char buf[7])
365383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{
366383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	struct usb_device *udev = port->serial->dev;
367383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
368383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
369383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
370383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
371383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				0, 0, buf, 7, 100);
372383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	if (ret != 7) {
373383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
374383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
375383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (ret > 0)
376383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold			ret = -EIO;
377383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
378383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		return ret;
379383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	}
380383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
381383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);
382383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
383383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	return 0;
384383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold}
385383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
386383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_set_line_request(struct usb_serial_port *port,
387383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold							unsigned char buf[7])
388383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{
389383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	struct usb_device *udev = port->serial->dev;
390383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
391383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
392383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
393383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
394383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				0, 0, buf, 7, 100);
395383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	if (ret != 7) {
396383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
397383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
398383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (ret > 0)
399383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold			ret = -EIO;
400383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
401383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		return ret;
402383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	}
403383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
404383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);
405383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
406383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	return 0;
407383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold}
408383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
40915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_set_termios(struct tty_struct *tty,
41015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		struct usb_serial_port *port, struct ktermios *old_termios)
41115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold{
41215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct usb_serial *serial = port->serial;
41315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
41415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
41515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	unsigned long flags;
41615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	unsigned char *buf;
417383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
41815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	u8 control;
41915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
42015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
42115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		return;
42215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
42315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	buf = kzalloc(7, GFP_KERNEL);
42415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	if (!buf) {
42515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		/* Report back no change occurred */
42615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		if (old_termios)
42715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			tty->termios = *old_termios;
42815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		return;
42915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	}
43015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
431383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	pl2303_get_line_request(port, buf);
43215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
433a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	switch (C_CSIZE(tty)) {
434a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS5:
435a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 5;
436a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
437a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS6:
438a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 6;
439a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
440a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS7:
441a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 7;
442a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
443a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	default:
444a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS8:
445a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 8;
44615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	}
447a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
44815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
449692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman	/* For reference buf[0]:buf[3] baud rate value */
450692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman	pl2303_encode_baudrate(tty, port, &buf[0]);
45115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
45587265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CSTOPB(tty)) {
45687265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		/*
45787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		 * NOTE: Comply with "real" UARTs / RS232:
45829cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 *       use 1.5 instead of 2 stop bits with 5 data bits
45929cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 */
46087265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		if (C_CSIZE(tty) == CS5) {
46129cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 1;
462d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 1.5\n");
46329cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		} else {
46429cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 2;
465d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 2\n");
46629cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
469d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "stop bits = 1\n");
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47287265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_PARENB(tty)) {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
47887265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		if (C_PARODD(tty)) {
47987265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold			if (tty->termios.c_cflag & CMSPAR) {
4806dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 3;
481d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = mark\n");
4826dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
4836dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 1;
484d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = odd\n");
4856dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
48787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold			if (tty->termios.c_cflag & CMSPAR) {
4886dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 4;
489d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = space\n");
4906dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
4916dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 2;
492d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = even\n");
4936dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
497d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "parity = none\n");
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
500623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	/*
501623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * Some PL2303 are known to lose bytes if you change serial settings
502623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * even to the same values as before. Thus we actually need to filter
503623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * in this specific case.
504623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *
505623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * Note that the tty_termios_hw_change check above is not sufficient
506623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * as a previously requested baud rate may differ from the one
507623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * actually used (and stored in old_termios).
508623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *
509623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * NOTE: No additional locking needed for line_settings as it is
510623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *       only used in set_termios, which is serialised against itself.
511623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 */
512623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	if (!old_termios || memcmp(buf, priv->line_settings, 7)) {
513383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		ret = pl2303_set_line_request(port, buf);
514383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (!ret)
515623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold			memcpy(priv->line_settings, buf, 7);
516623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
52187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_BAUD(tty) == B0)
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
5232d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
528f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold		pl2303_set_control_lines(port, control);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
532372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
53387265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CRTSCTS(tty)) {
5347f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		if (spriv->type == TYPE_01)
535362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			pl2303_vendor_write(serial, 0x0, 0x41);
5367f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		else
5377f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold			pl2303_vendor_write(serial, 0x0, 0x61);
538715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
539362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 0x0, 0x0);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
541572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
542572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
543572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
544572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
545335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on)
546335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
547335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
548335f8514f200e63d689113d29cb7253a5c282967Alan Cox	unsigned long flags;
549335f8514f200e63d689113d29cb7253a5c282967Alan Cox	u8 control;
550335f8514f200e63d689113d29cb7253a5c282967Alan Cox
551335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_lock_irqsave(&priv->lock, flags);
552335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (on)
553335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
554335f8514f200e63d689113d29cb7253a5c282967Alan Cox	else
555335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
556335f8514f200e63d689113d29cb7253a5c282967Alan Cox	control = priv->line_control;
557335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_unlock_irqrestore(&priv->lock, flags);
558ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
559f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	pl2303_set_control_lines(port, control);
560335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
561335f8514f200e63d689113d29cb7253a5c282967Alan Cox
562335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port)
563572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
5648b0127b2082601e40295045414a8318f2c8ee5a0Johan Hovold	usb_serial_generic_close(port);
565572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
568a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
5718bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5747f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	if (spriv->type == TYPE_01) {
5751694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
5761694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
5773e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	} else {
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
579362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 8, 0);
580362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 9, 0);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
58495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (tty)
5852d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold		pl2303_set_termios(tty, port, NULL);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
587372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
589ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold		dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
590ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold			result);
591db6e9186c90188edea20aaa5161ea073440cc2a1Johan Hovold		return result;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
593d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
594f5230a53c1d551811b077ccad219105786da1becJohan Hovold	result = usb_serial_generic_open(tty, port);
595d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	if (result) {
596d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		usb_kill_urb(port->interrupt_in_urb);
597d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		return result;
598d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	}
599d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60320b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty,
604372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
60695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
6106f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	int ret;
6116fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
612372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
622372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6245ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	ret = pl2303_set_control_lines(port, control);
6255ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	if (ret)
6265ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold		return usb_translate_errors(ret);
6276f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold
6285ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	return 0;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63160b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int pl2303_tiocmget(struct tty_struct *tty)
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
63395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
640372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
643372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
652d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
657335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port)
658335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
659335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
660ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
661335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (priv->line_status & UART_DCD)
662335f8514f200e63d689113d29cb7253a5c282967Alan Cox		return 1;
663ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
664335f8514f200e63d689113d29cb7253a5c282967Alan Cox	return 0;
665335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
666335f8514f200e63d689113d29cb7253a5c282967Alan Cox
667824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovoldstatic int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg)
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
669824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold	struct usb_serial_port *port = tty->driver_data;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
676372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
678372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
6816d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold		interruptible_sleep_on(&port->port.delta_msr_wait);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
685372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
68640509ca982c00c4b70fc00be887509feca0bff15Johan Hovold		if (port->serial->disconnected)
68740509ca982c00c4b70fc00be887509feca0bff15Johan Hovold			return -EIO;
68840509ca982c00c4b70fc00be887509feca0bff15Johan Hovold
689372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
691372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
692372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6933a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		changed = prevstatus ^ status;
694372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
6983a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
70700a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int pl2303_ioctl(struct tty_struct *tty,
708372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
71067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	struct serial_struct ser;
71195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
712d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
71467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	case TIOCGSERIAL:
71567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		memset(&ser, 0, sizeof ser);
71667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.type = PORT_16654;
717e5b1e2062e0535e8ffef79bb34d857e21380d101Greg Kroah-Hartman		ser.line = port->minor;
7181143832eca8f1d64da7d85642c956ae9d25c69e1Greg Kroah-Hartman		ser.port = port->port_number;
71967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.baud_base = 460800;
72067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
72167b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		if (copy_to_user((void __user *)arg, &ser, sizeof ser))
72267b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas			return -EFAULT;
72367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
72467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		return 0;
7253a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	default:
7263a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		break;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
728ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
73295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state)
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
73495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
743ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
744d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
7453a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			state == BREAK_OFF ? "off" : "on");
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
747372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
748372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
749372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
751d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev, "error sending break = %d\n", result);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
75497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
75597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
75697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
75797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
758228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	struct usb_serial *serial = port->serial;
759228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
76097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
761d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	struct tty_struct *tty;
76297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
763228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	unsigned int status_idx = UART_STATE_INDEX;
764d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	u8 prev_line_status;
76597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
766228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0)
767228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		status_idx = 0;
76897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
769228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	if (actual_length < status_idx + 1)
770a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
77197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
7723a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	/* Save off the uart status for others to look at */
77397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
774d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	prev_line_status = priv->line_status;
77597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
77697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
777ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
778430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel	if (priv->line_status & UART_BREAK_ERROR)
779430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel		usb_serial_handle_break(port);
780ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
7816d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold	wake_up_interruptible(&port->port.delta_msr_wait);
782d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek
783d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty = tty_port_tty_get(&port->port);
784d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if (!tty)
785d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		return;
786d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if ((priv->line_status ^ prev_line_status) & UART_DCD)
787d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		usb_serial_handle_dcd_change(port, tty,
788d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek				priv->line_status & UART_DCD);
789d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty_kref_put(tty);
79097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7927d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
794cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
79697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
797461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
798461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
800461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
808d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
809d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
812d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
813d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81759d33f2fc2d63796296b1b76143e039d6e7cf532Greg Kroah-Hartman	usb_serial_debug_data(&port->dev, __func__,
818372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
819372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
82097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
823461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
824ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	if (retval) {
825d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev,
826372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
827441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, retval);
828ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	}
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovoldstatic void pl2303_process_read_urb(struct urb *urb)
832d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{
833f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct usb_serial_port *port = urb->context;
834f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
835d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	unsigned char *data = urb->transfer_buffer;
836d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	char tty_flag = TTY_NORMAL;
837f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	unsigned long flags;
838f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	u8 line_status;
839f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	int i;
840f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
841f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	/* update line status */
842f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_lock_irqsave(&priv->lock, flags);
843f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	line_status = priv->line_status;
844f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
845f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_unlock_irqrestore(&priv->lock, flags);
846f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
847f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	if (!urb->actual_length)
848f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold		return;
849f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
850ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	/*
851ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 * Break takes precedence over parity, which takes precedence over
852ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 * framing errors.
853ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 */
854d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_BREAK_ERROR)
855d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_BREAK;
856d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_PARITY_ERROR)
857d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_PARITY;
858d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_FRAME_ERROR)
859d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_FRAME;
860d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox
8613ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold	if (tty_flag != TTY_NORMAL)
8623ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold		dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
8633ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold								tty_flag);
864d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* overrun is special, not associated with a char */
865d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_OVERRUN_ERROR)
86692a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby		tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
8679388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold
868d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	if (port->port.console && port->sysrq) {
869d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		for (i = 0; i < urb->actual_length; ++i)
8706ee9f4b4affe751d313d2538999aeec134d413a6Dmitry Torokhov			if (!usb_serial_handle_sysrq_char(port, data[i]))
87192a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby				tty_insert_flip_char(&port->port, data[i],
87292a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby						tty_flag);
873d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	} else {
8742f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby		tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
875d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold							urb->actual_length);
8769388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold	}
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8782e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	tty_flip_buffer_push(&port->port);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
882572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
883572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
884572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
885572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
886572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
887572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
8887919c2fd9e07276403b9a4d9ae52305e0d70f923Johan Hovold	.bulk_in_size =		256,
8893efeaff6298290b36499532f0b4c87aa4bae8aefJohan Hovold	.bulk_out_size =	256,
890572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
891572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
892ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	.dtr_rts =		pl2303_dtr_rts,
893335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.carrier_raised =	pl2303_carrier_raised,
894572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
895572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
896572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
897572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
898572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
899824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold	.tiocmiwait =		pl2303_tiocmiwait,
900f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	.process_read_urb =	pl2303_process_read_urb,
901572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
902228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	.probe =		pl2303_probe,
903572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
904f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =		pl2303_release,
9058bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_probe =		pl2303_port_probe,
9068bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_remove =		pl2303_port_remove,
907572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
909f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = {
910f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern	&pl2303_device, NULL
911f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern};
912f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern
91368e24113457e437b1576670f2419b77ed0531e9eGreg Kroah-Hartmanmodule_usb_serial_driver(serial_drivers, id_table);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
915ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan HovoldMODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver");
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
917