pl2303.c revision 281393ad0bcfc309434d2bff38abc15805c2cbc4
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 *
757ce61aad748ceaa08c859da04043ad7dae7c15eFrank Schäfer * Copyright (C) 2009, 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
857ce61aad748ceaa08c859da04043ad7dae7c15eFrank Schäfer *  - fixes, improvements and documentation for the baud rate encoding methods
957ce61aad748ceaa08c859da04043ad7dae7c15eFrank Schäfer * Copyright (C) 2013 Reinhard Max <max@suse.de>
1057ce61aad748ceaa08c859da04043ad7dae7c15eFrank Schäfer *  - fixes and improvements for the divisor based baud rate encoding method
1157ce61aad748ceaa08c859da04043ad7dae7c15eFrank Schäfer *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Original driver for 2.2.x by anonymous
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
144d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman *	This program is free software; you can redistribute it and/or
154d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman *	modify it under the terms of the GNU General Public License version
164d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman *	2 as published by the Free Software Foundation.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
183a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox * See Documentation/usb/usb-serial.txt for more information on using this
193a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox * driver
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
343a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#include <linux/uaccess.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
36a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h>
37b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold#include <asm/unaligned.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h"
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
457d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = {
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
483d861494729c70d9ebeb7d93caa107897925c355Peter Moulder	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
51b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
524be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
53727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
5418344a1cd5889d48dac67229fcf024ed300030d5Simone Contini	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
5596a3e79edff6f41b0f115a82f1a39d66218077a7Dario Lombardo	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
578a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
6358381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
72a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
74a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
75e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
76912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
77acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
78c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
79c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
806cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
81c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
82491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
833b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
84b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
858fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
862d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
879e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
88cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
897c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
90af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
918540d66615c39010168ab97eaafb476ec2851298Gianpaolo Cugola	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
92f36ecd5de93e4c85a9e3d25100c6e233155b12e5Jef Driesen	{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
9349276560c9004fce24c42e3c0ad75f34d956fc63Khanh-Dang Nguyen Thu Lam	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
9435904e6b5106fda51b04c8b8080c04466865415fPawel Ludwikow	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
959a61d72602771906e11a5944e8571f8006387b39Manuel Jander	{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
96598f0b703506da841d3459dc0c48506be14d1778Eric Benoit	{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
100372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1113a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST			0x23
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE			0x08
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
137e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	type_0,		/* don't know the difference between type 0 and */
138e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	type_1,		/* type 1, until someone from prolific tells us... */
139e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	HX,		/* HX version of the pl2303 chip */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1428bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstruct pl2303_serial_private {
1438bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	enum pl2303_type type;
1448bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold};
1458bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_read(__u16 value, __u16 index,
153eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial, unsigned char *buf)
154eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
155eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
156eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
157eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, buf, 1, 100);
1587b5789a86890423e1460362798140c26822798b1Johan Hovold	dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x  %d - %x\n",
159d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
160d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		res, buf[0]);
161eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
162eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
163eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
164eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_write(__u16 value, __u16 index,
165eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial)
166eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
167eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
168eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
169eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
1707b5789a86890423e1460362798140c26822798b1Johan Hovold	dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x  %d\n",
171d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
172d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		res);
173eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
174eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
175eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
176372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1788bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type = type_0;
1803e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	unsigned char *buf;
1818bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
1828bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
1838bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!spriv)
1848bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1863e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	buf = kmalloc(10, GFP_KERNEL);
1878bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!buf) {
1888bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		kfree(spriv);
1893e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		return -ENOMEM;
1908bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	}
1913e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
192b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	if (serial->dev->descriptor.bDeviceClass == 0x02)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_0;
194b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
195e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman		type = HX;
196281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman	else if (serial->dev->descriptor.bDeviceClass == 0x00)
197281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman		type = type_1;
198281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
200b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman	dev_dbg(&serial->interface->dev, "device type: %d\n", type);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2028bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv->type = type;
2038bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_data(serial, spriv);
2043e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2053e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2063e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 0, serial);
2073e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2083e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
2093e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2103e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 1, serial);
2113e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
2123e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
2133e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0, 1, serial);
2143e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(1, 0, serial);
215e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	if (type == HX)
216034d1527adebd302115c87ef343497a889638275Frank Schäfer		pl2303_vendor_write(2, 0x44, serial);
217e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	else
218e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman		pl2303_vendor_write(2, 0x24, serial);
2193e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
2203e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2228bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2248bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic void pl2303_release(struct usb_serial *serial)
2258bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2268bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv;
2278bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2288bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spriv = usb_get_serial_data(serial);
2298bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(spriv);
2308bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2318bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2328bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_probe(struct usb_serial_port *port)
2338bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2348bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_private *priv;
2358bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2368bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2378bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	if (!priv)
2388bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold		return -ENOMEM;
2398bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2408bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	spin_lock_init(&priv->lock);
2418bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2428bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	usb_set_serial_port_data(port, priv);
2438bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
244d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold	port->port.drain_delay = 256;
245d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold
2468bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2478bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}
2488bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2498bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_remove(struct usb_serial_port *port)
2508bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{
2518bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_private *priv;
2528bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2538bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	priv = usb_get_serial_port_data(port);
2548bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	kfree(priv);
2558bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold
2568bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	return 0;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
259f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovoldstatic int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
261f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	struct usb_device *dev = port->serial->dev;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
2633a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox
264372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
265372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
266372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
267f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	dev_dbg(&port->dev, "%s - value = %d, retval = %d\n", __func__,
268d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		value, retval);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
272e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäferstatic int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
273e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer								      u8 buf[4])
274e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer{
275e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/*
276e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * NOTE: Only the values defined in baud_sup are supported !
27709169197c9f5e3b42f0c83c6d7071b3e9c94153eGreg Kroah-Hartman	 *       => if unsupported values are set, the PL2303 seems to
27809169197c9f5e3b42f0c83c6d7071b3e9c94153eGreg Kroah-Hartman	 *	    use 9600 baud (at least my PL2303X always does)
279e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 */
280e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
281e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer				 4800, 7200, 9600, 14400, 19200, 28800, 38400,
282e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer				 57600, 115200, 230400, 460800, 614400, 921600,
283e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman				 1228800, 2457600, 3000000, 6000000 };
284c23bda365dfbf56aa4d6d4a97f83136c36050e01Frank Schäfer	/*
285e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	 * NOTE: The PL2303HX (tested with rev. 3A) also supports the following
286e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	 * baud rates: 128000, 134400, 161280, 201600, 268800, 403200, 806400.
287e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	 * As long as we are not using this encoding method for them, there is
288e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	 * no point in complicating the code to support them.
289c23bda365dfbf56aa4d6d4a97f83136c36050e01Frank Schäfer	 */
290e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	int i;
291e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer
292e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/* Set baudrate to nearest supported value */
293e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
294e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		if (baud_sup[i] > baud)
295e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer			break;
296e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	}
297e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	if (i == ARRAY_SIZE(baud_sup))
298e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		baud = baud_sup[i - 1];
299e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
300e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		baud = baud_sup[i - 1];
301e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	else
302e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		baud = baud_sup[i];
303e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	/* type_0, type_1 only support up to 1228800 baud */
304e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	if (type != HX)
305e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		baud = min_t(int, baud, 1228800);
306e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/* Direct (standard) baud rate encoding method */
307e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	put_unaligned_le32(baud, buf);
308e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer
309e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	return baud;
310e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer}
311e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer
312e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäferstatic int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type,
313e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer								      u8 buf[4])
314e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer{
315e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/*
316e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * Divisor based baud rate encoding method
317e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 *
31809169197c9f5e3b42f0c83c6d7071b3e9c94153eGreg Kroah-Hartman	 * NOTE: it's not clear if the type_0/1 chips support this method
319e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 *
320e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * divisor = 12MHz * 32 / baudrate = 2^A * B
321e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 *
322e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * with
323e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 *
324e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * A = buf[1] & 0x0e
325e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * B = buf[0]  +  (buf[1] & 0x01) << 8
326e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 *
327e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * Special cases:
328e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * => 8 < B < 16: device seems to work not properly
329e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * => B <= 8: device uses the max. value B = 512 instead
330e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 */
331e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	unsigned int A, B;
332e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer
333b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	/*
334b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 * NOTE: The Windows driver allows maximum baud rates of 110% of the
335b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 * specified maximium value.
336b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 * Quick tests with early (2004) HX (rev. A) chips suggest, that even
337b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 * higher baud rates (up to the maximum of 24M baud !) are working fine,
338b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 * but that should really be tested carefully in "real life" scenarios
339b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 * before removing the upper limit completely.
340b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 * Baud rates smaller than the specified 75 baud are definitely working
341b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 * fine.
342b5c16c6a031c52cc4b7dda6c3de46462fbc92eabFrank Schäfer	 */
343e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	if (type == HX)
344034d1527adebd302115c87ef343497a889638275Frank Schäfer		baud = min_t(int, baud, 6000000 * 1.1);
345e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	else
346e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman		baud = min_t(int, baud, 1228800 * 1.1);
347e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/* Determine factors A and B */
348e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	A = 0;
349e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	B = 12000000 * 32 / baud;  /* 12MHz */
350e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	B <<= 1; /* Add one bit for rounding */
351e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	while (B > (512 << 1) && A <= 14) {
352e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		A += 2;
353e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		B >>= 2;
354e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	}
355e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	if (A > 14) { /* max. divisor = min. baudrate reached */
356e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		A = 14;
357e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		B = 512;
358e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		/* => ~45.78 baud */
359e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	} else {
360e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		B = (B + 1) >> 1; /* Round the last bit */
361e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	}
362e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/* Handle special cases */
363e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	if (B == 512)
364e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		B = 0; /* also: 1 to 8 */
365e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	else if (B < 16)
366e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		/*
367e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		 * NOTE: With the current algorithm this happens
368e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		 * only for A=0 and means that the min. divisor
369e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		 * (respectively: the max. baudrate) is reached.
370e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		 */
371e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		B = 16;		/* => 24 MBaud */
372e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/* Encode the baud rate */
373e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	buf[3] = 0x80;     /* Select divisor encoding method */
374e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	buf[2] = 0;
375e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	buf[1] = (A & 0x0e);		/* A */
376e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	buf[1] |= ((B & 0x100) >> 8);	/* MSB of B */
377e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	buf[0] = B & 0xff;		/* 8 LSBs of B */
378e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/* Calculate the actual/resulting baud rate */
379e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	if (B <= 8)
380e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		B = 512;
381e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	baud = 12000000 * 32 / ((1 << A) * B);
382e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer
383e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	return baud;
384e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer}
385e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer
38615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_encode_baudrate(struct tty_struct *tty,
38715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold					struct usb_serial_port *port,
388e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer					enum pl2303_type type,
38915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold					u8 buf[4])
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
39115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	int baud;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	baud = tty_get_baud_rate(tty);
394d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "baud requested = %d\n", baud);
395b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold	if (!baud)
396b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold		return;
397e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/*
398e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * There are two methods for setting/encoding the baud rate
399e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * 1) Direct method: encodes the baud rate value directly
400e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 *    => supported by all chip types
401e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 * 2) Divisor based method: encodes a divisor to a base value (12MHz*32)
40209169197c9f5e3b42f0c83c6d7071b3e9c94153eGreg Kroah-Hartman	 *    => supported by HX chips (and likely not by type_0/1 chips)
403c23bda365dfbf56aa4d6d4a97f83136c36050e01Frank Schäfer	 *
404c23bda365dfbf56aa4d6d4a97f83136c36050e01Frank Schäfer	 * NOTE: Although the divisor based baud rate encoding method is much
405c23bda365dfbf56aa4d6d4a97f83136c36050e01Frank Schäfer	 * more flexible, some of the standard baud rate values can not be
406c23bda365dfbf56aa4d6d4a97f83136c36050e01Frank Schäfer	 * realized exactly. But the difference is very small (max. 0.2%) and
407c23bda365dfbf56aa4d6d4a97f83136c36050e01Frank Schäfer	 * the device likely uses the same baud rate generator for both methods
408c23bda365dfbf56aa4d6d4a97f83136c36050e01Frank Schäfer	 * so that there is likley no difference.
409e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	 */
410e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	if (type != HX)
411e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		baud = pl2303_baudrate_encode_direct(baud, type, buf);
412e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	else
413e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer		baud = pl2303_baudrate_encode_divisor(baud, type, buf);
41415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	/* Save resulting baud rate */
415b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold	tty_encode_baud_rate(tty, baud, baud);
416b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold	dev_dbg(&port->dev, "baud set = %d\n", baud);
41715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold}
41815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
41915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_set_termios(struct tty_struct *tty,
42015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		struct usb_serial_port *port, struct ktermios *old_termios)
42115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold{
42215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct usb_serial *serial = port->serial;
42315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
42415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
42515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	unsigned long flags;
42615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	unsigned char *buf;
42715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	int i;
42815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	u8 control;
42915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
43087265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	/*
43187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	 * The PL2303 is reported to lose bytes if you change serial settings
43287265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	 * even to the same values as before. Thus we actually need to filter
43387265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	 * in this specific case.
43487265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	 */
43515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
43615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		return;
43715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
43815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	buf = kzalloc(7, GFP_KERNEL);
43915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	if (!buf) {
44015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		dev_err(&port->dev, "%s - out of memory.\n", __func__);
44115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		/* Report back no change occurred */
44215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		if (old_termios)
44315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			tty->termios = *old_termios;
44415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		return;
44515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	}
44615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
44715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
44815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
44915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			    0, 0, buf, 7, 100);
45015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
45115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
45287265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CSIZE(tty)) {
45387265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		switch (C_CSIZE(tty)) {
45415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		case CS5:
45515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			buf[6] = 5;
45615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			break;
45715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		case CS6:
45815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			buf[6] = 6;
45915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			break;
46015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		case CS7:
46115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			buf[6] = 7;
46215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			break;
46315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		default:
46415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		case CS8:
46515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold			buf[6] = 8;
46615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		}
46715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold		dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
46815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold	}
46915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
470e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	/* For reference:   buf[0]:buf[3] baud rate value */
471e917ba01d69ad705a4cd6a6c77538f55d84f5907Frank Schäfer	pl2303_encode_baudrate(tty, port, spriv->type, buf);
47215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
47687265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CSTOPB(tty)) {
47787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		/*
47887265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		 * NOTE: Comply with "real" UARTs / RS232:
47929cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 *       use 1.5 instead of 2 stop bits with 5 data bits
48029cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 */
48187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		if (C_CSIZE(tty) == CS5) {
48229cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 1;
483d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 1.5\n");
48429cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		} else {
48529cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 2;
486d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			dev_dbg(&port->dev, "stop bits = 2\n");
48729cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
490d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "stop bits = 1\n");
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49387265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_PARENB(tty)) {
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
49987265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold		if (C_PARODD(tty)) {
50087265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold			if (tty->termios.c_cflag & CMSPAR) {
5016dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 3;
502d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = mark\n");
5036dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
5046dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 1;
505d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = odd\n");
5066dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
50887265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold			if (tty->termios.c_cflag & CMSPAR) {
5096dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 4;
510d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = space\n");
5116dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
5126dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 2;
513d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman				dev_dbg(&port->dev, "parity = even\n");
5146dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
518d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "parity = none\n");
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
522372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
523372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
524d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "0x21:0x20:0:0  %d\n", i);
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
52987265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_BAUD(tty) == B0)
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
5312d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
536f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold		pl2303_set_control_lines(port, control);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
540372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
54187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	memset(buf, 0, 7);
542372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
543372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
544372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
545715cf92aeb061c47f7170d0d7899311b7597bc66Andy Shevchenko	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold	if (C_CRTSCTS(tty)) {
548e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman		if (spriv->type == HX)
549034d1527adebd302115c87ef343497a889638275Frank Schäfer			pl2303_vendor_write(0x0, 0x61, serial);
550e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman		else
551e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman			pl2303_vendor_write(0x0, 0x41, serial);
552715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
553eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(0x0, 0x0, serial);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
555572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
556572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
557572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
558572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
559335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on)
560335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
561335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
562335f8514f200e63d689113d29cb7253a5c282967Alan Cox	unsigned long flags;
563335f8514f200e63d689113d29cb7253a5c282967Alan Cox	u8 control;
564335f8514f200e63d689113d29cb7253a5c282967Alan Cox
565335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_lock_irqsave(&priv->lock, flags);
566335f8514f200e63d689113d29cb7253a5c282967Alan Cox	/* Change DTR and RTS */
567335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (on)
568335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
569335f8514f200e63d689113d29cb7253a5c282967Alan Cox	else
570335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
571335f8514f200e63d689113d29cb7253a5c282967Alan Cox	control = priv->line_control;
572335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_unlock_irqrestore(&priv->lock, flags);
573f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold	pl2303_set_control_lines(port, control);
574335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
575335f8514f200e63d689113d29cb7253a5c282967Alan Cox
576335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port)
577572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
5788b0127b2082601e40295045414a8318f2c8ee5a0Johan Hovold	usb_serial_generic_close(port);
579572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
582a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
5858bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
588e8bbd5c42b65b662756d67290a5c4dcda1abc596Greg Kroah-Hartman	if (spriv->type != HX) {
5891694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
5901694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
5913e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	} else {
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
593eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(8, 0, serial);
594eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(9, 0, serial);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
59895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (tty)
5992d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold		pl2303_set_termios(tty, port, NULL);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
603372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
604441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
605db6e9186c90188edea20aaa5161ea073440cc2a1Johan Hovold		return result;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
607d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
608f5230a53c1d551811b077ccad219105786da1becJohan Hovold	result = usb_serial_generic_open(tty, port);
609d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	if (result) {
610d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		usb_kill_urb(port->interrupt_in_urb);
611d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold		return result;
612d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold	}
613d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61720b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty,
618372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
62095da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
6246f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold	int ret;
6256fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
626372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
636372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6385ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	ret = pl2303_set_control_lines(port, control);
6395ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	if (ret)
6405ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold		return usb_translate_errors(ret);
6416f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold
6425ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold	return 0;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64560b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int pl2303_tiocmget(struct tty_struct *tty)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
64795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
654372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
657372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
666d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port)
672335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
673335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
674335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (priv->line_status & UART_DCD)
675335f8514f200e63d689113d29cb7253a5c282967Alan Cox		return 1;
676335f8514f200e63d689113d29cb7253a5c282967Alan Cox	return 0;
677335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
678335f8514f200e63d689113d29cb7253a5c282967Alan Cox
679824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovoldstatic int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg)
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
681824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold	struct usb_serial_port *port = tty->driver_data;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
688372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
690372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
6936d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold		interruptible_sleep_on(&port->port.delta_msr_wait);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
697372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
69840509ca982c00c4b70fc00be887509feca0bff15Johan Hovold		if (port->serial->disconnected)
69940509ca982c00c4b70fc00be887509feca0bff15Johan Hovold			return -EIO;
70040509ca982c00c4b70fc00be887509feca0bff15Johan Hovold
701372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
703372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
704372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
7053a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		changed = prevstatus ^ status;
706372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
7103a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71900a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int pl2303_ioctl(struct tty_struct *tty,
720372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
72267b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	struct serial_struct ser;
72395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
724d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman
725d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
72867b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas	case TIOCGSERIAL:
72967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		memset(&ser, 0, sizeof ser);
73067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.type = PORT_16654;
731e5b1e2062e0535e8ffef79bb34d857e21380d101Greg Kroah-Hartman		ser.line = port->minor;
7321143832eca8f1d64da7d85642c956ae9d25c69e1Greg Kroah-Hartman		ser.port = port->port_number;
73367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		ser.baud_base = 460800;
73467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
73567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		if (copy_to_user((void __user *)arg, &ser, sizeof ser))
73667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas			return -EFAULT;
73767b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas
73867b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas		return 0;
7393a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	default:
740d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
7413a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		break;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
74695da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state)
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
74895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
757d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
7583a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			state == BREAK_OFF ? "off" : "on");
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
760372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
761372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
762372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
764d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev, "error sending break = %d\n", result);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
76897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
76997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
77097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
77197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
77297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
773d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	struct tty_struct *tty;
77497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
77597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 status_idx = UART_STATE;
77695f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier	u8 length = UART_STATE + 1;
777d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	u8 prev_line_status;
7789c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	u16 idv, idp;
77997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
7809c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
7819c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
7829c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7839c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7849c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	if (idv == SIEMENS_VENDOR_ID) {
7859c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		if (idp == SIEMENS_PRODUCT_ID_X65 ||
7869c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_SX1 ||
7879c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_X75) {
7889c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
7899c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			length = 1;
7909c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			status_idx = 0;
7919c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		}
79297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	}
79397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
79497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if (actual_length < length)
795a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
79697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
7973a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	/* Save off the uart status for others to look at */
79897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
799d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	prev_line_status = priv->line_status;
80097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
80197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
802430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel	if (priv->line_status & UART_BREAK_ERROR)
803430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel		usb_serial_handle_break(port);
8046d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold	wake_up_interruptible(&port->port.delta_msr_wait);
805d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek
806d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty = tty_port_tty_get(&port->port);
807d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if (!tty)
808d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		return;
809d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	if ((priv->line_status ^ prev_line_status) & UART_DCD)
810d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek		usb_serial_handle_dcd_change(port, tty,
811d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek				priv->line_status & UART_DCD);
812d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek	tty_kref_put(tty);
81397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8157d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
817cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
81997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
820461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
821461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
823461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
831d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
832d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
835d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
836d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman			__func__, status);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
84059d33f2fc2d63796296b1b76143e039d6e7cf532Greg Kroah-Hartman	usb_serial_debug_data(&port->dev, __func__,
841372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
842372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
84397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
846461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
847461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (retval)
848d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman		dev_err(&port->dev,
849372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
850441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, retval);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
853f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovoldstatic void pl2303_process_read_urb(struct urb *urb)
854d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{
855f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct usb_serial_port *port = urb->context;
856f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	struct pl2303_private *priv = usb_get_serial_port_data(port);
857d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	unsigned char *data = urb->transfer_buffer;
858d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	char tty_flag = TTY_NORMAL;
859f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	unsigned long flags;
860f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	u8 line_status;
861f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	int i;
862f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
863f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	/* update line status */
864f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_lock_irqsave(&priv->lock, flags);
865f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	line_status = priv->line_status;
866f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
867f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	spin_unlock_irqrestore(&priv->lock, flags);
8686d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold	wake_up_interruptible(&port->port.delta_msr_wait);
869f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
870f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	if (!urb->actual_length)
871f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold		return;
872f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold
873d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* break takes precedence over parity, */
874d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* which takes precedence over framing errors */
875d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_BREAK_ERROR)
876d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_BREAK;
877d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_PARITY_ERROR)
878d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_PARITY;
879d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_FRAME_ERROR)
880d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_FRAME;
881d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox
8823ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold	if (tty_flag != TTY_NORMAL)
8833ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold		dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
8843ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold								tty_flag);
885d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* overrun is special, not associated with a char */
886d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_OVERRUN_ERROR)
88792a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby		tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
8889388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold
889d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	if (port->port.console && port->sysrq) {
890d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		for (i = 0; i < urb->actual_length; ++i)
8916ee9f4b4affe751d313d2538999aeec134d413a6Dmitry Torokhov			if (!usb_serial_handle_sysrq_char(port, data[i]))
89292a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby				tty_insert_flip_char(&port->port, data[i],
89392a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby						tty_flag);
894d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold	} else {
8952f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby		tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
896d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold							urb->actual_length);
8979388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold	}
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8992e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	tty_flip_buffer_push(&port->port);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
902572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */
903572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
904572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
905572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
906572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
907572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
908572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
909572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
9107919c2fd9e07276403b9a4d9ae52305e0d70f923Johan Hovold	.bulk_in_size =		256,
9113efeaff6298290b36499532f0b4c87aa4bae8aefJohan Hovold	.bulk_out_size =	256,
912572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
913572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
914335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.dtr_rts = 		pl2303_dtr_rts,
915335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.carrier_raised =	pl2303_carrier_raised,
916572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
917572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
918572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
919572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
920572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
921824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold	.tiocmiwait =		pl2303_tiocmiwait,
922f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold	.process_read_urb =	pl2303_process_read_urb,
923572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
924572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
925f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =		pl2303_release,
9268bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_probe =		pl2303_port_probe,
9278bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold	.port_remove =		pl2303_port_remove,
928572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
930f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = {
931f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern	&pl2303_device, NULL
932f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern};
933f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern
93468e24113457e437b1576670f2419b77ed0531e9eGreg Kroah-Hartmanmodule_usb_serial_driver(serial_drivers, id_table);
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
938