pl2303.c revision 29cf1b72f34519413b3fafbccc9ac776eb948ede
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
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_CLOSING_WAIT	(30*HZ)
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_BUF_SIZE		1024
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_TMP_BUF_SIZE	1024
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_buf {
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int	buf_size;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_buf;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_get;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_put;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table [] = {
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
563d861494729c70d9ebeb7d93caa107897925c355Peter Moulder	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
59b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
604be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
61727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
638a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
6958381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
78a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
80a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
81e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
82912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
83acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
84c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
85c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
866cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
87c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
88491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
893b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
90b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
918fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
922d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
939e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
94cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
957c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
96af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
978540d66615c39010168ab97eaafb476ec2851298Gianpaolo Cugola	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
9849276560c9004fce24c42e3c0ad75f34d956fc63Khanh-Dang Nguyen Thu Lam	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
9935904e6b5106fda51b04c8b8080c04466865415fPawel Ludwikow	{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
103372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver pl2303_driver = {
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"pl2303",
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =	usb_serial_probe,
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =	usb_serial_disconnect,
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =	id_table,
110fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.suspend =      usb_serial_suspend,
111fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.resume =       usb_serial_resume,
112ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman	.no_dynamic_id = 	1,
113fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.supports_autosuspend =	1,
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1253a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST			0x23
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE			0x08
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_0,		/* don't know the difference between type 0 and */
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_1,		/* type 1, until someone from prolific tells us... */
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HX,		/* HX version of the pl2303 chip */
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_buf *buf;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int write_urb_in_use;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t delta_msr_wait;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
166572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
167572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_alloc
168572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
169572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Allocate a circular buffer and all associated memory.
170572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
171572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
172572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
173572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_buf *pb;
174572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
175572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (size == 0)
176572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
177572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
1785cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
179572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
180572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
181572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
182572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_buf = kmalloc(size, GFP_KERNEL);
183572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb->buf_buf == NULL) {
184572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb);
185572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
186572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
187572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
188572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_size = size;
189572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_get = pb->buf_put = pb->buf_buf;
190572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
191572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return pb;
192572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
193572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
194572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
195572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_free
196572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
197572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Free the buffer and all associated memory.
198572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
199572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_free(struct pl2303_buf *pb)
200572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
201572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb) {
202572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb->buf_buf);
203572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb);
204572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
205572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
206572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
207572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
208572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_clear
209572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
210572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Clear out all data in the circular buffer.
211572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
212572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_clear(struct pl2303_buf *pb)
213572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
214572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb != NULL)
215572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_get = pb->buf_put;
216572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		/* equivalent to a get of all data available */
217572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
218572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
219572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
220572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_data_avail
221572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
222572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of data available in the circular
223572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer.
224572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
225572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
226572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
227572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
228572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
229572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
2303a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
231572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
232572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
233572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
234572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_space_avail
235572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
236572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of space available in the circular
237572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer.
238572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
239572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
240572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
241572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
242572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
243572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
2443a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
245572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
246572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
247572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
248572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_put
249572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
250572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Copy data data from a user buffer and put it into the circular buffer.
251572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of space available.
252572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
253572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied.
254572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
255572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
256572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi				   unsigned int count)
257572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
258572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int len;
259572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
260572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
261572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
262572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
263572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len  = pl2303_buf_space_avail(pb);
264572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len)
265572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		count = len;
266572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
267572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count == 0)
268572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
269572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
270572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pb->buf_buf + pb->buf_size - pb->buf_put;
271572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len) {
272572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_put, buf, len);
273572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_buf, buf+len, count - len);
274572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_put = pb->buf_buf + count - len;
275572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	} else {
276572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_put, buf, count);
277572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (count < len)
278572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_put += count;
279572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		else /* count == len */
280572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_put = pb->buf_buf;
281572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
282572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
283572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
284572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
285572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
286572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
287572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_get
288572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
289572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Get data from the circular buffer and copy to the given buffer.
290572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of data available.
291572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
292572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied.
293572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
294572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
295572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi				   unsigned int count)
296572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
297572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int len;
298572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
299572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
300572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
301572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
302572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pl2303_buf_data_avail(pb);
303572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len)
304572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		count = len;
305572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
306572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count == 0)
307572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
308572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
309572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pb->buf_buf + pb->buf_size - pb->buf_get;
310572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len) {
311572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf, pb->buf_get, len);
312572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf+len, pb->buf_buf, count - len);
313572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_get = pb->buf_buf + count - len;
314572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	} else {
315572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf, pb->buf_get, count);
316572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (count < len)
317572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_get += count;
318572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		else /* count == len */
319572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_get = pb->buf_buf;
320572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
321572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
322572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
323572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
325eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_read(__u16 value, __u16 index,
326eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial, unsigned char *buf)
327eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
328eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
329eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
330eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, buf, 1, 100);
331eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", VENDOR_READ_REQUEST_TYPE,
332eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, value, index, res, buf[0]);
333eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
334eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
335eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
336eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_write(__u16 value, __u16 index,
337eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial)
338eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
339eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
340eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
341eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
342eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	dbg("0x%x:0x%x:0x%x:0x%x  %d", VENDOR_WRITE_REQUEST_TYPE,
343eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, value, index, res);
344eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
345eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
346eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
347372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type = type_0;
3513e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	unsigned char *buf;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3543e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	buf = kmalloc(10, GFP_KERNEL);
3553e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	if (buf == NULL)
3563e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		return -ENOMEM;
3573e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serial->dev->descriptor.bDeviceClass == 0x02)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_0;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = HX;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0x00)
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("device type: %d", type);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
36980b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!priv)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&priv->lock);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->buf == NULL) {
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_waitqueue_head(&priv->delta_msr_wait);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->type = type;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], priv);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3823e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
3833e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
3843e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 0, serial);
3853e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
3863e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
3873e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
3883e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 1, serial);
3893e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
3903e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
3913e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0, 1, serial);
3923e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(1, 0, serial);
3933e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	if (type == HX)
3943e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		pl2303_vendor_write(2, 0x44, serial);
3953e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	else
3963e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		pl2303_vendor_write(2, 0x24, serial);
3973e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
3983e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup:
4023e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
4033a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	for (--i; i >= 0; --i) {
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl2303_buf_free(priv->buf);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(priv);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], NULL);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
412372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int set_control_lines(struct usb_device *dev, u8 value)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
4153a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox
416372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
417372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
418372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
419441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - value = %d, retval = %d", __func__, value, retval);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_send(struct usb_serial_port *port)
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count, result;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
429441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->write_urb_in_use) {
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
439372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			       port->bulk_out_size);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0) {
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 1;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
450441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__, count,
451372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      port->write_urb->transfer_buffer);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->transfer_buffer_length = count;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->dev = port->serial->dev;
455372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
457372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting write urb,"
458441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
4603a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		/* TODO: reschedule pl2303_send */
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
463cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev	usb_serial_port_softint(port);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46695da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
46795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox				const unsigned char *buf, int count)
468572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
469572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_private *priv = usb_get_serial_port_data(port);
470572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned long flags;
471572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
472441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d, %d bytes", __func__, port->number, count);
473572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
474572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (!count)
475572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return count;
476572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
477572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_lock_irqsave(&priv->lock, flags);
478572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	count = pl2303_buf_put(priv->buf, buf, count);
479572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
480572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
481572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pl2303_send(port);
482572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
483572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
484572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
485572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
48695da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_write_room(struct tty_struct *tty)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
48895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int room = 0;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
493441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	room = pl2303_buf_space_avail(priv->buf);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
499441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, room);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return room;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
50395da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_chars_in_buffer(struct tty_struct *tty)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
50595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars = 0;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
510441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chars = pl2303_buf_data_avail(priv->buf);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
516441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, chars);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return chars;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52095da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_set_termios(struct tty_struct *tty,
52195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		struct usb_serial_port *port, struct ktermios *old_termios)
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cflag;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
53125b8286805e856c8c7fda127018e31032c918015Frank Schaefer	const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
53225b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         4800, 7200, 9600, 14400, 19200, 28800, 38400,
53325b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         57600, 115200, 230400, 460800, 614400,
53425b8286805e856c8c7fda127018e31032c918015Frank Schaefer	                         921600, 1228800, 2457600, 3000000, 6000000 };
53525b8286805e856c8c7fda127018e31032c918015Frank Schaefer	int baud_floor, baud_ceil;
53625b8286805e856c8c7fda127018e31032c918015Frank Schaefer	int k;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
538441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s -  port %d", __func__, port->number);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
540bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	/* The PL2303 is reported to lose bytes if you change
541bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   serial settings even to the same values as before. Thus
542bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   we actually need to filter in this specific case */
543bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
54495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (!tty_termios_hw_change(tty->termios, old_termios))
545bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox		return;
546bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
54795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	cflag = tty->termios->c_cflag;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
549372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	buf = kzalloc(7, GFP_KERNEL);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
551441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dev_err(&port->dev, "%s - out of memory.\n", __func__);
552a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox		/* Report back no change occurred */
55395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		*tty->termios = *old_termios;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
557372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
558372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
559372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
560372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
561372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSIZE) {
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (cflag & CSIZE) {
5653a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS5:
5663a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 5;
5673a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
5683a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS6:
5693a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 6;
5703a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
5713a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS7:
5723a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 7;
5733a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
5743a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		default:
5753a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		case CS8:
5763a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			buf[6] = 8;
5773a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			break;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
579441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - data bits = %d", __func__, buf[6]);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58225b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* For reference buf[0]:buf[3] baud rate value */
58325b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* NOTE: Only the values defined in baud_sup are supported !
58425b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 *       => if unsupported values are set, the PL2303 seems to use
58525b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 *          9600 baud (at least my PL2303X always does)
58625b8286805e856c8c7fda127018e31032c918015Frank Schaefer	 */
58795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	baud = tty_get_baud_rate(tty);
58825b8286805e856c8c7fda127018e31032c918015Frank Schaefer	dbg("%s - baud requested = %d", __func__, baud);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud) {
59025b8286805e856c8c7fda127018e31032c918015Frank Schaefer		/* Set baudrate to nearest supported value */
59125b8286805e856c8c7fda127018e31032c918015Frank Schaefer		for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
59225b8286805e856c8c7fda127018e31032c918015Frank Schaefer			if (baud_sup[k] / baud) {
59325b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud_ceil = baud_sup[k];
59425b8286805e856c8c7fda127018e31032c918015Frank Schaefer				if (k==0) {
59525b8286805e856c8c7fda127018e31032c918015Frank Schaefer					baud = baud_ceil;
59625b8286805e856c8c7fda127018e31032c918015Frank Schaefer				} else {
59725b8286805e856c8c7fda127018e31032c918015Frank Schaefer					baud_floor = baud_sup[k-1];
59825b8286805e856c8c7fda127018e31032c918015Frank Schaefer					if ((baud_ceil % baud)
59925b8286805e856c8c7fda127018e31032c918015Frank Schaefer					    > (baud % baud_floor))
60025b8286805e856c8c7fda127018e31032c918015Frank Schaefer						baud = baud_floor;
60125b8286805e856c8c7fda127018e31032c918015Frank Schaefer					else
60225b8286805e856c8c7fda127018e31032c918015Frank Schaefer						baud = baud_ceil;
60325b8286805e856c8c7fda127018e31032c918015Frank Schaefer				}
60425b8286805e856c8c7fda127018e31032c918015Frank Schaefer				break;
60525b8286805e856c8c7fda127018e31032c918015Frank Schaefer			}
60625b8286805e856c8c7fda127018e31032c918015Frank Schaefer		}
60725b8286805e856c8c7fda127018e31032c918015Frank Schaefer		if (baud > 1228800) {
60825b8286805e856c8c7fda127018e31032c918015Frank Schaefer			/* type_0, type_1 only support up to 1228800 baud */
60925b8286805e856c8c7fda127018e31032c918015Frank Schaefer			if (priv->type != HX)
61025b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud = 1228800;
61125b8286805e856c8c7fda127018e31032c918015Frank Schaefer			else if (baud > 6000000)
61225b8286805e856c8c7fda127018e31032c918015Frank Schaefer				baud = 6000000;
61325b8286805e856c8c7fda127018e31032c918015Frank Schaefer		}
61425b8286805e856c8c7fda127018e31032c918015Frank Schaefer		dbg("%s - baud set = %d", __func__, baud);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[0] = baud & 0xff;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[1] = (baud >> 8) & 0xff;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[2] = (baud >> 16) & 0xff;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[3] = (baud >> 24) & 0xff;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSTOPB) {
62529cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		/* NOTE: Comply with "real" UARTs / RS232:
62629cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 *       use 1.5 instead of 2 stop bits with 5 data bits
62729cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		 */
62829cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		if ((cflag & CSIZE) == CS5) {
62929cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 1;
63029cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			dbg("%s - stop bits = 1.5", __func__);
63129cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		} else {
63229cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			buf[4] = 2;
63329cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer			dbg("%s - stop bits = 2", __func__);
63429cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer		}
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
637441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - stop bits = 1", __func__);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & PARENB) {
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cflag & PARODD) {
6476dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			if (cflag & CMSPAR) {
6486dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 3;
6496dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				dbg("%s - parity = mark", __func__);
6506dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
6516dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 1;
6526dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				dbg("%s - parity = odd", __func__);
6536dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
6556dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			if (cflag & CMSPAR) {
6566dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 4;
6576dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				dbg("%s - parity = space", __func__);
6586dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			} else {
6596dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				buf[5] = 2;
6606dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer				dbg("%s - parity = even", __func__);
6616dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer			}
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
665441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - parity = none", __func__);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
668372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
669372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
670372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
671372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0x21:0x20:0:0  %d", i);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cflag & CBAUD) == B0)
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_control_lines(serial->dev, control);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
687372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
690372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
691372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
692372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
693372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CRTSCTS) {
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == HX)
698eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x61, serial);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
700eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x41, serial);
701715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
702eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(0x0, 0x0, serial);
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
704572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
70525b8286805e856c8c7fda127018e31032c918015Frank Schaefer	/* Save resulting baud rate */
706df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox	if (baud)
70795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		tty_encode_baud_rate(tty, baud, baud);
708df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox
709572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
710572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
711572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
712335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on)
713335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
714335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
715335f8514f200e63d689113d29cb7253a5c282967Alan Cox	unsigned long flags;
716335f8514f200e63d689113d29cb7253a5c282967Alan Cox	u8 control;
717335f8514f200e63d689113d29cb7253a5c282967Alan Cox
718335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_lock_irqsave(&priv->lock, flags);
719335f8514f200e63d689113d29cb7253a5c282967Alan Cox	/* Change DTR and RTS */
720335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (on)
721335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
722335f8514f200e63d689113d29cb7253a5c282967Alan Cox	else
723335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
724335f8514f200e63d689113d29cb7253a5c282967Alan Cox	control = priv->line_control;
725335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_unlock_irqrestore(&priv->lock, flags);
726335f8514f200e63d689113d29cb7253a5c282967Alan Cox	set_control_lines(port->serial->dev, control);
727335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
728335f8514f200e63d689113d29cb7253a5c282967Alan Cox
729335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port)
730572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
731572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_private *priv = usb_get_serial_port_data(port);
732572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned long flags;
733572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
734441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
735572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
736572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_lock_irqsave(&priv->lock, flags);
737572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* clear out any remaining data in the buffer */
738572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pl2303_buf_clear(priv->buf);
739572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
740572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
741572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* shutdown our urbs */
742441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - shutting down urbs", __func__);
743572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->write_urb);
744572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->read_urb);
745572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
746572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
749a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
751606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios tmp_termios;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
756441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s -  port %d", __func__, port->number);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581694899fd1af43636351aac97f415fd3c9cefb1dDariusz M	if (priv->type != HX) {
7591694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
7601694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
7613e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	} else {
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
763eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(8, 0, serial);
764eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(9, 0, serial);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
76895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (tty)
76995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		pl2303_set_termios(tty, port, &tmp_termios);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - submitting read urb", __func__);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->read_urb->dev = serial->dev;
773372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
775372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting read urb,"
776441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
777335f8514f200e63d689113d29cb7253a5c282967Alan Cox		pl2303_close(port);
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - submitting interrupt urb", __func__);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->interrupt_in_urb->dev = serial->dev;
783372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
785372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
786441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
787335f8514f200e63d689113d29cb7253a5c282967Alan Cox		pl2303_close(port);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
790335f8514f200e63d689113d29cb7253a5c282967Alan Cox	port->port.drain_delay = 256;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
79495da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
795372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
79795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8026fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
8036fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
8046fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
805372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
815372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
817372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	return set_control_lines(port->serial->dev, control);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
82095da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
82295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
829441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d)", __func__, port->number);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8316fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
8326fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
8336fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
834372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
837372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
846441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - result = %x", __func__, result);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port)
852335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
853335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct pl2303_private *priv = usb_get_serial_port_data(port);
854335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (priv->line_status & UART_DCD)
855335f8514f200e63d689113d29cb7253a5c282967Alan Cox		return 1;
856335f8514f200e63d689113d29cb7253a5c282967Alan Cox	return 0;
857335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
858335f8514f200e63d689113d29cb7253a5c282967Alan Cox
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
867372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
869372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		interruptible_sleep_on(&priv->delta_msr_wait);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
876372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
877372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
879372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
880372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8813a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		changed = prevstatus ^ status;
882372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
8863a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89595da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_ioctl(struct tty_struct *tty, struct file *file,
896372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
89895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
899441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
9023a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	case TIOCMIWAIT:
9033a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
9043a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		return wait_modem_info(port, arg);
9053a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	default:
9063a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		dbg("%s not supported = 0x%04x", __func__, cmd);
9073a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox		break;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state)
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
91495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
919441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
9253a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	dbg("%s - turning break %s", __func__,
9263a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox			state == BREAK_OFF ? "off" : "on");
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
928372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
929372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
930372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
932441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - error sending break = %d", __func__, result);
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
935f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void pl2303_release(struct usb_serial *serial)
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
940441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s", __func__);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv) {
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pl2303_buf_free(priv->buf);
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
948372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	}
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
95297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
95397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
95497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
95597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
95697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
95797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
95897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 status_idx = UART_STATE;
95995f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier	u8 length = UART_STATE + 1;
9609c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	u16 idv, idp;
96197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
9629c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
9639c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
9649c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9659c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9669c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	if (idv == SIEMENS_VENDOR_ID) {
9679c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		if (idp == SIEMENS_PRODUCT_ID_X65 ||
9689c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_SX1 ||
9699c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_X75) {
9709c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9719c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			length = 1;
9729c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			status_idx = 0;
9739c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		}
97497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	}
97597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
97697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if (actual_length < length)
977a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
97897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
9793a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox	/* Save off the uart status for others to look at */
98097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
98197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
98297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
983430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel	if (priv->line_status & UART_BREAK_ERROR)
984430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel		usb_serial_handle_break(port);
985372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
98697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9887d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
990cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
99297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
993461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
994461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
996441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d)", __func__, port->number);
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
998461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
1006441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb shutting down with status: %d", __func__,
1007461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1010441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - nonzero urb status received: %d", __func__,
1011461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1015441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__,
1016372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
1017372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
101897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
1021461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
1022461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (retval)
1023372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&urb->dev->dev,
1024372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
1025441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, retval);
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1028d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Coxstatic void pl2303_push_data(struct tty_struct *tty,
1029d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		struct usb_serial_port *port, struct urb *urb,
1030d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		u8 line_status)
1031d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{
1032d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	unsigned char *data = urb->transfer_buffer;
1033d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* get tty_flag from status */
1034d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	char tty_flag = TTY_NORMAL;
1035d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* break takes precedence over parity, */
1036d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* which takes precedence over framing errors */
1037d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_BREAK_ERROR)
1038d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_BREAK;
1039d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_PARITY_ERROR)
1040d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_PARITY;
1041d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	else if (line_status & UART_FRAME_ERROR)
1042d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_flag = TTY_FRAME;
1043d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	dbg("%s - tty_flag = %d", __func__, tty_flag);
1044d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox
1045d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	tty_buffer_request_room(tty, urb->actual_length + 1);
1046d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	/* overrun is special, not associated with a char */
1047d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (line_status & UART_OVERRUN_ERROR)
1048d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
1049d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	if (port->console && port->sysrq) {
1050d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		int i;
1051d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		for (i = 0; i < urb->actual_length; ++i)
1052d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox			if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
1053d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox				tty_insert_flip_char(tty, data[i], tty_flag);
1054d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	} else
1055d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		tty_insert_flip_string(tty, data, urb->actual_length);
1056d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox	tty_flip_buffer_push(tty);
1057d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox}
1058d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox
10597d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_bulk_callback(struct urb *urb)
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1061cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tty;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1066461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
1067461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	u8 line_status;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1069441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (status) {
1072441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb status = %d", __func__, status);
107395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		if (!port->port.count) {
1074441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s - port is closed, exiting.", __func__);
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1077461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		if (status == -EPROTO) {
1078372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			/* PL2303 mysteriously fails with -EPROTO reschedule
1079372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			 * the read */
1080372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dbg("%s - caught -EPROTO, resubmitting the urb",
1081441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			    __func__);
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->dev = port->serial->dev;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = usb_submit_urb(urb, GFP_ATOMIC);
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (result)
1085372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				dev_err(&urb->dev->dev, "%s - failed"
1086372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					" resubmitting read urb, error %d\n",
1087441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison					__func__, result);
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1090441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - unable to handle the error, exiting.", __func__);
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1094441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__,
1095d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox			      urb->actual_length, urb->transfer_buffer);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
1098461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	line_status = priv->line_status;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
1101372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11034a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty = tty_port_tty_get(&port->port);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty && urb->actual_length) {
1105d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox		pl2303_push_data(tty, port, urb, line_status);
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11074a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty_kref_put(tty);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Schedule the next read _if_ we are still open */
110995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (port->port.count) {
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->dev = port->serial->dev;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = usb_submit_urb(urb, GFP_ATOMIC);
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
1113372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&urb->dev->dev, "%s - failed resubmitting"
1114441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison				" read urb, error %d\n", __func__, result);
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11207d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_write_bulk_callback(struct urb *urb)
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1122cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1125461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1127441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1129461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
1137441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb shutting down with status: %d", __func__,
1138461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* error in the urb, so we have to resubmit it */
1143441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - Overflow in write", __func__);
1144441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - nonzero write bulk status received: %d", __func__,
1145461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->transfer_buffer_length = 1;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->dev = port->serial->dev;
1148372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
1150372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&urb->dev->dev, "%s - failed resubmitting write"
1151441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison				" urb, error %d\n", __func__, result);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 0;
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* send any buffered data */
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pl2303_send(port);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1162572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */
1163572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
1164572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
1165572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
1166572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
1167572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
1168572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
1169d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.usb_driver = 		&pl2303_driver,
1170572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
1171572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
1172572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
1173335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.dtr_rts = 		pl2303_dtr_rts,
1174335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.carrier_raised =	pl2303_carrier_raised,
1175572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write =		pl2303_write,
1176572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
1177572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
1178572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
1179572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
1180572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
1181572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_bulk_callback =	pl2303_read_bulk_callback,
1182572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
1183572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write_bulk_callback =	pl2303_write_bulk_callback,
1184572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write_room =		pl2303_write_room,
1185572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.chars_in_buffer =	pl2303_chars_in_buffer,
1186572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
1187f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =		pl2303_release,
1188572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1190372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int __init pl2303_init(void)
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
1193372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_serial_register(&pl2303_device);
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_serial_register;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_register(&pl2303_driver);
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_register;
1200c197a8db59daf06dc5e77acd5a9681329cb22458Greg Kroah-Hartman	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register:
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_deregister(&pl2303_device);
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register:
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1208372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void __exit pl2303_exit(void)
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1210372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_deregister(&pl2303_driver);
1211372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_deregister(&pl2303_device);
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pl2303_init);
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl2303_exit);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not");
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1223