pl2303.c revision 461d696aeeae294ad22dfcaae462d1757f955778
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) },
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
6458381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
73a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
75a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
76acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
77c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
78c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
796cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
80c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
81491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
823b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
83b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
848fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
85b697f70f763fe92d5fd05e7e2043bd2b5f12b073Wesley PA	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
862d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
90372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver pl2303_driver = {
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"pl2303",
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =	usb_serial_probe,
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =	usb_serial_disconnect,
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =	id_table,
97ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman	.no_dynamic_id = 	1,
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST			0x23
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE			0x08
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_0,		/* don't know the difference between type 0 and */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_1,		/* type 1, until someone from prolific tells us... */
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HX,		/* HX version of the pl2303 chip */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_buf *buf;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int write_urb_in_use;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t delta_msr_wait;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 termios_initialized;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
152572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_alloc
153572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
154572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Allocate a circular buffer and all associated memory.
155572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
156572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
157572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
158572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_buf *pb;
159572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
160572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (size == 0)
161572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
162572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
1635cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
164572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
165572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
166572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
167572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_buf = kmalloc(size, GFP_KERNEL);
168572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb->buf_buf == NULL) {
169572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb);
170572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return NULL;
171572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
172572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
173572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_size = size;
174572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pb->buf_get = pb->buf_put = pb->buf_buf;
175572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
176572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return pb;
177572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
178572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
179572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
180572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_free
181572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
182572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Free the buffer and all associated memory.
183572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
184572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_free(struct pl2303_buf *pb)
185572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
186572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb) {
187572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb->buf_buf);
188572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		kfree(pb);
189572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
190572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
191572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
192572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
193572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_clear
194572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
195572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Clear out all data in the circular buffer.
196572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
197572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_clear(struct pl2303_buf *pb)
198572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
199572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb != NULL)
200572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_get = pb->buf_put;
201572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		/* equivalent to a get of all data available */
202572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
203572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
204572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
205572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_data_avail
206572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
207572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of data available in the circular
208572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer.
209572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
210572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
211572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
212572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
213572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
214572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
215572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
216572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
217572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
218572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
219572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_space_avail
220572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
221572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of space available in the circular
222572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer.
223572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
224572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
225572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
226572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
227572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
228572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
229572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
230572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
231572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
232572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
233572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_put
234572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
235572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Copy data data from a user buffer and put it into the circular buffer.
236572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of space available.
237572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
238572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied.
239572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
240572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
241572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi				   unsigned int count)
242572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
243572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int len;
244572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
245572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
246572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
247572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
248572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len  = pl2303_buf_space_avail(pb);
249572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len)
250572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		count = len;
251572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
252572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count == 0)
253572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
254572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
255572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pb->buf_buf + pb->buf_size - pb->buf_put;
256572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len) {
257572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_put, buf, len);
258572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_buf, buf+len, count - len);
259572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_put = pb->buf_buf + count - len;
260572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	} else {
261572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(pb->buf_put, buf, count);
262572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (count < len)
263572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_put += count;
264572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		else /* count == len */
265572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_put = pb->buf_buf;
266572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
267572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
268572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
269572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
270572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
271572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/*
272572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_get
273572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
274572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Get data from the circular buffer and copy to the given buffer.
275572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of data available.
276572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi *
277572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied.
278572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */
279572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
280572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi				   unsigned int count)
281572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
282572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int len;
283572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
284572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (pb == NULL)
285572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
286572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
287572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pl2303_buf_data_avail(pb);
288572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len)
289572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		count = len;
290572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
291572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count == 0)
292572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return 0;
293572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
294572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	len = pb->buf_buf + pb->buf_size - pb->buf_get;
295572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (count > len) {
296572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf, pb->buf_get, len);
297572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf+len, pb->buf_buf, count - len);
298572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		pb->buf_get = pb->buf_buf + count - len;
299572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	} else {
300572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		memcpy(buf, pb->buf_get, count);
301572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (count < len)
302572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_get += count;
303572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		else /* count == len */
304572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			pb->buf_get = pb->buf_buf;
305572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
306572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
307572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
308572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
310372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial)
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type = type_0;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serial->dev->descriptor.bDeviceClass == 0x02)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_0;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = HX;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0x00)
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("device type: %d", type);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
32780b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!priv)
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&priv->lock);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->buf == NULL) {
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_waitqueue_head(&priv->delta_msr_wait);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->type = type;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], priv);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup:
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (--i; i>=0; --i) {
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl2303_buf_free(priv->buf);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(priv);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], NULL);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
352372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int set_control_lines(struct usb_device *dev, u8 value)
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
356372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
357372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
358372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 value, 0, NULL, 0, 100);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_send(struct usb_serial_port *port)
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count, result;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->write_urb_in_use) {
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
379372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			       port->bulk_out_size);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0) {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 1;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
390372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
391372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      port->write_urb->transfer_buffer);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->transfer_buffer_length = count;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->dev = port->serial->dev;
395372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
397372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting write urb,"
398372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			" error %d\n", __FUNCTION__, result);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO: reschedule pl2303_send
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
403cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev	usb_serial_port_softint(port);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
406572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
407572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			int count)
408572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
409572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_private *priv = usb_get_serial_port_data(port);
410572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned long flags;
411572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
412572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
413572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
414572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (!count)
415572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		return count;
416572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
417572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_lock_irqsave(&priv->lock, flags);
418572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	count = pl2303_buf_put(priv->buf, buf, count);
419572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
420572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
421572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pl2303_send(port);
422572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
423572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	return count;
424572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
425572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_write_room(struct usb_serial_port *port)
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int room = 0;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	room = pl2303_buf_space_avail(priv->buf);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - returns %d", __FUNCTION__, room);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return room;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_chars_in_buffer(struct usb_serial_port *port)
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars = 0;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chars = pl2303_buf_data_avail(priv->buf);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - returns %d", __FUNCTION__, chars);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return chars;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
458372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_set_termios(struct usb_serial_port *port,
459606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox			       struct ktermios *old_termios)
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cflag;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s -  port %d", __FUNCTION__, port->number);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((!port->tty) || (!port->tty->termios)) {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - no tty structures", __FUNCTION__);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!priv->termios_initialized) {
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*(port->tty->termios) = tty_std_termios;
480372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
481372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					      HUPCL | CLOCAL;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->termios_initialized = 1;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cflag = port->tty->termios->c_cflag;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check that they really want us to change something */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_termios) {
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((cflag == old_termios->c_cflag) &&
490372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
491372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		     RELEVANT_IFLAG(old_termios->c_iflag))) {
492372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dbg("%s - nothing to change...", __FUNCTION__);
493372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			return;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
497372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	buf = kzalloc(7, GFP_KERNEL);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
503372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
504372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
505372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    0, 0, buf, 7, 100);
506372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	dbg("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
507372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSIZE) {
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (cflag & CSIZE) {
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS5:	buf[6] = 5;	break;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS6:	buf[6] = 6;	break;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS7:	buf[6] = 7;	break;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS8:	buf[6] = 8;	break;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baud = 0;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cflag & CBAUD) {
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B0:	baud = 0;	break;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B75:	baud = 75;	break;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B150:	baud = 150;	break;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B300:	baud = 300;	break;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B600:	baud = 600;	break;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B1200:	baud = 1200;	break;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B1800:	baud = 1800;	break;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B2400:	baud = 2400;	break;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B4800:	baud = 4800;	break;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B9600:	baud = 9600;	break;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B19200:	baud = 19200;	break;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B38400:	baud = 38400;	break;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B57600:	baud = 57600;	break;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B115200:	baud = 115200;	break;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B230400:	baud = 230400;	break;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B460800:	baud = 460800;	break;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
539372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&port->dev, "pl2303 driver does not support"
540372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				" the baudrate requested (fix it)\n");
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
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		__u16 index;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == HX)
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			index = 0x61;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			index = 0x41;
614372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		i = usb_control_msg(serial->dev,
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    usb_sndctrlpipe(serial->dev, 0),
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    VENDOR_WRITE_REQUEST,
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    VENDOR_WRITE_REQUEST_TYPE,
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    0x0, index, NULL, 0, 100);
619372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("0x40:0x1:0x0:0x%x  %d", index, i);
620715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick	} else {
621715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick		i = usb_control_msg(serial->dev,
622715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick				    usb_sndctrlpipe(serial->dev, 0),
623715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick				    VENDOR_WRITE_REQUEST,
624715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick				    VENDOR_WRITE_REQUEST_TYPE,
625715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick				    0x0, 0x0, NULL, 0, 100);
626715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick		dbg ("0x40:0x1:0x0:0x0  %d", i);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
628572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
629572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	kfree(buf);
630572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}
631572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
632572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_close(struct usb_serial_port *port, struct file *filp)
633572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{
634572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	struct pl2303_private *priv = usb_get_serial_port_data(port);
635572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned long flags;
636572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	unsigned int c_cflag;
637572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	int bps;
638572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	long timeout;
639572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	wait_queue_t wait;
640572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
641572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	dbg("%s - port %d", __FUNCTION__, port->number);
642572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
643572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* wait for data to drain from the buffer */
644572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_lock_irqsave(&priv->lock, flags);
645572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	timeout = PL2303_CLOSING_WAIT;
646572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	init_waitqueue_entry(&wait, current);
647572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	add_wait_queue(&port->tty->write_wait, &wait);
648572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	for (;;) {
649572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		set_current_state(TASK_INTERRUPTIBLE);
650572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (pl2303_buf_data_avail(priv->buf) == 0 ||
651572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		    timeout == 0 || signal_pending(current) ||
652572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		    !usb_get_intfdata(port->serial->interface))	/* disconnect */
653572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			break;
654572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
655572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = schedule_timeout(timeout);
656572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		spin_lock_irqsave(&priv->lock, flags);
657572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
658572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	set_current_state(TASK_RUNNING);
659572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	remove_wait_queue(&port->tty->write_wait, &wait);
660572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* clear out any remaining data in the buffer */
661572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	pl2303_buf_clear(priv->buf);
662572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
663572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
664572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* wait for characters to drain from the device */
665572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* (this is long enough for the entire 256 byte */
666572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* pl2303 hardware buffer to drain with no flow */
667572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* control for data rates of 1200 bps or more, */
668572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* for lower rates we should really know how much */
669572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* data is in the buffer to compute a delay */
670572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* that is not unnecessarily long) */
671572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	bps = tty_get_baud_rate(port->tty);
672572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (bps > 1200)
673572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = max((HZ*2560)/bps,HZ/10);
674572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	else
675572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		timeout = 2*HZ;
676572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	schedule_timeout_interruptible(timeout);
677572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
678572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	/* shutdown our urbs */
679572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	dbg("%s - shutting down urbs", __FUNCTION__);
680572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->write_urb);
681572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->read_urb);
682572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	usb_kill_urb(port->interrupt_in_urb);
683572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi
684572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	if (port->tty) {
685572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		c_cflag = port->tty->termios->c_cflag;
686572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		if (c_cflag & HUPCL) {
687572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			/* drop DTR and RTS */
688572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			spin_lock_irqsave(&priv->lock, flags);
689572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			priv->line_control = 0;
690572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			spin_unlock_irqrestore(&priv->lock, flags);
691572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi			set_control_lines(port->serial->dev, 0);
692572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		}
693572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
696372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_open(struct usb_serial_port *port, struct file *filp)
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
698606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios tmp_termios;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s -  port %d", __FUNCTION__, port->number);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061694899fd1af43636351aac97f415fd3c9cefb1dDariusz M	if (priv->type != HX) {
7071694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->write_urb->pipe);
7081694899fd1af43636351aac97f415fd3c9cefb1dDariusz M		usb_clear_halt(serial->dev, port->read_urb->pipe);
7091694899fd1af43636351aac97f415fd3c9cefb1dDariusz M	}
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf = kmalloc(10, GFP_KERNEL);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf==NULL)
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FISH(a,b,c,d)								\
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       b, a, c, d, buf, 1, 100);			\
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,result,buf[0]);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SOUP(a,b,c,d)								\
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),	\
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       b, a, c, d, NULL, 0, 100);			\
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->type == HX) {
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* HX chip */
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buf);
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->tty) {
750372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_set_termios(port, &tmp_termios);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	//FIXME: need to assert RTS and DTR if CRTSCTS off
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - submitting read urb", __FUNCTION__);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->read_urb->dev = serial->dev;
757372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
759372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting read urb,"
760372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			" error %d\n", __FUNCTION__, result);
761372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_close(port, NULL);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - submitting interrupt urb", __FUNCTION__);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->interrupt_in_urb->dev = serial->dev;
767372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
769372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
770372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			" error %d\n", __FUNCTION__, result);
771372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		pl2303_close(port, NULL);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
777372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
778372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			   unsigned int set, unsigned int clear)
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7846fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
7856fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
7866fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
787372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
797372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
799372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	return set_control_lines(port->serial->dev, control);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
802372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d)", __FUNCTION__, port->number);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8126fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
8136fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
8146fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
815372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
818372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - result = %x", __FUNCTION__, result);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
840372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_lock_irqsave(&priv->lock, flags);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
842372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	spin_unlock_irqrestore(&priv->lock, flags);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		interruptible_sleep_on(&priv->delta_msr_wait);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
849372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
850372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_lock_irqsave(&priv->lock, flags);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
852372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		spin_unlock_irqrestore(&priv->lock, flags);
853372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changed=prevstatus^status;
855372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
868372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
869372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			unsigned int cmd, unsigned long arg)
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case TIOCMIWAIT:
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return wait_modem_info(port, arg);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
886372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
900372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
901372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
902372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				 0, NULL, 0, 100);
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - error sending break = %d", __FUNCTION__, result);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
907372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_shutdown(struct usb_serial *serial)
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s", __FUNCTION__);
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv) {
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pl2303_buf_free(priv->buf);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			usb_set_serial_port_data(serial->port[i], NULL);
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
921372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	}
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
92497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
92597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
92697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
92797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
92897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
92997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
93097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
93197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 status_idx = UART_STATE;
93295f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier	u8 length = UART_STATE + 1;
9339c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	u16 idv, idp;
93497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
9359c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
9369c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
9379c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9389c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9399c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi	if (idv == SIEMENS_VENDOR_ID) {
9409c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		if (idp == SIEMENS_PRODUCT_ID_X65 ||
9419c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_SX1 ||
9429c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		    idp == SIEMENS_PRODUCT_ID_X75) {
9439c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi
9449c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			length = 1;
9459c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi			status_idx = 0;
9469c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi		}
94797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	}
94897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
94997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if (actual_length < length)
950a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino		return;
95197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
95297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner        /* Save off the uart status for others to look at */
95397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
95497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
95597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
956372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
95797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9597d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb)
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
96397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
964461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
965461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int retval;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d)", __FUNCTION__, port->number);
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
969461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
977372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("%s - urb shutting down with status: %d", __FUNCTION__,
978461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
981372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("%s - nonzero urb status received: %d", __FUNCTION__,
982461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
986372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
987372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, urb->transfer_buffer);
988372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
98997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
992461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	retval = usb_submit_urb(urb, GFP_ATOMIC);
993461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (retval)
994372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dev_err(&urb->dev->dev,
995372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			"%s - usb_submit_urb failed with result %d\n",
996461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman			__FUNCTION__, retval);
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_bulk_callback(struct urb *urb)
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tty;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1008461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
1009461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	u8 line_status;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tty_flag;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1014461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (status) {
1015461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		dbg("%s - urb status = %d", __FUNCTION__, status);
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!port->open_count) {
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s - port is closed, exiting.", __FUNCTION__);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1020461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		if (status == -EPROTO) {
1021372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			/* PL2303 mysteriously fails with -EPROTO reschedule
1022372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			 * the read */
1023372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dbg("%s - caught -EPROTO, resubmitting the urb",
1024372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			    __FUNCTION__);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->dev = port->serial->dev;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = usb_submit_urb(urb, GFP_ATOMIC);
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (result)
1028372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				dev_err(&urb->dev->dev, "%s - failed"
1029372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					" resubmitting read urb, error %d\n",
1030372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi					__FUNCTION__, result);
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1037372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
1038372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			      urb->actual_length, data);
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get tty_flag from status */
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_flag = TTY_NORMAL;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
1044461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	line_status = priv->line_status;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
1047372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	wake_up_interruptible(&priv->delta_msr_wait);
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* break takes precedence over parity, */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* which takes precedence over framing errors */
1051461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	if (line_status & UART_BREAK_ERROR )
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_BREAK;
1053461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	else if (line_status & UART_PARITY_ERROR)
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_PARITY;
1055461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	else if (line_status & UART_FRAME_ERROR)
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_FRAME;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty = port->tty;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty && urb->actual_length) {
106133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		tty_buffer_request_room(tty, urb->actual_length + 1);
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* overrun is special, not associated with a char */
1063461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		if (line_status & UART_OVERRUN_ERROR)
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
106533f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox		for (i = 0; i < urb->actual_length; ++i)
1066372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			tty_insert_flip_char(tty, data[i], tty_flag);
1067372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		tty_flip_buffer_push(tty);
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Schedule the next read _if_ we are still open */
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->open_count) {
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->dev = port->serial->dev;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = usb_submit_urb(urb, GFP_ATOMIC);
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
1075372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&urb->dev->dev, "%s - failed resubmitting"
1076372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				" read urb, error %d\n", __FUNCTION__, result);
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10827d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_write_bulk_callback(struct urb *urb)
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
1087461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	int status = urb->status;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman	switch (status) {
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
1099372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("%s - urb shutting down with status: %d", __FUNCTION__,
1100461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* error in the urb, so we have to resubmit it */
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - Overflow in write", __FUNCTION__);
1106372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
1107461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman		    status);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->transfer_buffer_length = 1;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->dev = port->serial->dev;
1110372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
1112372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi			dev_err(&urb->dev->dev, "%s - failed resubmitting write"
1113372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi				" urb, error %d\n", __FUNCTION__, result);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 0;
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* send any buffered data */
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pl2303_send(port);
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1124572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */
1125572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = {
1126572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.driver = {
1127572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.owner =	THIS_MODULE,
1128572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi		.name =		"pl2303",
1129572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	},
1130572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.id_table =		id_table,
1131d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.usb_driver = 		&pl2303_driver,
1132572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_interrupt_in =	NUM_DONT_CARE,
1133572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_bulk_in =		1,
1134572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_bulk_out =		1,
1135572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.num_ports =		1,
1136572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.open =			pl2303_open,
1137572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.close =		pl2303_close,
1138572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write =		pl2303_write,
1139572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.ioctl =		pl2303_ioctl,
1140572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.break_ctl =		pl2303_break_ctl,
1141572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.set_termios =		pl2303_set_termios,
1142572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmget =		pl2303_tiocmget,
1143572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.tiocmset =		pl2303_tiocmset,
1144572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_bulk_callback =	pl2303_read_bulk_callback,
1145572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.read_int_callback =	pl2303_read_int_callback,
1146572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write_bulk_callback =	pl2303_write_bulk_callback,
1147572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.write_room =		pl2303_write_room,
1148572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.chars_in_buffer =	pl2303_chars_in_buffer,
1149572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.attach =		pl2303_startup,
1150572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi	.shutdown =		pl2303_shutdown,
1151572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi};
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1153372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int __init pl2303_init(void)
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
1156372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_serial_register(&pl2303_device);
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_serial_register;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_register(&pl2303_driver);
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_register;
116317a882fc0c91477b2582a6dfd4ca93ae7eb58cd3Greg Kroah-Hartman	info(DRIVER_DESC);
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register:
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_deregister(&pl2303_device);
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register:
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void __exit pl2303_exit(void)
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1173372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_deregister(&pl2303_driver);
1174372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi	usb_serial_deregister(&pl2303_device);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pl2303_init);
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl2303_exit);
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not");
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1186