pl2303.c revision 2f69335710884ae6112fc8196ebe29b5cda7b79b
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
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
293a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#include <linux/uaccess.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
31a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h"
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
397d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = {
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
423d861494729c70d9ebeb7d93caa107897925c355Peter Moulder	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
45b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
464be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
47727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
4818344a1cd5889d48dac67229fcf024ed300030d5Simone Contini	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
4996a3e79edff6f41b0f115a82f1a39d66218077a7Dario Lombardo	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
518a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
5758381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
66a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
68a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
69e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
70912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
71acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
72c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
73c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
746cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
75c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
76491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
773b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
78b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
798fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
802d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
819e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
82cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
837c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
84af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
858540d66615c39010168ab97eaafb476ec2851298Gianpaolo Cugola	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
86f36ecd5de93e4c85a9e3d25100c6e233155b12e5Jef Driesen	{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
8749276560c9004fce24c42e3c0ad75f34d956fc63Khanh-Dang Nguyen Thu Lam	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
8835904e6b5106fda51b04c8b8080c04466865415fPawel Ludwikow	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
899a61d72602771906e11a5944e8571f8006387b39Manuel Jander	{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
90598f0b703506da841d3459dc0c48506be14d1778Eric Benoit	{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
94372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1053a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST			0x23
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE			0x08
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_0,		/* don't know the difference between type 0 and */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_1,		/* type 1, until someone from prolific tells us... */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HX,		/* HX version of the pl2303 chip */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1368bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstruct pl2303_serial_private {
1378bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	enum pl2303_type type;
1388bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold};
1398bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t delta_msr_wait;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
147eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_read(__u16 value, __u16 index,
148eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial, unsigned char *buf)
149eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
150eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
151eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
152eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, buf, 1, 100);
153d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x  %d - %x\n",
154d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
155d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		res, buf[0]);
156eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
157eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
158eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
159eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_write(__u16 value, __u16 index,
160eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial)
161eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
162eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
163eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
164eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
165d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x  %d\n",
166d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
167d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		res);
168eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
169eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
170eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
171372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1738bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type = type_0;
1753e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	unsigned char *buf;
1768bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
1778bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
1788bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!spriv)
1798bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1813e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	buf = kmalloc(10, GFP_KERNEL);
1828bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!buf) {
1838bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		kfree(spriv);
1843e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		return -ENOMEM;
1858bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	}
1863e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serial->dev->descriptor.bDeviceClass == 0x02)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_0;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = HX;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0x00)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
195d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&serial->interface->dev, "device type: %d\n", type);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1978bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv->type = type;
1988bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_data(serial, spriv);
1993e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2003e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2013e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 0, serial);
2023e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2033e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
2043e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2053e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 1, serial);
2063e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2073e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
2083e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0, 1, serial);
2093e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(1, 0, serial);
2103e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	if (type == HX)
2113e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		pl2303_vendor_write(2, 0x44, serial);
2123e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	else
2133e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		pl2303_vendor_write(2, 0x24, serial);
2143e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2153e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2178bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2198bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic void pl2303_release(struct usb_serial *serial)
2208bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2218bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv;
2228bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2238bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv = usb_get_serial_data(serial);
2248bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(spriv);
2258bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2268bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2278bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_probe(struct usb_serial_port *port)
2288bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2298bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_private *priv;
2308bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2318bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2328bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!priv)
2338bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
2348bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2358bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spin_lock_init(&priv->lock);
2368bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	init_waitqueue_head(&priv->delta_msr_wait);
2378bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2388bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_port_data(port, priv);
2398bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2408bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2418bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2428bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2438bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_remove(struct usb_serial_port *port)
2448bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2458bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_private *priv;
2468bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2478bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	priv = usb_get_serial_port_data(port);
2488bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(priv);
2498bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2508bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int set_control_lines(struct usb_device *dev, u8 value)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
2563a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox
257372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
258372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
259372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
260d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
261d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		value, retval);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26595da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_set_termios(struct tty_struct *tty,
26695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		struct usb_serial_port *port, struct ktermios *old_termios)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
2698bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cflag;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
27725b8286805e856c8c7fda127018e31032c918015Frank Schaefer	const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
27825b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         4800, 7200, 9600, 14400, 19200, 28800, 38400,
27925b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         57600, 115200, 230400, 460800, 614400,
28025b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         921600, 1228800, 2457600, 3000000, 6000000 };
28125b8286805e856c8c7fda127018e31032c918015Frank Schaefer	int baud_floor, baud_ceil;
28225b8286805e856c8c7fda127018e31032c918015Frank Schaefer	int k;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
284bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	/* The PL2303 is reported to lose bytes if you change
285bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   serial settings even to the same values as before. Thus
286bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   we actually need to filter in this specific case */
287bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
288adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	if (!tty_termios_hw_change(&tty->termios, old_termios))
289bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox		return;
290bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
291adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	cflag = tty->termios.c_cflag;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
293372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	buf = kzalloc(7, GFP_KERNEL);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
295441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dev_err(&port->dev, "%s - out of memory.\n", __func__);
296a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox		/* Report back no change occurred */
297adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox		tty->termios = *old_termios;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
302372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
303372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
304d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x\n", i,
305372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSIZE) {
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (cflag & CSIZE) {
3093a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS5:
3103a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 5;
3113a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
3123a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS6:
3133a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 6;
3143a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
3153a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS7:
3163a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 7;
3173a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
3183a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		default:
3193a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS8:
3203a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 8;
3213a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
323d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32625b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* For reference buf[0]:buf[3] baud rate value */
32725b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* NOTE: Only the values defined in baud_sup are supported !
32825b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 *       => if unsupported values are set, the PL2303 seems to use
32925b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 *          9600 baud (at least my PL2303X always does)
33025b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 */
33195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	baud = tty_get_baud_rate(tty);
332d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "baud requested = %d\n", baud);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud) {
33425b8286805e856c8c7fda127018e31032c918015Frank Schaefer		/* Set baudrate to nearest supported value */
33525b8286805e856c8c7fda127018e31032c918015Frank Schaefer		for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
33625b8286805e856c8c7fda127018e31032c918015Frank Schaefer			if (baud_sup[k] / baud) {
33725b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud_ceil = baud_sup[k];
33825b8286805e856c8c7fda127018e31032c918015Frank Schaefer				if (k==0) {
33925b8286805e856c8c7fda127018e31032c918015Frank Schaefer					baud = baud_ceil;
34025b8286805e856c8c7fda127018e31032c918015Frank Schaefer				} else {
34125b8286805e856c8c7fda127018e31032c918015Frank Schaefer					baud_floor = baud_sup[k-1];
34225b8286805e856c8c7fda127018e31032c918015Frank Schaefer					if ((baud_ceil % baud)
34325b8286805e856c8c7fda127018e31032c918015Frank Schaefer					    > (baud % baud_floor))
34425b8286805e856c8c7fda127018e31032c918015Frank Schaefer						baud = baud_floor;
34525b8286805e856c8c7fda127018e31032c918015Frank Schaefer					else
34625b8286805e856c8c7fda127018e31032c918015Frank Schaefer						baud = baud_ceil;
34725b8286805e856c8c7fda127018e31032c918015Frank Schaefer				}
34825b8286805e856c8c7fda127018e31032c918015Frank Schaefer				break;
34925b8286805e856c8c7fda127018e31032c918015Frank Schaefer			}
35025b8286805e856c8c7fda127018e31032c918015Frank Schaefer		}
35125b8286805e856c8c7fda127018e31032c918015Frank Schaefer		if (baud > 1228800) {
35225b8286805e856c8c7fda127018e31032c918015Frank Schaefer			/* type_0, type_1 only support up to 1228800 baud */
3538bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold			if (spriv->type != HX)
35425b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud = 1228800;
35525b8286805e856c8c7fda127018e31032c918015Frank Schaefer			else if (baud > 6000000)
35625b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud = 6000000;
35725b8286805e856c8c7fda127018e31032c918015Frank Schaefer		}
358d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "baud set = %d\n", baud);
3598d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński		if (baud <= 115200) {
3608d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[0] = baud & 0xff;
3618d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[1] = (baud >> 8) & 0xff;
3628d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[2] = (baud >> 16) & 0xff;
3638d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[3] = (baud >> 24) & 0xff;
3648d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński		} else {
3658d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			/* apparently the formula for higher speeds is:
3668d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
3678d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			 */
3688d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			unsigned tmp = 12*1000*1000*32 / baud;
3698d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[3] = 0x80;
3708d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[2] = 0;
3718d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[1] = (tmp >= 256);
3728d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			while (tmp >= 256) {
3738d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński				tmp >>= 2;
3748d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński				buf[1] <<= 1;
3758d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			}
3768d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[0] = tmp;
3778d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński		}
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSTOPB) {
38429cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		/* NOTE: Comply with "real" UARTs / RS232:
38529cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 *       use 1.5 instead of 2 stop bits with 5 data bits
38629cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 */
38729cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		if ((cflag & CSIZE) == CS5) {
38829cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 1;
389d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 1.5\n");
39029cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		} else {
39129cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 2;
392d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 2\n");
39329cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		}
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
396d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "stop bits = 1\n");
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & PARENB) {
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cflag & PARODD) {
4066dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			if (cflag & CMSPAR) {
4076dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 3;
408d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = mark\n");
4096dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
4106dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 1;
411d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = odd\n");
4126dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4146dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			if (cflag & CMSPAR) {
4156dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 4;
416d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = space\n");
4176dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
4186dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 2;
419d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = even\n");
4206dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
424d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "parity = none\n");
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
427372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
428372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
429372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
430d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "0x21:0x20:0:0  %d\n", i);
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cflag & CBAUD) == B0)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
437ce5c9851855bab190c9a142761d54ba583ab094cJohan Hovold	else if ((old_termios->c_cflag & CBAUD) == B0)
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_control_lines(serial->dev, control);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
446372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
449372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
450372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
451372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
452d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x\n", i,
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CRTSCTS) {
4568bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		if (spriv->type == HX)
457eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x61, serial);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
459eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x41, serial);
460715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
461eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(0x0, 0x0, serial);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
463572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
46425b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* Save resulting baud rate */
465df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox	if (baud)
46695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		tty_encode_baud_rate(tty, baud, baud);
467df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox
468572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
469572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
470572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
471335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on)
472335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
473335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
474335f8514f200e63d689113d29cb7253a5c282967Alan Cox	unsigned long flags;
475335f8514f200e63d689113d29cb7253a5c282967Alan Cox	u8 control;
476335f8514f200e63d689113d29cb7253a5c282967Alan Cox
477335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_lock_irqsave(&priv->lock, flags);
478335f8514f200e63d689113d29cb7253a5c282967Alan Cox	/* Change DTR and RTS */
479335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (on)
480335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
481335f8514f200e63d689113d29cb7253a5c282967Alan Cox	else
482335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
483335f8514f200e63d689113d29cb7253a5c282967Alan Cox	control = priv->line_control;
484335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_unlock_irqrestore(&priv->lock, flags);
485335f8514f200e63d689113d29cb7253a5c282967Alan Cox	set_control_lines(port->serial->dev, control);
486335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
487335f8514f200e63d689113d29cb7253a5c282967Alan Cox
488335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port)
489572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
4908b0127b2082601e40295045414a8318f2c8ee5a0Johan Hovold	usb_serial_generic_close(port);
491572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
494a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
496606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios tmp_termios;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
4988bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5018bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (spriv->type != HX) {
5021694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
5031694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
5043e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	} else {
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
506eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(8, 0, serial);
507eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(9, 0, serial);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
51195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (tty)
51295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		pl2303_set_termios(tty, port, &tmp_termios);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
514372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
516372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
517441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
518db6e9186c90188edea20aaa5161ea073440cc2a1Johan Hovold		return result;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
520d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
521f5230a53c1d551811b077ccad219105786da1becJohan Hovold	result = usb_serial_generic_open(tty, port);
522d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	if (result) {
523d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		usb_kill_urb(port->interrupt_in_urb);
524d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		return result;
525d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	}
526d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
527335f8514f200e63d689113d29cb7253a5c282967Alan Cox	port->port.drain_delay = 256;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53120b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty,
532372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
53495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
5356f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	struct usb_serial *serial = port->serial;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
5396f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	int ret;
5406fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
541372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
551372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5536f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	mutex_lock(&serial->disc_mutex);
5546f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	if (!serial->disconnected)
5556f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold		ret = set_control_lines(serial->dev, control);
5566f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	else
5576f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold		ret = -ENODEV;
5586f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	mutex_unlock(&serial->disc_mutex);
5596f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold
5606f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	return ret;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56360b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int pl2303_tiocmget(struct tty_struct *tty)
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
56595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
572372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
575372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
584d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
589335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port)
590335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
591335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
592335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (priv->line_status & UART_DCD)
593335f8514f200e63d689113d29cb7253a5c282967Alan Cox		return 1;
594335f8514f200e63d689113d29cb7253a5c282967Alan Cox	return 0;
595335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
596335f8514f200e63d689113d29cb7253a5c282967Alan Cox
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
605372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
607372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		interruptible_sleep_on(&priv->delta_msr_wait);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
614372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
615372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
617372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
618372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6193a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		changed = prevstatus ^ status;
620372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
6243a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63300a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int pl2303_ioctl(struct tty_struct *tty,
634372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
63667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	struct serial_struct ser;
63795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
638d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman
639d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
64267b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	case TIOCGSERIAL:
64367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		memset(&ser, 0, sizeof ser);
64467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.type = PORT_16654;
64567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.line = port->serial->minor;
64667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.port = port->number;
64767b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.baud_base = 460800;
64867b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
64967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		if (copy_to_user((void __user *)arg, &ser, sizeof ser))
65067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas			return -EFAULT;
65167b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
65267b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		return 0;
65367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
6543a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	case TIOCMIWAIT:
655d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
6563a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		return wait_modem_info(port, arg);
6573a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	default:
658d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
6593a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		break;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66495da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state)
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
66695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
675d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
6763a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			state == BREAK_OFF ? "off" : "on");
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
678372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
679372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
680372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
682d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev, "error sending break = %d\n", result);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
68597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
68697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
68797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
68897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
68997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
69097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
691d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	struct tty_struct *tty;
69297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
69397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 status_idx = UART_STATE;
69495f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier	u8 length = UART_STATE + 1;
695d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	u8 prev_line_status;
6969c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	u16 idv, idp;
69797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
6989c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
6999c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
7009c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7019c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7029c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	if (idv == SIEMENS_VENDOR_ID) {
7039c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		if (idp == SIEMENS_PRODUCT_ID_X65 ||
7049c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_SX1 ||
7059c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_X75) {
7069c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7079c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			length = 1;
7089c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			status_idx = 0;
7099c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		}
71097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	}
71197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
71297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if (actual_length < length)
713a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
71497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
7153a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	/* Save off the uart status for others to look at */
71697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
717d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	prev_line_status = priv->line_status;
71897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
71997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
720430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel	if (priv->line_status & UART_BREAK_ERROR)
721430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel		usb_serial_handle_break(port);
722372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
723d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek
724d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty = tty_port_tty_get(&port->port);
725d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if (!tty)
726d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		return;
727d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if ((priv->line_status ^ prev_line_status) & UART_DCD)
728d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		usb_serial_handle_dcd_change(port, tty,
729d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek				priv->line_status & UART_DCD);
730d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty_kref_put(tty);
73197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7337d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
735cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
73797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
738461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
739461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
749d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
750d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
753d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
754d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
75859d33f2fc2d63796296b1b76143e039d6e7cf532Greg Kroah-Hartman	usb_serial_debug_data(&port->dev, __func__,
759372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
760372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
76197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
764461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
765461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (retval)
766d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev,
767372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
768441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, retval);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovoldstatic void pl2303_process_read_urb(struct urb *urb)
772d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{
773f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct usb_serial_port *port = urb->context;
774f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
775f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct tty_struct *tty;
776d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	unsigned char *data = urb->transfer_buffer;
777d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	char tty_flag = TTY_NORMAL;
778f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	unsigned long flags;
779f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	u8 line_status;
780f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	int i;
781f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
782f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	/* update line status */
783f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_lock_irqsave(&priv->lock, flags);
784f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	line_status = priv->line_status;
785f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
786f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_unlock_irqrestore(&priv->lock, flags);
787f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	wake_up_interruptible(&priv->delta_msr_wait);
788f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
789f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	if (!urb->actual_length)
790f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold		return;
791f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
792f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	tty = tty_port_tty_get(&port->port);
793f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	if (!tty)
794f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold		return;
795f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
796d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* break takes precedence over parity, */
797d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* which takes precedence over framing errors */
798d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_BREAK_ERROR)
799d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_BREAK;
800d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_PARITY_ERROR)
801d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_PARITY;
802d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_FRAME_ERROR)
803d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_FRAME;
804d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
805d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox
806d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* overrun is special, not associated with a char */
807d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_OVERRUN_ERROR)
808d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
8099388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold
810d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	if (port->port.console && port->sysrq) {
811d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		for (i = 0; i < urb->actual_length; ++i)
8126ee9f4b4affe751d313d2538999aeec134d413a6Dmitry Torokhov			if (!usb_serial_handle_sysrq_char(port, data[i]))
813d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox				tty_insert_flip_char(tty, data[i], tty_flag);
814d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	} else {
8152f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby		tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
816d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold							urb->actual_length);
8179388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold	}
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
819f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	tty_flip_buffer_push(tty);
8204a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty_kref_put(tty);
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
823572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */
824572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
825572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
826572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
827572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
828572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
829572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
830572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
8317919c2fd9e07276403b9a4d9ae52305e0d70f923Johan Hovold	.bulk_in_size =		256,
8323efeaff6298290b36499532f0b4c87aa4bae8aefJohan Hovold	.bulk_out_size =	256,
833572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
834572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
835335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.dtr_rts = 		pl2303_dtr_rts,
836335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.carrier_raised =	pl2303_carrier_raised,
837572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
838572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
839572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
840572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
841572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
842f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	.process_read_urb =	pl2303_process_read_urb,
843572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
844572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
845f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =		pl2303_release,
8468bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_probe =		pl2303_port_probe,
8478bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_remove =		pl2303_port_remove,
848572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
850f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = {
851f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern	&pl2303_device, NULL
852f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern};
853f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern
85468e24113457e437b1576670f2419b77ed0531e9eGreg Kroah-Hartmanmodule_usb_serial_driver(serial_drivers, id_table);
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
858