pl2303.c revision eb44da0b3aa0105cb38d81c5747a8feae64834be
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) },
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
598a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
6558381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
6857833ea6b95a3995149f1f6d1a8d8862ab7a0ba2Akira Tsukamoto	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
75a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
77a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
78e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
79acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
80c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
81c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
826cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
83c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
84491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
853b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
86b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
878fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
882d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
899e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
90002e8f2c80c6be76bb312940bc278fc10b2b2487Piotr Roszatycki	{ USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
91cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver pl2303_driver = {
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"pl2303",
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =	usb_serial_probe,
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =	usb_serial_disconnect,
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =	id_table,
102ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman	.no_dynamic_id = 	1,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST			0x23
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE			0x08
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_0,		/* don't know the difference between type 0 and */
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_1,		/* type 1, until someone from prolific tells us... */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HX,		/* HX version of the pl2303 chip */
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_buf *buf;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int write_urb_in_use;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t delta_msr_wait;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 termios_initialized;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
157572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_alloc
158572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
159572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Allocate a circular buffer and all associated memory.
160572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
161572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
162572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
163572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_buf *pb;
164572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
165572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (size == 0)
166572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
167572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
1685cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
169572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
170572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
171572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
172572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_buf = kmalloc(size, GFP_KERNEL);
173572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb->buf_buf == NULL) {
174572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb);
175572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
176572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
177572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
178572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_size = size;
179572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_get = pb->buf_put = pb->buf_buf;
180572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
181572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return pb;
182572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
183572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
184572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
185572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_free
186572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
187572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Free the buffer and all associated memory.
188572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
189572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_free(struct pl2303_buf *pb)
190572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
191572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb) {
192572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb->buf_buf);
193572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb);
194572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
195572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
196572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
197572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
198572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_clear
199572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
200572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Clear out all data in the circular buffer.
201572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
202572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_clear(struct pl2303_buf *pb)
203572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
204572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb != NULL)
205572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_get = pb->buf_put;
206572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		/* equivalent to a get of all data available */
207572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
208572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
209572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
210572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_data_avail
211572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
212572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of data available in the circular
213572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer.
214572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
215572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
216572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
217572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
218572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
219572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
220572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
221572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
222572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
223572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
224572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_space_avail
225572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
226572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of space available in the circular
227572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer.
228572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
229572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
230572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
231572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
232572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
233572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
234572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
235572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
236572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
237572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
238572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_put
239572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
240572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Copy data data from a user buffer and put it into the circular buffer.
241572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of space available.
242572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
243572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied.
244572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
245572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
246572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi				   unsigned int count)
247572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
248572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int len;
249572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
250572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
251572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
252572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
253572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len  = pl2303_buf_space_avail(pb);
254572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len)
255572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		count = len;
256572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
257572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count == 0)
258572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
259572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
260572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pb->buf_buf + pb->buf_size - pb->buf_put;
261572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len) {
262572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_put, buf, len);
263572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_buf, buf+len, count - len);
264572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_put = pb->buf_buf + count - len;
265572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	} else {
266572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_put, buf, count);
267572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (count < len)
268572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_put += count;
269572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		else /* count == len */
270572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_put = pb->buf_buf;
271572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
272572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
273572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
274572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
275572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
276572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
277572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_get
278572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
279572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Get data from the circular buffer and copy to the given buffer.
280572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of data available.
281572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
282572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied.
283572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
284572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
285572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi				   unsigned int count)
286572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
287572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int len;
288572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
289572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
290572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
291572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
292572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pl2303_buf_data_avail(pb);
293572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len)
294572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		count = len;
295572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
296572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count == 0)
297572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
298572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
299572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pb->buf_buf + pb->buf_size - pb->buf_get;
300572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len) {
301572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf, pb->buf_get, len);
302572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf+len, pb->buf_buf, count - len);
303572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_get = pb->buf_buf + count - len;
304572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	} else {
305572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf, pb->buf_get, count);
306572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (count < len)
307572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_get += count;
308572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		else /* count == len */
309572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_get = pb->buf_buf;
310572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
311572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
312572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
313572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
315eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_read(__u16 value, __u16 index,
316eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial, unsigned char *buf)
317eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
318eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
319eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
320eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, buf, 1, 100);
321eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", VENDOR_READ_REQUEST_TYPE,
322eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_READ_REQUEST, value, index, res, buf[0]);
323eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
324eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
325eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
326eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_write(__u16 value, __u16 index,
327eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		struct usb_serial *serial)
328eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{
329eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
330eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
331eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			value, index, NULL, 0, 100);
332eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	dbg("0x%x:0x%x:0x%x:0x%x  %d", VENDOR_WRITE_REQUEST_TYPE,
333eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			VENDOR_WRITE_REQUEST, value, index, res);
334eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	return res;
335eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp}
336eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp
337372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type = type_0;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serial->dev->descriptor.bDeviceClass == 0x02)
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_0;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = HX;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0x00)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("device type: %d", type);
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
35480b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!priv)
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&priv->lock);
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->buf == NULL) {
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_waitqueue_head(&priv->delta_msr_wait);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->type = type;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], priv);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup:
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (--i; i>=0; --i) {
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl2303_buf_free(priv->buf);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(priv);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], NULL);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
379372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int set_control_lines(struct usb_device *dev, u8 value)
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
383372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
384372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
385372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_send(struct usb_serial_port *port)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count, result;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->write_urb_in_use) {
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
406372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			       port->bulk_out_size);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0) {
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 1;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
417372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
418372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      port->write_urb->transfer_buffer);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->transfer_buffer_length = count;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->dev = port->serial->dev;
422372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
424372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting write urb,"
425372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			" error %d\n", __FUNCTION__, result);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO: reschedule pl2303_send
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
430cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev	usb_serial_port_softint(port);
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
433572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
434572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			int count)
435572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
436572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_private *priv = usb_get_serial_port_data(port);
437572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned long flags;
438572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
439572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
440572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
441572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (!count)
442572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return count;
443572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
444572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_lock_irqsave(&priv->lock, flags);
445572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	count = pl2303_buf_put(priv->buf, buf, count);
446572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
447572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
448572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pl2303_send(port);
449572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
450572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
451572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
452572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_write_room(struct usb_serial_port *port)
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int room = 0;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	room = pl2303_buf_space_avail(priv->buf);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - returns %d", __FUNCTION__, room);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return room;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_chars_in_buffer(struct usb_serial_port *port)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars = 0;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chars = pl2303_buf_data_avail(priv->buf);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - returns %d", __FUNCTION__, chars);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return chars;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
485372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_set_termios(struct usb_serial_port *port,
486606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox			       struct ktermios *old_termios)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cflag;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s -  port %d", __FUNCTION__, port->number);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!priv->termios_initialized) {
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*(port->tty->termios) = tty_std_termios;
502372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
503372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					      HUPCL | CLOCAL;
504df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox		port->tty->termios->c_ispeed = 9600;
505df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox		port->tty->termios->c_ospeed = 9600;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->termios_initialized = 1;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
510bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	/* The PL2303 is reported to lose bytes if you change
511bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   serial settings even to the same values as before. Thus
512bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	   we actually need to filter in this specific case */
513bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
514bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox	if (!tty_termios_hw_change(port->tty->termios, old_termios))
515bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox		return;
516bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cflag = port->tty->termios->c_cflag;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
519372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	buf = kzalloc(7, GFP_KERNEL);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
525372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
526372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
527372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
528372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
529372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSIZE) {
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (cflag & CSIZE) {
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS5:	buf[6] = 5;	break;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS6:	buf[6] = 6;	break;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS7:	buf[6] = 7;	break;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS8:	buf[6] = 8;	break;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
542e0c79f512cf469bc11fe9d53a4dcc5d0c39a3b79Alan Cox	baud = tty_get_baud_rate(port->tty);;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - baud = %d", __FUNCTION__, baud);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud) {
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[0] = baud & 0xff;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[1] = (baud >> 8) & 0xff;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[2] = (baud >> 16) & 0xff;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[3] = (baud >> 24) & 0xff;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSTOPB) {
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 2;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - stop bits = 2", __FUNCTION__);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - stop bits = 1", __FUNCTION__);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & PARENB) {
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cflag & PARODD) {
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf[5] = 1;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s - parity = odd", __FUNCTION__);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf[5] = 2;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s - parity = even", __FUNCTION__);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - parity = none", __FUNCTION__);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
580372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
581372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
582372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
583372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0x21:0x20:0:0  %d", i);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cflag & CBAUD) == B0)
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_control_lines(serial->dev, control);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
599372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
602372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
603372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
604372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
605372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CRTSCTS) {
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == HX)
610eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x61, serial);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
612eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp			pl2303_vendor_write(0x0, 0x41, serial);
613715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
614eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(0x0, 0x0, serial);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
616572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
617df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox	/* FIXME: Need to read back resulting baud rate */
618df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox	if (baud)
619df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox		tty_encode_baud_rate(port->tty, baud, baud);
620df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox
621572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
622572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
623572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
624572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_close(struct usb_serial_port *port, struct file *filp)
625572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
626572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_private *priv = usb_get_serial_port_data(port);
627572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned long flags;
628572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int c_cflag;
629572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	int bps;
630572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	long timeout;
631572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	wait_queue_t wait;
632572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
633572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	dbg("%s - port %d", __FUNCTION__, port->number);
634572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
635572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* wait for data to drain from the buffer */
636572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_lock_irqsave(&priv->lock, flags);
637572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	timeout = PL2303_CLOSING_WAIT;
638572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	init_waitqueue_entry(&wait, current);
639572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	add_wait_queue(&port->tty->write_wait, &wait);
640572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	for (;;) {
641572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		set_current_state(TASK_INTERRUPTIBLE);
642572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (pl2303_buf_data_avail(priv->buf) == 0 ||
643572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		    timeout == 0 || signal_pending(current) ||
644572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		    !usb_get_intfdata(port->serial->interface))	/* disconnect */
645572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			break;
646572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
647572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = schedule_timeout(timeout);
648572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		spin_lock_irqsave(&priv->lock, flags);
649572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
650572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	set_current_state(TASK_RUNNING);
651572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	remove_wait_queue(&port->tty->write_wait, &wait);
652572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* clear out any remaining data in the buffer */
653572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pl2303_buf_clear(priv->buf);
654572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
655572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
656572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* wait for characters to drain from the device */
657572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* (this is long enough for the entire 256 byte */
658572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* pl2303 hardware buffer to drain with no flow */
659572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* control for data rates of 1200 bps or more, */
660572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* for lower rates we should really know how much */
661572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* data is in the buffer to compute a delay */
662572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* that is not unnecessarily long) */
663572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	bps = tty_get_baud_rate(port->tty);
664572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (bps > 1200)
665572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = max((HZ*2560)/bps,HZ/10);
666572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	else
667572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = 2*HZ;
668572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	schedule_timeout_interruptible(timeout);
669572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
670572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* shutdown our urbs */
671572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	dbg("%s - shutting down urbs", __FUNCTION__);
672572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->write_urb);
673572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->read_urb);
674572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
675572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
676572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (port->tty) {
677572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		c_cflag = port->tty->termios->c_cflag;
678572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (c_cflag & HUPCL) {
679572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			/* drop DTR and RTS */
680572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			spin_lock_irqsave(&priv->lock, flags);
681572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			priv->line_control = 0;
682572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			spin_unlock_irqrestore(&priv->lock, flags);
683572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			set_control_lines(port->serial->dev, 0);
684572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		}
685572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
688372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_open(struct usb_serial_port *port, struct file *filp)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
690606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios tmp_termios;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s -  port %d", __FUNCTION__, port->number);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6981694899fd1af43636351aac97f415fd3c9cefb1dDariusz M	if (priv->type != HX) {
6991694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
7001694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
7011694899fd1af43636351aac97f415fd3c9cefb1dDariusz M	}
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf = kmalloc(10, GFP_KERNEL);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf==NULL)
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
707eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
708eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_write(0x0404, 0, serial);
709eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
710eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
711eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
712eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_write(0x0404, 1, serial);
713eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_read(0x8484, 0, serial, buf);
714eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_read(0x8383, 0, serial, buf);
715eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_write(0, 1, serial);
716eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp	pl2303_vendor_write(1, 0, serial);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->type == HX) {
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* HX chip */
720eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(2, 0x44, serial);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
722eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(8, 0, serial);
723eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(9, 0, serial);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
725eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp		pl2303_vendor_write(2, 0x24, serial);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buf);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->tty) {
732372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_set_termios(port, &tmp_termios);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	//FIXME: need to assert RTS and DTR if CRTSCTS off
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - submitting read urb", __FUNCTION__);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->read_urb->dev = serial->dev;
739372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
741372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting read urb,"
742372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			" error %d\n", __FUNCTION__, result);
743372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_close(port, NULL);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - submitting interrupt urb", __FUNCTION__);
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->interrupt_in_urb->dev = serial->dev;
749372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
751372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
752372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			" error %d\n", __FUNCTION__, result);
753372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_close(port, NULL);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
759372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
760372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7666fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
7676fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
7686fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
769372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
779372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	return set_control_lines(port->serial->dev, control);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
784372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d)", __FUNCTION__, port->number);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7946fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
7956fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
7966fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
797372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
800372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - result = %x", __FUNCTION__, result);
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
822372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
824372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		interruptible_sleep_on(&priv->delta_msr_wait);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
831372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
832372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
834372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
835372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changed=prevstatus^status;
837372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
850372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
851372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case TIOCMIWAIT:
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return wait_modem_info(port, arg);
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
868372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
882372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
883372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
884372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - error sending break = %d", __FUNCTION__, result);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
889372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_shutdown(struct usb_serial *serial)
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s", __FUNCTION__);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv) {
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pl2303_buf_free(priv->buf);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			usb_set_serial_port_data(serial->port[i], NULL);
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
903372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	}
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
90697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
90797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
90897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
90997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
91097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
91197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
91297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
91397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 status_idx = UART_STATE;
91495f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier	u8 length = UART_STATE + 1;
9159c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	u16 idv, idp;
91697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
9179c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
9189c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
9199c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9209c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9219c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	if (idv == SIEMENS_VENDOR_ID) {
9229c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		if (idp == SIEMENS_PRODUCT_ID_X65 ||
9239c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_SX1 ||
9249c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_X75) {
9259c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9269c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			length = 1;
9279c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			status_idx = 0;
9289c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		}
92997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	}
93097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
93197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if (actual_length < length)
932a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
93397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
93497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner        /* Save off the uart status for others to look at */
93597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
93697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
93797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
938372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
93997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9417d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
94597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
946461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
947461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d)", __FUNCTION__, port->number);
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
959372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("%s - urb shutting down with status: %d", __FUNCTION__,
960461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
963372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("%s - nonzero urb status received: %d", __FUNCTION__,
964461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
968372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
969372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
970372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
97197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
974461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
975461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (retval)
976372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&urb->dev->dev,
977372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
978461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman			__FUNCTION__, retval);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9817d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_bulk_callback(struct urb *urb)
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tty;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
990461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
991461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	u8 line_status;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tty_flag;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
996461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (status) {
997461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		dbg("%s - urb status = %d", __FUNCTION__, status);
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!port->open_count) {
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s - port is closed, exiting.", __FUNCTION__);
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1002461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		if (status == -EPROTO) {
1003372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			/* PL2303 mysteriously fails with -EPROTO reschedule
1004372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			 * the read */
1005372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dbg("%s - caught -EPROTO, resubmitting the urb",
1006372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    __FUNCTION__);
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->dev = port->serial->dev;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = usb_submit_urb(urb, GFP_ATOMIC);
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (result)
1010372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				dev_err(&urb->dev->dev, "%s - failed"
1011372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					" resubmitting read urb, error %d\n",
1012372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					__FUNCTION__, result);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1019372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
1020372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, data);
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get tty_flag from status */
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_flag = TTY_NORMAL;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
1026461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	line_status = priv->line_status;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
1029372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* break takes precedence over parity, */
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* which takes precedence over framing errors */
1033461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (line_status & UART_BREAK_ERROR )
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_BREAK;
1035461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	else if (line_status & UART_PARITY_ERROR)
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_PARITY;
1037461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	else if (line_status & UART_FRAME_ERROR)
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_FRAME;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty = port->tty;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty && urb->actual_length) {
104333f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		tty_buffer_request_room(tty, urb->actual_length + 1);
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* overrun is special, not associated with a char */
1045461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		if (line_status & UART_OVERRUN_ERROR)
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
104733f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		for (i = 0; i < urb->actual_length; ++i)
1048372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			tty_insert_flip_char(tty, data[i], tty_flag);
1049372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		tty_flip_buffer_push(tty);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Schedule the next read _if_ we are still open */
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->open_count) {
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->dev = port->serial->dev;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = usb_submit_urb(urb, GFP_ATOMIC);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
1057372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&urb->dev->dev, "%s - failed resubmitting"
1058372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				" read urb, error %d\n", __FUNCTION__, result);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10647d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_write_bulk_callback(struct urb *urb)
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1069461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1073461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
1081372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("%s - urb shutting down with status: %d", __FUNCTION__,
1082461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* error in the urb, so we have to resubmit it */
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - Overflow in write", __FUNCTION__);
1088372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
1089461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->transfer_buffer_length = 1;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->dev = port->serial->dev;
1092372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
1094372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&urb->dev->dev, "%s - failed resubmitting write"
1095372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				" urb, error %d\n", __FUNCTION__, result);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 0;
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* send any buffered data */
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pl2303_send(port);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1106572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */
1107572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
1108572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
1109572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
1110572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
1111572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
1112572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
1113d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.usb_driver = 		&pl2303_driver,
1114572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_interrupt_in =	NUM_DONT_CARE,
1115572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_bulk_in =		1,
1116572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_bulk_out =		1,
1117572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
1118572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
1119572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
1120572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write =		pl2303_write,
1121572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
1122572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
1123572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
1124572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
1125572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
1126572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_bulk_callback =	pl2303_read_bulk_callback,
1127572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
1128572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write_bulk_callback =	pl2303_write_bulk_callback,
1129572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write_room =		pl2303_write_room,
1130572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.chars_in_buffer =	pl2303_chars_in_buffer,
1131572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
1132572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.shutdown =		pl2303_shutdown,
1133572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1135372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int __init pl2303_init(void)
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
1138372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_serial_register(&pl2303_device);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_serial_register;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_register(&pl2303_driver);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_register;
114517a882fc0c91477b2582a6dfd4ca93ae7eb58cd3Greg Kroah-Hartman	info(DRIVER_DESC);
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register:
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_deregister(&pl2303_device);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register:
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1153372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void __exit pl2303_exit(void)
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1155372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_deregister(&pl2303_driver);
1156372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_deregister(&pl2303_device);
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pl2303_init);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl2303_exit);
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not");
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1168