pl2303.c revision b16c02fbfb963fa2941b7517ebf1f8a21946775e
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/slab.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
273a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#include <linux/uaccess.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
29a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h>
30b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold#include <asm/unaligned.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h"
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
34228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold#define PL2303_QUIRK_UART_STATE_IDX0		BIT(0)
3523c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold#define PL2303_QUIRK_LEGACY			BIT(1)
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) },
86b16c02fbfb963fa2941b7517ebf1f8a21946775eAaron Sanders	{ USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) },
87b16c02fbfb963fa2941b7517ebf1f8a21946775eAaron Sanders	{ USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) },
88b16c02fbfb963fa2941b7517ebf1f8a21946775eAaron Sanders	{ USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) },
898540d66615c39010168ab97eaafb476ec2851298Gianpaolo Cugola	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
90f36ecd5de93e4c85a9e3d25100c6e233155b12e5Jef Driesen	{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
9149276560c9004fce24c42e3c0ad75f34d956fc63Khanh-Dang Nguyen Thu Lam	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
9235904e6b5106fda51b04c8b8080c04466865415fPawel Ludwikow	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
939a61d72602771906e11a5944e8571f8006387b39Manuel Jander	{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
94598f0b703506da841d3459dc0c48506be14d1778Eric Benoit	{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1093a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST			0x23
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
122228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold#define UART_STATE_INDEX		8
123dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold#define UART_STATE_MSR_MASK		0x8b
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1367f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	TYPE_01,	/* Type 0 and 1 (difference unknown) */
1377f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	TYPE_HX,	/* HX version of the pl2303 chip */
138359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	TYPE_COUNT
139359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold};
140359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold
141359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovoldstruct pl2303_type_data {
142359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	speed_t max_baud_rate;
143359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	unsigned long quirks;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1468bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstruct pl2303_serial_private {
147b693468155f5650dcaf01089ecf2b56ab66f9271Johan Hovold	const struct pl2303_type_data *type;
148228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	unsigned long quirks;
1498bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold};
1508bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
155623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold
156623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	u8 line_settings[7];
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159b693468155f5650dcaf01089ecf2b56ab66f9271Johan Hovoldstatic const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
160359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	[TYPE_01] = {
161359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold		.max_baud_rate =	1228800,
162359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold		.quirks =		PL2303_QUIRK_LEGACY,
163359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	},
164359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold};
165359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold
166362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_read(struct usb_serial *serial, u16 value,
167362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold							unsigned char buf[1])
168eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
169362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	struct device *dev = &serial->interface->dev;
170ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	int res;
171ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
172ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
173eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
174362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			value, 0, buf, 1, 100);
175362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	if (res != 1) {
176362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__,
177362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold								value, res);
178362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		if (res >= 0)
179362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			res = -EIO;
180362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold
181362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		return res;
182362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	}
183ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
184362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]);
185ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
186362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	return 0;
187eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
188eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
189362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
190eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
191362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	struct device *dev = &serial->interface->dev;
192ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	int res;
193ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
194362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index);
195362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold
196ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
197eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
198eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
199362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	if (res) {
200362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__,
201362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold								value, res);
202362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		return res;
203362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	}
204ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
205362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	return 0;
206eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
207eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
208228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovoldstatic int pl2303_probe(struct usb_serial *serial,
209228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold					const struct usb_device_id *id)
210228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold{
211228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	usb_set_serial_data(serial, (void *)id->driver_info);
212228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
213228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	return 0;
214228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold}
215228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
216372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2188bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv;
2197f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	enum pl2303_type type = TYPE_01;
2203e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	unsigned char *buf;
2218bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2228bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
2238bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!spriv)
2248bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
226362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	buf = kmalloc(1, GFP_KERNEL);
2278bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!buf) {
2288bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		kfree(spriv);
2293e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		return -ENOMEM;
2308bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	}
2313e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
232b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	if (serial->dev->descriptor.bDeviceClass == 0x02)
2337f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 0 */
234b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
2357f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_HX;
236281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman	else if (serial->dev->descriptor.bDeviceClass == 0x00)
2377f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 1 */
238281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
2397f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		type = TYPE_01;		/* type 1 */
240b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	dev_dbg(&serial->interface->dev, "device type: %d\n", type);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
242359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	spriv->type = &pl2303_type_data[type];
243228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	spriv->quirks = (unsigned long)usb_get_serial_data(serial);
244359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold	spriv->quirks |= spriv->type->quirks;
245228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold
2468bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_data(serial, spriv);
2473e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
248362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
249362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0x0404, 0);
250362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
251362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8383, buf);
252362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
253362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0x0404, 1);
254362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8484, buf);
255362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_read(serial, 0x8383, buf);
256362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 0, 1);
257362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold	pl2303_vendor_write(serial, 1, 0);
25823c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold	if (spriv->quirks & PL2303_QUIRK_LEGACY)
259362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 2, 0x24);
2607f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold	else
2617f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		pl2303_vendor_write(serial, 2, 0x44);
2623e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2633e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
264ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2668bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2688bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic void pl2303_release(struct usb_serial *serial)
2698bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
270ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
2718bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2728bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(spriv);
2738bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2748bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2758bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_probe(struct usb_serial_port *port)
2768bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2778bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_private *priv;
2788bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2798bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2808bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!priv)
2818bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
2828bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2838bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spin_lock_init(&priv->lock);
2848bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2858bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_port_data(port, priv);
2868bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
287d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold	port->port.drain_delay = 256;
288d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold
2898bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2908bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2918bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2928bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_remove(struct usb_serial_port *port)
2938bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
294ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
2958bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2968bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(priv);
2978bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2988bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovoldstatic int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
303f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	struct usb_device *dev = port->serial->dev;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
3053a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox
306a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold	dev_dbg(&port->dev, "%s - %02x\n", __func__, value);
307a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold
308372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
309372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
310372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
311a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold	if (retval)
312a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, retval);
313ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31759afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold/*
3185d85045f4b082800beb384094fc67fa0d2096563Johan Hovold * Returns the nearest supported baud rate that can be set directly without
3195d85045f4b082800beb384094fc67fa0d2096563Johan Hovold * using divisors.
32059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold */
32159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovoldstatic speed_t pl2303_get_supported_baud_rate(speed_t baud)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	static const speed_t baud_sup[] = {
32459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold		75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600,
32559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold		14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800,
3265d85045f4b082800beb384094fc67fa0d2096563Johan Hovold		614400, 921600, 1228800, 2457600, 3000000, 6000000
32759afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	};
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	unsigned i;
330692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
3317e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
3327e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		if (baud_sup[i] > baud)
3337e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman			break;
3347e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	}
335692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
3367e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	if (i == ARRAY_SIZE(baud_sup))
3377e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i - 1];
3387e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
3397e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i - 1];
3407e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman	else
3417e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman		baud = baud_sup[i];
342692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
34359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	return baud;
34459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold}
34559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold
34620b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold/*
34720b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold * NOTE: If unsupported baud rates are set directly, the PL2303 seems to
34820b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold *       use 9600 baud.
34920b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold */
35020b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovoldstatic speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4],
35120b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold								speed_t baud)
35220b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold{
35320b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold	put_unaligned_le32(baud, buf);
35420b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold
35520b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold	return baud;
35620b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold}
35720b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold
358c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovoldstatic speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
359c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold								speed_t baud)
360c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold{
361c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	unsigned int tmp;
362c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold
363c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	/*
364c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	 * Apparently the formula is:
365c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
366c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	 */
367c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	tmp = 12000000 * 32 / baud;
368c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	buf[3] = 0x80;
369c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	buf[2] = 0;
370c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	buf[1] = (tmp >= 256);
371c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	while (tmp >= 256) {
372c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold		tmp >>= 2;
373c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold		buf[1] <<= 1;
374c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	}
375c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	buf[0] = tmp;
376c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold
377c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold	return baud;
378c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold}
379c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold
38059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovoldstatic void pl2303_encode_baud_rate(struct tty_struct *tty,
38159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold					struct usb_serial_port *port,
38259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold					u8 buf[4])
38359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold{
38459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	struct usb_serial *serial = port->serial;
38559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
3865d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	speed_t	baud_sup;
38759afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	speed_t baud;
38859afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold
38959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	baud = tty_get_baud_rate(tty);
39059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	dev_dbg(&port->dev, "baud requested = %u\n", baud);
39159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold	if (!baud)
39259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold		return;
393871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold
394871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold	if (spriv->type->max_baud_rate)
395871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold		baud = min_t(speed_t, baud, spriv->type->max_baud_rate);
3965d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	/*
3975d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	 * Set baud rate to nearest supported value.
3985d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	 *
3995d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	 * NOTE: Baud rate 500k can only be set using divisors.
4005d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	 */
4015d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	baud_sup = pl2303_get_supported_baud_rate(baud);
40220b4c787199f4fcf0fae5ed78a4ff0104e2afaa3Johan Hovold
4035d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	if (baud == 500000)
404c82c6d45a2fc882fedfde517ba86690b2d5ed555Johan Hovold		baud = pl2303_encode_baud_rate_divisor(buf, baud);
4055d85045f4b082800beb384094fc67fa0d2096563Johan Hovold	else
4065d85045f4b082800beb384094fc67fa0d2096563Johan Hovold		baud = pl2303_encode_baud_rate_direct(buf, baud_sup);
407692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman
40815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	/* Save resulting baud rate */
409b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold	tty_encode_baud_rate(tty, baud, baud);
410f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold	dev_dbg(&port->dev, "baud set = %u\n", baud);
41115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold}
41215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
413383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_get_line_request(struct usb_serial_port *port,
414383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold							unsigned char buf[7])
415383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{
416383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	struct usb_device *udev = port->serial->dev;
417383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
418383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
419383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
420383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
421383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				0, 0, buf, 7, 100);
422383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	if (ret != 7) {
423383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
424383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
425383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (ret > 0)
426383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold			ret = -EIO;
427383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
428383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		return ret;
429383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	}
430383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
431383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);
432383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
433383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	return 0;
434383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold}
435383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
436383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_set_line_request(struct usb_serial_port *port,
437383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold							unsigned char buf[7])
438383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{
439383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	struct usb_device *udev = port->serial->dev;
440383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
441383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
442383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
443383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
444383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold				0, 0, buf, 7, 100);
445383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	if (ret != 7) {
446383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
447383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
448383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (ret > 0)
449383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold			ret = -EIO;
450383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
451383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		return ret;
452383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	}
453383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
454383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);
455383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
456383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	return 0;
457383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold}
458383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold
45915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_set_termios(struct tty_struct *tty,
46015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		struct usb_serial_port *port, struct ktermios *old_termios)
46115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold{
46215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct usb_serial *serial = port->serial;
46315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
46415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
46515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	unsigned long flags;
46615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	unsigned char *buf;
467383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	int ret;
46815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	u8 control;
46915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
47015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
47115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		return;
47215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
47315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	buf = kzalloc(7, GFP_KERNEL);
47415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	if (!buf) {
47515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		/* Report back no change occurred */
47615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		if (old_termios)
47715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			tty->termios = *old_termios;
47815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		return;
47915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	}
48015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
481383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold	pl2303_get_line_request(port, buf);
48215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
483a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	switch (C_CSIZE(tty)) {
484a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS5:
485a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 5;
486a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
487a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS6:
488a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 6;
489a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
490a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS7:
491a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 7;
492a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		break;
493a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	default:
494a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	case CS8:
495a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner		buf[6] = 8;
49615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	}
497a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner	dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
49815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
499692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman	/* For reference buf[0]:buf[3] baud rate value */
50079816824c1ae73542d9523283ce353142b67563eJohan Hovold	pl2303_encode_baud_rate(tty, port, &buf[0]);
50115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
50587265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CSTOPB(tty)) {
50687265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		/*
50787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		 * NOTE: Comply with "real" UARTs / RS232:
50829cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 *       use 1.5 instead of 2 stop bits with 5 data bits
50929cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 */
51087265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		if (C_CSIZE(tty) == CS5) {
51129cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 1;
512d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 1.5\n");
51329cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		} else {
51429cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 2;
515d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 2\n");
51629cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
519d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "stop bits = 1\n");
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52287265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_PARENB(tty)) {
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
52887265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		if (C_PARODD(tty)) {
529619c43543a946dd2f094d2f1bfc81a3fd48356d8Johan Hovold			if (C_CMSPAR(tty)) {
5306dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 3;
531d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = mark\n");
5326dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
5336dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 1;
534d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = odd\n");
5356dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
537619c43543a946dd2f094d2f1bfc81a3fd48356d8Johan Hovold			if (C_CMSPAR(tty)) {
5386dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 4;
539d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = space\n");
5406dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
5416dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 2;
542d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = even\n");
5436dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
547d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "parity = none\n");
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
550623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	/*
551623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * Some PL2303 are known to lose bytes if you change serial settings
552623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * even to the same values as before. Thus we actually need to filter
553623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * in this specific case.
554623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *
555623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * Note that the tty_termios_hw_change check above is not sufficient
556623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * as a previously requested baud rate may differ from the one
557623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * actually used (and stored in old_termios).
558623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *
559623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 * NOTE: No additional locking needed for line_settings as it is
560623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 *       only used in set_termios, which is serialised against itself.
561623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	 */
562623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	if (!old_termios || memcmp(buf, priv->line_settings, 7)) {
563383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		ret = pl2303_set_line_request(port, buf);
564383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold		if (!ret)
565623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold			memcpy(priv->line_settings, buf, 7);
566623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold	}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
57187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_BAUD(tty) == B0)
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
5732d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
578f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold		pl2303_set_control_lines(port, control);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
582372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
58387265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CRTSCTS(tty)) {
58423c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold		if (spriv->quirks & PL2303_QUIRK_LEGACY)
585362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold			pl2303_vendor_write(serial, 0x0, 0x41);
5867f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold		else
5877f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold			pl2303_vendor_write(serial, 0x0, 0x61);
588715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
589362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 0x0, 0x0);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
591572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
592572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
593572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
594572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
595335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on)
596335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
597335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
598335f8514f200e63d689113d29cb7253a5c282967Alan Cox	unsigned long flags;
599335f8514f200e63d689113d29cb7253a5c282967Alan Cox	u8 control;
600335f8514f200e63d689113d29cb7253a5c282967Alan Cox
601335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_lock_irqsave(&priv->lock, flags);
602335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (on)
603335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
604335f8514f200e63d689113d29cb7253a5c282967Alan Cox	else
605335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
606335f8514f200e63d689113d29cb7253a5c282967Alan Cox	control = priv->line_control;
607335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_unlock_irqrestore(&priv->lock, flags);
608ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
609f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	pl2303_set_control_lines(port, control);
610335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
611335f8514f200e63d689113d29cb7253a5c282967Alan Cox
612335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port)
613572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
6148b0127b2082601e40295045414a8318f2c8ee5a0Johan Hovold	usb_serial_generic_close(port);
615572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
618a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
6218bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62423c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold	if (spriv->quirks & PL2303_QUIRK_LEGACY) {
6251694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
6261694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
6273e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	} else {
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
629362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 8, 0);
630362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold		pl2303_vendor_write(serial, 9, 0);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
63495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (tty)
6352d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold		pl2303_set_termios(tty, port, NULL);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
637372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
639ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold		dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
640ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold			result);
641db6e9186c90188edea20aaa5161ea073440cc2a1Johan Hovold		return result;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
643d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
644f5230a53c1d551811b077ccad219105786da1becJohan Hovold	result = usb_serial_generic_open(tty, port);
645d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	if (result) {
646d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		usb_kill_urb(port->interrupt_in_urb);
647d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		return result;
648d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	}
649d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
65320b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty,
654372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
65695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
6606f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	int ret;
6616fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
662372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
672372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6745ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	ret = pl2303_set_control_lines(port, control);
6755ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	if (ret)
6765ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold		return usb_translate_errors(ret);
6776f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold
6785ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	return 0;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
68160b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int pl2303_tiocmget(struct tty_struct *tty)
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
68395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
690372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
693372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
702d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
707335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port)
708335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
709335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
710ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
711335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (priv->line_status & UART_DCD)
712335f8514f200e63d689113d29cb7253a5c282967Alan Cox		return 1;
713ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
714335f8514f200e63d689113d29cb7253a5c282967Alan Cox	return 0;
715335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
716335f8514f200e63d689113d29cb7253a5c282967Alan Cox
71700a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int pl2303_ioctl(struct tty_struct *tty,
718372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
72067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	struct serial_struct ser;
72195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
722d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
72467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	case TIOCGSERIAL:
72567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		memset(&ser, 0, sizeof ser);
72667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.type = PORT_16654;
727e5b1e2062e0535e8ffef79bb34d857e21380d101Greg Kroah-Hartman		ser.line = port->minor;
7281143832eca8f1d64da7d85642c956ae9d25c69e1Greg Kroah-Hartman		ser.port = port->port_number;
72967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.baud_base = 460800;
73067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
73167b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		if (copy_to_user((void __user *)arg, &ser, sizeof ser))
73267b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas			return -EFAULT;
73367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
73467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		return 0;
7353a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	default:
7363a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		break;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
738ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
74295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state)
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
74495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
753ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
754d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
7553a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			state == BREAK_OFF ? "off" : "on");
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
757372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
758372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
759372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
761d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev, "error sending break = %d\n", result);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
76597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
76697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
76797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
768228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	struct usb_serial *serial = port->serial;
769228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
77097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
771d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	struct tty_struct *tty;
77297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
773228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	unsigned int status_idx = UART_STATE_INDEX;
7746020c3bec359873c1e4081785f220db99694c4e4Johan Hovold	u8 status;
7756020c3bec359873c1e4081785f220db99694c4e4Johan Hovold	u8 delta;
77697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
777228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0)
778228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold		status_idx = 0;
77997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
780228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	if (actual_length < status_idx + 1)
781a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
78297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
7836020c3bec359873c1e4081785f220db99694c4e4Johan Hovold	status = data[status_idx];
7846020c3bec359873c1e4081785f220db99694c4e4Johan Hovold
7853a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	/* Save off the uart status for others to look at */
78697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
7876020c3bec359873c1e4081785f220db99694c4e4Johan Hovold	delta = priv->line_status ^ status;
7886020c3bec359873c1e4081785f220db99694c4e4Johan Hovold	priv->line_status = status;
78997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
790ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
7916020c3bec359873c1e4081785f220db99694c4e4Johan Hovold	if (status & UART_BREAK_ERROR)
792430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel		usb_serial_handle_break(port);
793ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold
794dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold	if (delta & UART_STATE_MSR_MASK) {
795a4bcb2945926901bbacf978eb0c0fdda5b327dc7Johan Hovold		if (delta & UART_CTS)
796a4bcb2945926901bbacf978eb0c0fdda5b327dc7Johan Hovold			port->icount.cts++;
797a4bcb2945926901bbacf978eb0c0fdda5b327dc7Johan Hovold		if (delta & UART_DSR)
798a4bcb2945926901bbacf978eb0c0fdda5b327dc7Johan Hovold			port->icount.dsr++;
799a4bcb2945926901bbacf978eb0c0fdda5b327dc7Johan Hovold		if (delta & UART_RING)
800a4bcb2945926901bbacf978eb0c0fdda5b327dc7Johan Hovold			port->icount.rng++;
801dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold		if (delta & UART_DCD) {
802a4bcb2945926901bbacf978eb0c0fdda5b327dc7Johan Hovold			port->icount.dcd++;
803dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold			tty = tty_port_tty_get(&port->port);
804dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold			if (tty) {
805dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold				usb_serial_handle_dcd_change(port, tty,
8066020c3bec359873c1e4081785f220db99694c4e4Johan Hovold							status & UART_DCD);
807dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold				tty_kref_put(tty);
808dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold			}
8096020c3bec359873c1e4081785f220db99694c4e4Johan Hovold		}
810dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold
811dbfd2866ac36bab52a4f37384e935eb5df76ad60Johan Hovold		wake_up_interruptible(&port->port.delta_msr_wait);
8126020c3bec359873c1e4081785f220db99694c4e4Johan Hovold	}
81397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8157d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
817cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
81997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
820461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
821461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
823461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
831d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
832d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
835d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
836d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
84059d33f2fc2d63796296b1b76143e039d6e7cf532Greg Kroah-Hartman	usb_serial_debug_data(&port->dev, __func__,
841372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
842372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
84397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
846461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
847ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	if (retval) {
848d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev,
849372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
850441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, retval);
851ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	}
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
854f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovoldstatic void pl2303_process_read_urb(struct urb *urb)
855d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{
856f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct usb_serial_port *port = urb->context;
857f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
858d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	unsigned char *data = urb->transfer_buffer;
859d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	char tty_flag = TTY_NORMAL;
860f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	unsigned long flags;
861f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	u8 line_status;
862f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	int i;
863f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
864f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	/* update line status */
865f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_lock_irqsave(&priv->lock, flags);
866f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	line_status = priv->line_status;
867f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
868f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_unlock_irqrestore(&priv->lock, flags);
869f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
870f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	if (!urb->actual_length)
871f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold		return;
872f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
873ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	/*
874ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 * Break takes precedence over parity, which takes precedence over
875ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 * framing errors.
876ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	 */
877d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_BREAK_ERROR)
878d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_BREAK;
879d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_PARITY_ERROR)
880d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_PARITY;
881d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_FRAME_ERROR)
882d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_FRAME;
883d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox
8843ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold	if (tty_flag != TTY_NORMAL)
8853ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold		dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
8863ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold								tty_flag);
887d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* overrun is special, not associated with a char */
888d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_OVERRUN_ERROR)
88992a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby		tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
8909388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold
891d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	if (port->port.console && port->sysrq) {
892d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		for (i = 0; i < urb->actual_length; ++i)
8936ee9f4b4affe751d313d2538999aeec134d413a6Dmitry Torokhov			if (!usb_serial_handle_sysrq_char(port, data[i]))
89492a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby				tty_insert_flip_char(&port->port, data[i],
89592a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby						tty_flag);
896d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	} else {
8972f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby		tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
898d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold							urb->actual_length);
8999388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold	}
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9012e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	tty_flip_buffer_push(&port->port);
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
904572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
905572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
906572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
907572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
908572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
909572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
910572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
9117919c2fd9e07276403b9a4d9ae52305e0d70f923Johan Hovold	.bulk_in_size =		256,
9123efeaff6298290b36499532f0b4c87aa4bae8aefJohan Hovold	.bulk_out_size =	256,
913572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
914572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
915ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold	.dtr_rts =		pl2303_dtr_rts,
916335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.carrier_raised =	pl2303_carrier_raised,
917572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
918572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
919572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
920572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
921572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
922a4bcb2945926901bbacf978eb0c0fdda5b327dc7Johan Hovold	.tiocmiwait =		usb_serial_generic_tiocmiwait,
923f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	.process_read_urb =	pl2303_process_read_urb,
924572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
925228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold	.probe =		pl2303_probe,
926572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
927f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =		pl2303_release,
9288bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_probe =		pl2303_port_probe,
9298bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_remove =		pl2303_port_remove,
930572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
932f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = {
933f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern	&pl2303_device, NULL
934f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern};
935f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern
93668e24113457e437b1576670f2419b77ed0531e9eGreg Kroah-Hartmanmodule_usb_serial_driver(serial_drivers, id_table);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
938ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan HovoldMODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver");
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
940