pl2303.c revision 90ab5ee94171b3e28de6bb42ee30b527014e0be7
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
3990ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool debug;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_CLOSING_WAIT	(30*HZ)
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
437d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = {
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
463d861494729c70d9ebeb7d93caa107897925c355Peter Moulder	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
49b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
504be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
51727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
5218344a1cd5889d48dac67229fcf024ed300030d5Simone Contini	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
5396a3e79edff6f41b0f115a82f1a39d66218077a7Dario Lombardo	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
558a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
6158381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
70a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
72a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
73e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
74912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
75acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
76c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
77c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
786cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
79c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
80491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
813b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
82b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
838fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
842d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
859e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
86cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
877c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
88af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_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 Torvaldsstatic struct usb_driver pl2303_driver = {
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"pl2303",
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =	usb_serial_probe,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =	usb_serial_disconnect,
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =	id_table,
105fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.suspend =      usb_serial_suspend,
106fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.resume =       usb_serial_resume,
107ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman	.no_dynamic_id = 	1,
108fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.supports_autosuspend =	1,
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1203a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST			0x23
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE			0x08
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_0,		/* don't know the difference between type 0 and */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_1,		/* type 1, until someone from prolific tells us... */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HX,		/* HX version of the pl2303 chip */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t delta_msr_wait;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_read(__u16 value, __u16 index,
160eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial, unsigned char *buf)
161eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
162eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
163eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
164eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, buf, 1, 100);
165eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", VENDOR_READ_REQUEST_TYPE,
166eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, value, index, res, buf[0]);
167eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
168eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
169eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
170eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_write(__u16 value, __u16 index,
171eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial)
172eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
173eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
174eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
175eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
176eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	dbg("0x%x:0x%x:0x%x:0x%x  %d", VENDOR_WRITE_REQUEST_TYPE,
177eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, value, index, res);
178eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
179eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
180eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
181372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type = type_0;
1853e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	unsigned char *buf;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1883e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	buf = kmalloc(10, GFP_KERNEL);
1893e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	if (buf == NULL)
1903e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		return -ENOMEM;
1913e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serial->dev->descriptor.bDeviceClass == 0x02)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_0;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = HX;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0x00)
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("device type: %d", type);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
20380b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!priv)
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&priv->lock);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_waitqueue_head(&priv->delta_msr_wait);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->type = type;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], priv);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2113e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2123e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2133e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 0, serial);
2143e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2153e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
2163e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2173e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 1, serial);
2183e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2193e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
2203e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0, 1, serial);
2213e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(1, 0, serial);
2223e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	if (type == HX)
2233e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		pl2303_vendor_write(2, 0x44, serial);
2243e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	else
2253e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		pl2303_vendor_write(2, 0x24, serial);
2263e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2273e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup:
2313e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
2323a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	for (--i; i >= 0; --i) {
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(priv);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], NULL);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
240372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int set_control_lines(struct usb_device *dev, u8 value)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
2433a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox
244372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
245372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
246372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
247441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - value = %d, retval = %d", __func__, value, retval);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25195da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_set_termios(struct tty_struct *tty,
25295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		struct usb_serial_port *port, struct ktermios *old_termios)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cflag;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
26225b8286805e856c8c7fda127018e31032c918015Frank Schaefer	const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
26325b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         4800, 7200, 9600, 14400, 19200, 28800, 38400,
26425b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         57600, 115200, 230400, 460800, 614400,
26525b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         921600, 1228800, 2457600, 3000000, 6000000 };
26625b8286805e856c8c7fda127018e31032c918015Frank Schaefer	int baud_floor, baud_ceil;
26725b8286805e856c8c7fda127018e31032c918015Frank Schaefer	int k;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
269441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s -  port %d", __func__, port->number);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	/* The PL2303 is reported to lose bytes if you change
272bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   serial settings even to the same values as before. Thus
273bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   we actually need to filter in this specific case */
274bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
27595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (!tty_termios_hw_change(tty->termios, old_termios))
276bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox		return;
277bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
27895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	cflag = tty->termios->c_cflag;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
280372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	buf = kzalloc(7, GFP_KERNEL);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
282441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dev_err(&port->dev, "%s - out of memory.\n", __func__);
283a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox		/* Report back no change occurred */
28495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		*tty->termios = *old_termios;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
288372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
289372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
290372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
291372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
292372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSIZE) {
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (cflag & CSIZE) {
2963a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS5:
2973a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 5;
2983a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
2993a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS6:
3003a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 6;
3013a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
3023a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS7:
3033a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 7;
3043a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
3053a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		default:
3063a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS8:
3073a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 8;
3083a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
310441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - data bits = %d", __func__, buf[6]);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31325b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* For reference buf[0]:buf[3] baud rate value */
31425b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* NOTE: Only the values defined in baud_sup are supported !
31525b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 *       => if unsupported values are set, the PL2303 seems to use
31625b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 *          9600 baud (at least my PL2303X always does)
31725b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 */
31895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	baud = tty_get_baud_rate(tty);
31925b8286805e856c8c7fda127018e31032c918015Frank Schaefer	dbg("%s - baud requested = %d", __func__, baud);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud) {
32125b8286805e856c8c7fda127018e31032c918015Frank Schaefer		/* Set baudrate to nearest supported value */
32225b8286805e856c8c7fda127018e31032c918015Frank Schaefer		for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
32325b8286805e856c8c7fda127018e31032c918015Frank Schaefer			if (baud_sup[k] / baud) {
32425b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud_ceil = baud_sup[k];
32525b8286805e856c8c7fda127018e31032c918015Frank Schaefer				if (k==0) {
32625b8286805e856c8c7fda127018e31032c918015Frank Schaefer					baud = baud_ceil;
32725b8286805e856c8c7fda127018e31032c918015Frank Schaefer				} else {
32825b8286805e856c8c7fda127018e31032c918015Frank Schaefer					baud_floor = baud_sup[k-1];
32925b8286805e856c8c7fda127018e31032c918015Frank Schaefer					if ((baud_ceil % baud)
33025b8286805e856c8c7fda127018e31032c918015Frank Schaefer					    > (baud % baud_floor))
33125b8286805e856c8c7fda127018e31032c918015Frank Schaefer						baud = baud_floor;
33225b8286805e856c8c7fda127018e31032c918015Frank Schaefer					else
33325b8286805e856c8c7fda127018e31032c918015Frank Schaefer						baud = baud_ceil;
33425b8286805e856c8c7fda127018e31032c918015Frank Schaefer				}
33525b8286805e856c8c7fda127018e31032c918015Frank Schaefer				break;
33625b8286805e856c8c7fda127018e31032c918015Frank Schaefer			}
33725b8286805e856c8c7fda127018e31032c918015Frank Schaefer		}
33825b8286805e856c8c7fda127018e31032c918015Frank Schaefer		if (baud > 1228800) {
33925b8286805e856c8c7fda127018e31032c918015Frank Schaefer			/* type_0, type_1 only support up to 1228800 baud */
34025b8286805e856c8c7fda127018e31032c918015Frank Schaefer			if (priv->type != HX)
34125b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud = 1228800;
34225b8286805e856c8c7fda127018e31032c918015Frank Schaefer			else if (baud > 6000000)
34325b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud = 6000000;
34425b8286805e856c8c7fda127018e31032c918015Frank Schaefer		}
34525b8286805e856c8c7fda127018e31032c918015Frank Schaefer		dbg("%s - baud set = %d", __func__, baud);
3468d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński		if (baud <= 115200) {
3478d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[0] = baud & 0xff;
3488d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[1] = (baud >> 8) & 0xff;
3498d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[2] = (baud >> 16) & 0xff;
3508d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[3] = (baud >> 24) & 0xff;
3518d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński		} else {
3528d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			/* apparently the formula for higher speeds is:
3538d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
3548d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			 */
3558d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			unsigned tmp = 12*1000*1000*32 / baud;
3568d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[3] = 0x80;
3578d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[2] = 0;
3588d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[1] = (tmp >= 256);
3598d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			while (tmp >= 256) {
3608d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński				tmp >>= 2;
3618d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński				buf[1] <<= 1;
3628d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			}
3638d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński			buf[0] = tmp;
3648d48fdf689fed2c73c493e5146d1463689246442Michał Sroczyński		}
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSTOPB) {
37129cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		/* NOTE: Comply with "real" UARTs / RS232:
37229cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 *       use 1.5 instead of 2 stop bits with 5 data bits
37329cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 */
37429cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		if ((cflag & CSIZE) == CS5) {
37529cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 1;
37629cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			dbg("%s - stop bits = 1.5", __func__);
37729cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		} else {
37829cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 2;
37929cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			dbg("%s - stop bits = 2", __func__);
38029cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		}
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
383441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - stop bits = 1", __func__);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & PARENB) {
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cflag & PARODD) {
3936dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			if (cflag & CMSPAR) {
3946dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 3;
3956dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				dbg("%s - parity = mark", __func__);
3966dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
3976dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 1;
3986dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				dbg("%s - parity = odd", __func__);
3996dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4016dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			if (cflag & CMSPAR) {
4026dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 4;
4036dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				dbg("%s - parity = space", __func__);
4046dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
4056dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 2;
4066dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				dbg("%s - parity = even", __func__);
4076dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
411441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - parity = none", __func__);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
414372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
415372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
416372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
417372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0x21:0x20:0:0  %d", i);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cflag & CBAUD) == B0)
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_control_lines(serial->dev, control);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
433372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
436372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
437372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
438372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
439372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CRTSCTS) {
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == HX)
444eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x61, serial);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
446eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x41, serial);
447715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
448eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(0x0, 0x0, serial);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
450572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
45125b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* Save resulting baud rate */
452df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox	if (baud)
45395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		tty_encode_baud_rate(tty, baud, baud);
454df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox
455572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
456572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
457572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
458335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on)
459335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
460335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
461335f8514f200e63d689113d29cb7253a5c282967Alan Cox	unsigned long flags;
462335f8514f200e63d689113d29cb7253a5c282967Alan Cox	u8 control;
463335f8514f200e63d689113d29cb7253a5c282967Alan Cox
464335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_lock_irqsave(&priv->lock, flags);
465335f8514f200e63d689113d29cb7253a5c282967Alan Cox	/* Change DTR and RTS */
466335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (on)
467335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
468335f8514f200e63d689113d29cb7253a5c282967Alan Cox	else
469335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
470335f8514f200e63d689113d29cb7253a5c282967Alan Cox	control = priv->line_control;
471335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_unlock_irqrestore(&priv->lock, flags);
472335f8514f200e63d689113d29cb7253a5c282967Alan Cox	set_control_lines(port->serial->dev, control);
473335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
474335f8514f200e63d689113d29cb7253a5c282967Alan Cox
475335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port)
476572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
477441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
478572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
4798b0127b2082601e40295045414a8318f2c8ee5a0Johan Hovold	usb_serial_generic_close(port);
480572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
483a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
485606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios tmp_termios;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
490441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s -  port %d", __func__, port->number);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921694899fd1af43636351aac97f415fd3c9cefb1dDariusz M	if (priv->type != HX) {
4931694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
4941694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
4953e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	} else {
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
497eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(8, 0, serial);
498eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(9, 0, serial);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
50295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (tty)
50395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		pl2303_set_termios(tty, port, &tmp_termios);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
505441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - submitting interrupt urb", __func__);
506372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
508372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
509441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
510db6e9186c90188edea20aaa5161ea073440cc2a1Johan Hovold		return result;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
512d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
513f5230a53c1d551811b077ccad219105786da1becJohan Hovold	result = usb_serial_generic_open(tty, port);
514d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	if (result) {
515d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		usb_kill_urb(port->interrupt_in_urb);
516d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		return result;
517d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	}
518d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
519335f8514f200e63d689113d29cb7253a5c282967Alan Cox	port->port.drain_delay = 256;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52320b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty,
524372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
52695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5316fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
5326fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
5336fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
534372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
544372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
546372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	return set_control_lines(port->serial->dev, control);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54960b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int pl2303_tiocmget(struct tty_struct *tty)
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
55195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
558441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d)", __func__, port->number);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5606fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
5616fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
5626fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
563372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
566372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
575441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - result = %x", __func__, result);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
580335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port)
581335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
582335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
583335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (priv->line_status & UART_DCD)
584335f8514f200e63d689113d29cb7253a5c282967Alan Cox		return 1;
585335f8514f200e63d689113d29cb7253a5c282967Alan Cox	return 0;
586335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
587335f8514f200e63d689113d29cb7253a5c282967Alan Cox
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
596372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
598372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		interruptible_sleep_on(&priv->delta_msr_wait);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
605372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
606372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
608372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
609372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6103a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		changed = prevstatus ^ status;
611372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
6153a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62400a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int pl2303_ioctl(struct tty_struct *tty,
625372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
62767b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	struct serial_struct ser;
62895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
629441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
63267b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	case TIOCGSERIAL:
63367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		memset(&ser, 0, sizeof ser);
63467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.type = PORT_16654;
63567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.line = port->serial->minor;
63667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.port = port->number;
63767b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.baud_base = 460800;
63867b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
63967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		if (copy_to_user((void __user *)arg, &ser, sizeof ser))
64067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas			return -EFAULT;
64167b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
64267b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		return 0;
64367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
6443a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	case TIOCMIWAIT:
6453a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
6463a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		return wait_modem_info(port, arg);
6473a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	default:
6483a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		dbg("%s not supported = 0x%04x", __func__, cmd);
6493a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		break;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
65495da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state)
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
65695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
6673a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	dbg("%s - turning break %s", __func__,
6683a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			state == BREAK_OFF ? "off" : "on");
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
670372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
671372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
672372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
674441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - error sending break = %d", __func__, result);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
677f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void pl2303_release(struct usb_serial *serial)
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
682441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s", __func__);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
686684c6e30d389f67ef727c8f5a7b23a09b4cb02e4Johan Hovold		kfree(priv);
687372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	}
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
69197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
69297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
69397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
69497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
69597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
696d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	struct tty_struct *tty;
69797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
69897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 status_idx = UART_STATE;
69995f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier	u8 length = UART_STATE + 1;
700d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	u8 prev_line_status;
7019c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	u16 idv, idp;
70297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
7039c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
7049c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
7059c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7069c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7079c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	if (idv == SIEMENS_VENDOR_ID) {
7089c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		if (idp == SIEMENS_PRODUCT_ID_X65 ||
7099c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_SX1 ||
7109c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_X75) {
7119c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7129c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			length = 1;
7139c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			status_idx = 0;
7149c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		}
71597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	}
71697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
71797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if (actual_length < length)
718a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
71997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
7203a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	/* Save off the uart status for others to look at */
72197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
722d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	prev_line_status = priv->line_status;
72397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
72497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
725430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel	if (priv->line_status & UART_BREAK_ERROR)
726430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel		usb_serial_handle_break(port);
727372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
728d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek
729d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty = tty_port_tty_get(&port->port);
730d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if (!tty)
731d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		return;
732d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if ((priv->line_status ^ prev_line_status) & UART_DCD)
733d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		usb_serial_handle_dcd_change(port, tty,
734d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek				priv->line_status & UART_DCD);
735d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty_kref_put(tty);
73697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7387d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
740cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
74297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
743461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
744461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
746441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d)", __func__, port->number);
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
748461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
756441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb shutting down with status: %d", __func__,
757461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
760441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - nonzero urb status received: %d", __func__,
761461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
765441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__,
766372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
767372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
76897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
771461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
772461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (retval)
773372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&urb->dev->dev,
774372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
775441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, retval);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
778f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovoldstatic void pl2303_process_read_urb(struct urb *urb)
779d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{
780f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct usb_serial_port *port = urb->context;
781f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
782f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct tty_struct *tty;
783d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	unsigned char *data = urb->transfer_buffer;
784d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	char tty_flag = TTY_NORMAL;
785f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	unsigned long flags;
786f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	u8 line_status;
787f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	int i;
788f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
789f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	/* update line status */
790f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_lock_irqsave(&priv->lock, flags);
791f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	line_status = priv->line_status;
792f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
793f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_unlock_irqrestore(&priv->lock, flags);
794f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	wake_up_interruptible(&priv->delta_msr_wait);
795f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
796f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	if (!urb->actual_length)
797f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold		return;
798f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
799f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	tty = tty_port_tty_get(&port->port);
800f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	if (!tty)
801f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold		return;
802f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
803d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* break takes precedence over parity, */
804d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* which takes precedence over framing errors */
805d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_BREAK_ERROR)
806d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_BREAK;
807d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_PARITY_ERROR)
808d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_PARITY;
809d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_FRAME_ERROR)
810d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_FRAME;
811d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	dbg("%s - tty_flag = %d", __func__, tty_flag);
812d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox
813d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* overrun is special, not associated with a char */
814d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_OVERRUN_ERROR)
815d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
8169388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold
817d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	if (port->port.console && port->sysrq) {
818d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		for (i = 0; i < urb->actual_length; ++i)
8196ee9f4b4affe751d313d2538999aeec134d413a6Dmitry Torokhov			if (!usb_serial_handle_sysrq_char(port, data[i]))
820d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox				tty_insert_flip_char(tty, data[i], tty_flag);
821d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	} else {
822d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold		tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
823d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold							urb->actual_length);
8249388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold	}
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
826f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	tty_flip_buffer_push(tty);
8274a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty_kref_put(tty);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
830572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */
831572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
832572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
833572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
834572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
835572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
836572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
837d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.usb_driver = 		&pl2303_driver,
838572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
8397919c2fd9e07276403b9a4d9ae52305e0d70f923Johan Hovold	.bulk_in_size =		256,
8403efeaff6298290b36499532f0b4c87aa4bae8aefJohan Hovold	.bulk_out_size =	256,
841572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
842572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
843335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.dtr_rts = 		pl2303_dtr_rts,
844335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.carrier_raised =	pl2303_carrier_raised,
845572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
846572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
847572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
848572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
849572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
850f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	.process_read_urb =	pl2303_process_read_urb,
851572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
852572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
853f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =		pl2303_release,
854572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
856372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int __init pl2303_init(void)
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
859372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_serial_register(&pl2303_device);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_serial_register;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_register(&pl2303_driver);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_register;
866c197a8db59daf06dc5e77acd5a9681329cb22458Greg Kroah-Hartman	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register:
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_deregister(&pl2303_device);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register:
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
874372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void __exit pl2303_exit(void)
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
876372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_deregister(&pl2303_driver);
877372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_deregister(&pl2303_device);
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pl2303_init);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl2303_exit);
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not");
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
889