pl2303.c revision 727df3569b358ef440683787c2b9fe8cc55a0954
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 *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See Documentation/usb/usb-serial.txt for more information on using this driver
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
30a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h"
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_CLOSING_WAIT	(30*HZ)
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_BUF_SIZE		1024
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_TMP_BUF_SIZE	1024
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_buf {
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int	buf_size;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_buf;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_get;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_put;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table [] = {
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
553d861494729c70d9ebeb7d93caa107897925c355Peter Moulder	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
58b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
594be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
60727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
628a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
6858381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
77a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
79a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
80e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
81acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
82c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
83c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
846cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
85c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
86491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
873b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
88b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
898fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
902d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
919e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
92002e8f2c80c6be76bb312940bc278fc10b2b2487Piotr Roszatycki	{ USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
93cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
97372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver pl2303_driver = {
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"pl2303",
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =	usb_serial_probe,
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =	usb_serial_disconnect,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =	id_table,
104fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.suspend =      usb_serial_suspend,
105fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.resume =       usb_serial_resume,
106ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman	.no_dynamic_id = 	1,
107fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp	.supports_autosuspend =	1,
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST			0x23
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE			0x08
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_0,		/* don't know the difference between type 0 and */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_1,		/* type 1, until someone from prolific tells us... */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HX,		/* HX version of the pl2303 chip */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_buf *buf;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int write_urb_in_use;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t delta_msr_wait;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 termios_initialized;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
162572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_alloc
163572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
164572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Allocate a circular buffer and all associated memory.
165572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
166572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
167572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
168572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_buf *pb;
169572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
170572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (size == 0)
171572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
172572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
1735cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
174572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
175572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
176572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
177572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_buf = kmalloc(size, GFP_KERNEL);
178572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb->buf_buf == NULL) {
179572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb);
180572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
181572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
182572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
183572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_size = size;
184572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_get = pb->buf_put = pb->buf_buf;
185572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
186572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return pb;
187572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
188572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
189572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
190572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_free
191572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
192572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Free the buffer and all associated memory.
193572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
194572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_free(struct pl2303_buf *pb)
195572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
196572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb) {
197572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb->buf_buf);
198572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb);
199572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
200572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
201572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
202572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
203572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_clear
204572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
205572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Clear out all data in the circular buffer.
206572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
207572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_clear(struct pl2303_buf *pb)
208572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
209572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb != NULL)
210572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_get = pb->buf_put;
211572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		/* equivalent to a get of all data available */
212572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
213572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
214572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
215572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_data_avail
216572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
217572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of data available in the circular
218572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer.
219572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
220572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
221572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
222572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
223572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
224572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
225572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
226572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
227572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
228572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
229572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_space_avail
230572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
231572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of space available in the circular
232572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer.
233572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
234572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
235572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
236572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
237572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
238572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
239572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
240572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
241572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
242572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
243572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_put
244572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
245572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Copy data data from a user buffer and put it into the circular buffer.
246572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of space available.
247572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
248572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied.
249572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
250572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
251572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi				   unsigned int count)
252572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
253572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int len;
254572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
255572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
256572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
257572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
258572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len  = pl2303_buf_space_avail(pb);
259572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len)
260572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		count = len;
261572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
262572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count == 0)
263572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
264572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
265572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pb->buf_buf + pb->buf_size - pb->buf_put;
266572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len) {
267572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_put, buf, len);
268572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_buf, buf+len, count - len);
269572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_put = pb->buf_buf + count - len;
270572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	} else {
271572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_put, buf, count);
272572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (count < len)
273572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_put += count;
274572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		else /* count == len */
275572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_put = pb->buf_buf;
276572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
277572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
278572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
279572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
280572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
281572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
282572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_get
283572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
284572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Get data from the circular buffer and copy to the given buffer.
285572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of data available.
286572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
287572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied.
288572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
289572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
290572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi				   unsigned int count)
291572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
292572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int len;
293572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
294572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
295572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
296572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
297572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pl2303_buf_data_avail(pb);
298572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len)
299572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		count = len;
300572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
301572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count == 0)
302572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
303572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
304572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pb->buf_buf + pb->buf_size - pb->buf_get;
305572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len) {
306572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf, pb->buf_get, len);
307572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf+len, pb->buf_buf, count - len);
308572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_get = pb->buf_buf + count - len;
309572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	} else {
310572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf, pb->buf_get, count);
311572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (count < len)
312572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_get += count;
313572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		else /* count == len */
314572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_get = pb->buf_buf;
315572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
316572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
317572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
318572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
320eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_read(__u16 value, __u16 index,
321eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial, unsigned char *buf)
322eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
323eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
324eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
325eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, buf, 1, 100);
326eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", VENDOR_READ_REQUEST_TYPE,
327eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, value, index, res, buf[0]);
328eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
329eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
330eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
331eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_write(__u16 value, __u16 index,
332eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial)
333eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
334eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
335eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
336eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
337eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	dbg("0x%x:0x%x:0x%x:0x%x  %d", VENDOR_WRITE_REQUEST_TYPE,
338eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, value, index, res);
339eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
340eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
341eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
342372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type = type_0;
3463e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	unsigned char *buf;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3493e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	buf = kmalloc(10, GFP_KERNEL);
3503e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	if (buf == NULL)
3513e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		return -ENOMEM;
3523e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serial->dev->descriptor.bDeviceClass == 0x02)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_0;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = HX;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0x00)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("device type: %d", type);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
36480b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!priv)
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&priv->lock);
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->buf == NULL) {
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_waitqueue_head(&priv->delta_msr_wait);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->type = type;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], priv);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3773e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
3783e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
3793e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 0, serial);
3803e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
3813e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
3823e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
3833e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0x0404, 1, serial);
3843e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
3853e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
3863e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(0, 1, serial);
3873e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	pl2303_vendor_write(1, 0, serial);
3883e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	if (type == HX)
3893e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		pl2303_vendor_write(2, 0x44, serial);
3903e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	else
3913e152505a57db6622deb1322c22551c046e33d16Sarah Sharp		pl2303_vendor_write(2, 0x24, serial);
3923e152505a57db6622deb1322c22551c046e33d16Sarah Sharp
3933e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup:
3973e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	kfree(buf);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (--i; i>=0; --i) {
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl2303_buf_free(priv->buf);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(priv);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], NULL);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
407372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int set_control_lines(struct usb_device *dev, u8 value)
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
412372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
413372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
414441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - value = %d, retval = %d", __func__, value, retval);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_send(struct usb_serial_port *port)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count, result;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
424441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->write_urb_in_use) {
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
434372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			       port->bulk_out_size);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0) {
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 1;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
445441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__, count,
446372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      port->write_urb->transfer_buffer);
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->transfer_buffer_length = count;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->dev = port->serial->dev;
450372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
452372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting write urb,"
453441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO: reschedule pl2303_send
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
458cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev	usb_serial_port_softint(port);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
462572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			int count)
463572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
464572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_private *priv = usb_get_serial_port_data(port);
465572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned long flags;
466572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
467441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d, %d bytes", __func__, port->number, count);
468572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
469572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (!count)
470572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return count;
471572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
472572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_lock_irqsave(&priv->lock, flags);
473572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	count = pl2303_buf_put(priv->buf, buf, count);
474572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
475572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
476572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pl2303_send(port);
477572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
478572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
479572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
480572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_write_room(struct usb_serial_port *port)
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int room = 0;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
487441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	room = pl2303_buf_space_avail(priv->buf);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
493441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, room);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return room;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_chars_in_buffer(struct usb_serial_port *port)
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars = 0;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
503441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chars = pl2303_buf_data_avail(priv->buf);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
509441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, chars);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return chars;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
513372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_set_termios(struct usb_serial_port *port,
514606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox			       struct ktermios *old_termios)
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cflag;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
525441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s -  port %d", __func__, port->number);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!priv->termios_initialized) {
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*(port->tty->termios) = tty_std_termios;
530372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
531372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					      HUPCL | CLOCAL;
532df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox		port->tty->termios->c_ispeed = 9600;
533df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox		port->tty->termios->c_ospeed = 9600;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->termios_initialized = 1;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
538bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	/* The PL2303 is reported to lose bytes if you change
539bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   serial settings even to the same values as before. Thus
540bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   we actually need to filter in this specific case */
541bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
542bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	if (!tty_termios_hw_change(port->tty->termios, old_termios))
543bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox		return;
544bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cflag = port->tty->termios->c_cflag;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
547372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	buf = kzalloc(7, GFP_KERNEL);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
549441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dev_err(&port->dev, "%s - out of memory.\n", __func__);
550a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox		/* Report back no change occurred */
551a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox		*port->tty->termios = *old_termios;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
555372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
556372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
557372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
558372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
559372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSIZE) {
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (cflag & CSIZE) {
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS5:	buf[6] = 5;	break;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS6:	buf[6] = 6;	break;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS7:	buf[6] = 7;	break;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS8:	buf[6] = 8;	break;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
569441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - data bits = %d", __func__, buf[6]);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
572e0c79f512cf469bc11fe9d53a4dcc5d0c39a3b79Alan Cox	baud = tty_get_baud_rate(port->tty);;
573441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - baud = %d", __func__, baud);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud) {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[0] = baud & 0xff;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[1] = (baud >> 8) & 0xff;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[2] = (baud >> 16) & 0xff;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[3] = (baud >> 24) & 0xff;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSTOPB) {
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 2;
586441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - stop bits = 2", __func__);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
589441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - stop bits = 1", __func__);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & PARENB) {
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cflag & PARODD) {
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf[5] = 1;
600441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s - parity = odd", __func__);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf[5] = 2;
603441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s - parity = even", __func__);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
607441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - parity = none", __func__);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
610372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
611372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
612372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
613372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0x21:0x20:0:0  %d", i);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cflag & CBAUD) == B0)
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_control_lines(serial->dev, control);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
629372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
632372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
633372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
634372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
635372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CRTSCTS) {
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == HX)
640eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x61, serial);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
642eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x41, serial);
643715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
644eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(0x0, 0x0, serial);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
646572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
647df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox	/* FIXME: Need to read back resulting baud rate */
648df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox	if (baud)
649df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox		tty_encode_baud_rate(port->tty, baud, baud);
650df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox
651572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
652572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
653572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
654572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_close(struct usb_serial_port *port, struct file *filp)
655572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
656572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_private *priv = usb_get_serial_port_data(port);
657572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned long flags;
658572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int c_cflag;
659572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	int bps;
660572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	long timeout;
661572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	wait_queue_t wait;
662572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
663441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
664572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
665572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* wait for data to drain from the buffer */
666572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_lock_irqsave(&priv->lock, flags);
667572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	timeout = PL2303_CLOSING_WAIT;
668572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	init_waitqueue_entry(&wait, current);
669572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	add_wait_queue(&port->tty->write_wait, &wait);
670572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	for (;;) {
671572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		set_current_state(TASK_INTERRUPTIBLE);
672572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (pl2303_buf_data_avail(priv->buf) == 0 ||
673572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		    timeout == 0 || signal_pending(current) ||
6740915f490d81c1a5098b399ec6c0be45bd421ee1dOliver Neukum		    port->serial->disconnected)
675572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			break;
676572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
677572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = schedule_timeout(timeout);
678572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		spin_lock_irqsave(&priv->lock, flags);
679572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
680572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	set_current_state(TASK_RUNNING);
681572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	remove_wait_queue(&port->tty->write_wait, &wait);
682572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* clear out any remaining data in the buffer */
683572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pl2303_buf_clear(priv->buf);
684572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
685572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
686572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* wait for characters to drain from the device */
687572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* (this is long enough for the entire 256 byte */
688572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* pl2303 hardware buffer to drain with no flow */
689572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* control for data rates of 1200 bps or more, */
690572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* for lower rates we should really know how much */
691572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* data is in the buffer to compute a delay */
692572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* that is not unnecessarily long) */
693572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	bps = tty_get_baud_rate(port->tty);
694572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (bps > 1200)
695572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = max((HZ*2560)/bps,HZ/10);
696572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	else
697572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = 2*HZ;
698572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	schedule_timeout_interruptible(timeout);
699572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
700572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* shutdown our urbs */
701441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - shutting down urbs", __func__);
702572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->write_urb);
703572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->read_urb);
704572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
705572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
706572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (port->tty) {
707572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		c_cflag = port->tty->termios->c_cflag;
708572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (c_cflag & HUPCL) {
709572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			/* drop DTR and RTS */
710572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			spin_lock_irqsave(&priv->lock, flags);
711572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			priv->line_control = 0;
712572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			spin_unlock_irqrestore(&priv->lock, flags);
713572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			set_control_lines(port->serial->dev, 0);
714572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		}
715572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
718372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_open(struct usb_serial_port *port, struct file *filp)
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
720606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios tmp_termios;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
725441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s -  port %d", __func__, port->number);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7271694899fd1af43636351aac97f415fd3c9cefb1dDariusz M	if (priv->type != HX) {
7281694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
7291694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
7303e152505a57db6622deb1322c22551c046e33d16Sarah Sharp	} else {
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
732eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(8, 0, serial);
733eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(9, 0, serial);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->tty) {
738372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_set_termios(port, &tmp_termios);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	//FIXME: need to assert RTS and DTR if CRTSCTS off
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
743441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - submitting read urb", __func__);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->read_urb->dev = serial->dev;
745372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
747372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting read urb,"
748441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
749372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_close(port, NULL);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
753441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - submitting interrupt urb", __func__);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->interrupt_in_urb->dev = serial->dev;
755372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
757372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
758441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			" error %d\n", __func__, result);
759372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_close(port, NULL);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
765372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
766372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7726fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
7736fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
7746fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
775372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
785372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
787372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	return set_control_lines(port->serial->dev, control);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
790372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
798441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d)", __func__, port->number);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8006fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
8016fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
8026fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
803372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
806372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
815441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - result = %x", __func__, result);
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
828372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
830372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		interruptible_sleep_on(&priv->delta_msr_wait);
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
837372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
838372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
840372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
841372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changed=prevstatus^status;
843372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
856372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
857372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
859441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case TIOCMIWAIT:
863441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return wait_modem_info(port, arg);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
867441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s not supported = 0x%04x", __func__, cmd);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
874372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
880441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
886441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - turning break %s", __func__, state==BREAK_OFF ? "off" : "on");
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
888372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
889372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
890372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
892441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - error sending break = %d", __func__, result);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
895372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_shutdown(struct usb_serial *serial)
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
900441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s", __func__);
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv) {
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pl2303_buf_free(priv->buf);
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			usb_set_serial_port_data(serial->port[i], NULL);
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
909372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	}
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
91397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
91497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
91597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
91697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
91797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
91897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
91997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 status_idx = UART_STATE;
92095f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier	u8 length = UART_STATE + 1;
9219c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	u16 idv, idp;
92297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
9239c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
9249c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
9259c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9269c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9279c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	if (idv == SIEMENS_VENDOR_ID) {
9289c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		if (idp == SIEMENS_PRODUCT_ID_X65 ||
9299c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_SX1 ||
9309c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_X75) {
9319c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9329c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			length = 1;
9339c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			status_idx = 0;
9349c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		}
93597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	}
93697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
93797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if (actual_length < length)
938a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
93997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
94097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner        /* Save off the uart status for others to look at */
94197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
94297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
94397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
944372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
94597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9477d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
949cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
95197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
952461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
953461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
955441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s (%d)", __func__, port->number);
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
957461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
965441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb shutting down with status: %d", __func__,
966461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
969441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - nonzero urb status received: %d", __func__,
970461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
974441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__,
975372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
976372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
97797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
980461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
981461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (retval)
982372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&urb->dev->dev,
983372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
984441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, retval);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9877d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_bulk_callback(struct urb *urb)
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
989cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tty;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
996461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
997461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	u8 line_status;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tty_flag;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1000441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1002461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (status) {
1003441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb status = %d", __func__, status);
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!port->open_count) {
1005441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s - port is closed, exiting.", __func__);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1008461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		if (status == -EPROTO) {
1009372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			/* PL2303 mysteriously fails with -EPROTO reschedule
1010372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			 * the read */
1011372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dbg("%s - caught -EPROTO, resubmitting the urb",
1012441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			    __func__);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->dev = port->serial->dev;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = usb_submit_urb(urb, GFP_ATOMIC);
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (result)
1016372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				dev_err(&urb->dev->dev, "%s - failed"
1017372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					" resubmitting read urb, error %d\n",
1018441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison					__func__, result);
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1021441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - unable to handle the error, exiting.", __func__);
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1025441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__,
1026372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, data);
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get tty_flag from status */
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_flag = TTY_NORMAL;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
1032461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	line_status = priv->line_status;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
1035372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* break takes precedence over parity, */
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* which takes precedence over framing errors */
1039461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (line_status & UART_BREAK_ERROR )
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_BREAK;
1041461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	else if (line_status & UART_PARITY_ERROR)
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_PARITY;
1043461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	else if (line_status & UART_FRAME_ERROR)
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_FRAME;
1045441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - tty_flag = %d", __func__, tty_flag);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty = port->tty;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty && urb->actual_length) {
104933f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		tty_buffer_request_room(tty, urb->actual_length + 1);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* overrun is special, not associated with a char */
1051461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		if (line_status & UART_OVERRUN_ERROR)
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
105333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		for (i = 0; i < urb->actual_length; ++i)
1054372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			tty_insert_flip_char(tty, data[i], tty_flag);
1055372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		tty_flip_buffer_push(tty);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Schedule the next read _if_ we are still open */
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->open_count) {
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->dev = port->serial->dev;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = usb_submit_urb(urb, GFP_ATOMIC);
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
1063372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&urb->dev->dev, "%s - failed resubmitting"
1064441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison				" read urb, error %d\n", __func__, result);
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10707d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_write_bulk_callback(struct urb *urb)
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1072cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port =  urb->context;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1075461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1077441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1079461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
1087441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb shutting down with status: %d", __func__,
1088461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* error in the urb, so we have to resubmit it */
1093441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - Overflow in write", __func__);
1094441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - nonzero write bulk status received: %d", __func__,
1095461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->transfer_buffer_length = 1;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->dev = port->serial->dev;
1098372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
1100372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&urb->dev->dev, "%s - failed resubmitting write"
1101441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison				" urb, error %d\n", __func__, result);
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 0;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* send any buffered data */
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pl2303_send(port);
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1112572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */
1113572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
1114572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
1115572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
1116572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
1117572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
1118572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
1119d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.usb_driver = 		&pl2303_driver,
1120572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
1121572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
1122572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
1123572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write =		pl2303_write,
1124572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
1125572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
1126572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
1127572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
1128572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
1129572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_bulk_callback =	pl2303_read_bulk_callback,
1130572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
1131572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write_bulk_callback =	pl2303_write_bulk_callback,
1132572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write_room =		pl2303_write_room,
1133572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.chars_in_buffer =	pl2303_chars_in_buffer,
1134572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
1135572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.shutdown =		pl2303_shutdown,
1136572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1138372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int __init pl2303_init(void)
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
1141372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_serial_register(&pl2303_device);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_serial_register;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_register(&pl2303_driver);
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_register;
114817a882fc0c91477b2582a6dfd4ca93ae7eb58cd3Greg Kroah-Hartman	info(DRIVER_DESC);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register:
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_deregister(&pl2303_device);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register:
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1156372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void __exit pl2303_exit(void)
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1158372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_deregister(&pl2303_driver);
1159372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_deregister(&pl2303_device);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pl2303_init);
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl2303_exit);
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not");
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171