pl2303.c revision 97bb13ec5bc156352cca8af90080597e04299a73
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prolific PL2303 USB to serial adaptor driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001-2004 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 *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This program is free software; you can redistribute it and/or modify
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	it under the terms of the GNU General Public License as published by
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the Free Software Foundation; either version 2 of the License, or
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	(at your option) any later version.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See Documentation/usb/usb-serial.txt for more information on using this driver
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2002_Mar_26 gkh
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	allowed driver to work properly if there is no tty assigned to a port
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	(this happens for serial console devices.)
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001_Oct_06 gkh
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Added RTS and DTR line control.  Thanks to joe@bndlg.de for parts of it.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001_Sep_19 gkh
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Added break support.
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001_Aug_30 gkh
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	fixed oops in write_bulk_callback.
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001_Aug_28 gkh
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	reworked buffer logic to be like other usb-serial drivers.  Hopefully
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	removing some reported problems.
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001_Jun_06 gkh
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	finished porting to 2.4 format.
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "usb-serial.h"
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h"
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "v0.12"
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_CLOSING_WAIT	(30*HZ)
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_BUF_SIZE		1024
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_TMP_BUF_SIZE	1024
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DECLARE_MUTEX(pl2303_tmp_buf_sem);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_buf {
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int	buf_size;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_buf;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_get;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf_put;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table [] = {
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }					/* Terminating entry */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (usb, id_table);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver pl2303_driver = {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner =	THIS_MODULE,
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"pl2303",
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =	usb_serial_probe,
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =	usb_serial_disconnect,
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =	id_table,
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE		0x21
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST		0x20
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE	0x21
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST		0x22
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR			0x01
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS			0x02
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE		0x21
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST			0x23
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON			0xffff
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF			0x0000
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE		0xa1
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST		0x21
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE	0x40
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST		0x01
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE	0xc0
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST		0x01
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE			0x08
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK	0x74
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD			0x01
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR			0x02
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR		0x04
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING			0x08
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR		0x10
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR		0x20
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR		0x40
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS			0x80
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* function prototypes for a PL2303 serial converter */
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_open (struct usb_serial_port *port, struct file *filp);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_close (struct usb_serial_port *port, struct file *filp);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_set_termios (struct usb_serial_port *port,
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct termios *old);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned int cmd, unsigned long arg);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_write (struct usb_serial_port *port,
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 const unsigned char *buf, int count);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_send (struct usb_serial_port *port);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_write_room(struct usb_serial_port *port);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_chars_in_buffer(struct usb_serial_port *port);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_tiocmget (struct usb_serial_port *port, struct file *file);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    unsigned int set, unsigned int clear);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_startup (struct usb_serial *serial);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_shutdown (struct usb_serial *serial);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_buf_free(struct pl2303_buf *pb);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_buf_clear(struct pl2303_buf *pb);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int count);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int count);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* All of the device info needed for the PL2303 SIO serial converter */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_serial_device_type pl2303_device = {
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner =		THIS_MODULE,
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =			"PL-2303",
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =		id_table,
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.num_interrupt_in =	NUM_DONT_CARE,
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.num_bulk_in =		1,
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.num_bulk_out =		1,
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.num_ports =		1,
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open =			pl2303_open,
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.close =		pl2303_close,
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write =		pl2303_write,
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl =		pl2303_ioctl,
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.break_ctl =		pl2303_break_ctl,
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios =		pl2303_set_termios,
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmget =		pl2303_tiocmget,
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmset =		pl2303_tiocmset,
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_bulk_callback =	pl2303_read_bulk_callback,
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_int_callback =	pl2303_read_int_callback,
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_bulk_callback =	pl2303_write_bulk_callback,
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_room =		pl2303_write_room,
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.chars_in_buffer =	pl2303_chars_in_buffer,
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attach =		pl2303_startup,
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.shutdown =		pl2303_shutdown,
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_0,		/* don't know the difference between type 0 and */
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type_1,		/* type 1, until someone from prolific tells us... */
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	HX,		/* HX version of the pl2303 chip */
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private {
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_buf *buf;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int write_urb_in_use;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t delta_msr_wait;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_control;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 line_status;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 termios_initialized;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_startup (struct usb_serial *serial)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum pl2303_type type = type_0;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (serial->dev->descriptor.bDeviceClass == 0x02)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_0;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = HX;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0x00)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = type_1;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("device type: %d", type);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!priv)
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset (priv, 0x00, sizeof (struct pl2303_private));
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&priv->lock);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->buf == NULL) {
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_waitqueue_head(&priv->delta_msr_wait);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->type = type;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], priv);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup:
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (--i; i>=0; --i) {
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl2303_buf_free(priv->buf);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(priv);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_set_serial_port_data(serial->port[i], NULL);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_control_lines (struct usb_device *dev, u8 value)
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0),
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  value, 0, NULL, 0, 100);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_write (struct usb_serial_port *port,  const unsigned char *buf, int count)
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!count)
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return count;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = pl2303_buf_put(priv->buf, buf, count);
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pl2303_send(port);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_send(struct usb_serial_port *port)
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count, result;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->write_urb_in_use) {
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->bulk_out_size);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0) {
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 1;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->transfer_buffer_length = count;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->write_urb->dev = port->serial->dev;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO: reschedule pl2303_send
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	schedule_work(&port->work);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_write_room(struct usb_serial_port *port)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int room = 0;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	room = pl2303_buf_space_avail(priv->buf);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - returns %d", __FUNCTION__, room);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return room;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_chars_in_buffer(struct usb_serial_port *port)
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars = 0;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chars = pl2303_buf_data_avail(priv->buf);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - returns %d", __FUNCTION__, chars);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return chars;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cflag;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s -  port %d", __FUNCTION__, port->number);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((!port->tty) || (!port->tty->termios)) {
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - no tty structures", __FUNCTION__);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!priv->termios_initialized) {
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*(port->tty->termios) = tty_std_termios;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->termios_initialized = 1;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cflag = port->tty->termios->c_cflag;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check that they really want us to change something */
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_termios) {
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((cflag == old_termios->c_cflag) &&
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    dbg("%s - nothing to change...", __FUNCTION__);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    return;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf = kmalloc (7, GFP_KERNEL);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (buf, 0x00, 0x07);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     0, 0, buf, 7, 100);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg ("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSIZE) {
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (cflag & CSIZE) {
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS5:	buf[6] = 5;	break;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS6:	buf[6] = 6;	break;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS7:	buf[6] = 7;	break;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case CS8:	buf[6] = 8;	break;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baud = 0;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cflag & CBAUD) {
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B0:	baud = 0;	break;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B75:	baud = 75;	break;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B150:	baud = 150;	break;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B300:	baud = 300;	break;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B600:	baud = 600;	break;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B1200:	baud = 1200;	break;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B1800:	baud = 1800;	break;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B2400:	baud = 2400;	break;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B4800:	baud = 4800;	break;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B9600:	baud = 9600;	break;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B19200:	baud = 19200;	break;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B38400:	baud = 38400;	break;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B57600:	baud = 57600;	break;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B115200:	baud = 115200;	break;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B230400:	baud = 230400;	break;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case B460800:	baud = 460800;	break;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(&port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n");
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - baud = %d", __FUNCTION__, baud);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (baud) {
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[0] = baud & 0xff;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[1] = (baud >> 8) & 0xff;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[2] = (baud >> 16) & 0xff;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[3] = (baud >> 24) & 0xff;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=0 is 1 stop bits */
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=1 is 1.5 stop bits */
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For reference buf[4]=2 is 2 stop bits */
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CSTOPB) {
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 2;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - stop bits = 2", __FUNCTION__);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[4] = 0;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - stop bits = 1", __FUNCTION__);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & PARENB) {
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=0 is none parity */
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=1 is odd parity */
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=2 is even parity */
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=3 is mark parity */
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For reference buf[5]=4 is space parity */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cflag & PARODD) {
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf[5] = 1;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s - parity = odd", __FUNCTION__);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf[5] = 2;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s - parity = even", __FUNCTION__);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[5] = 0;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - parity = none", __FUNCTION__);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     0, 0, buf, 7, 100);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg ("0x21:0x20:0:0  %d", i);
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* change control lines if we are switching to or from B0 */
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cflag & CBAUD) == B0)
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (control != priv->line_control) {
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		control = priv->line_control;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_control_lines(serial->dev, control);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     0, 0, buf, 7, 100);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg ("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & CRTSCTS) {
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__u16 index;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == HX)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			index = 0x61;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			index = 0x41;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = usb_control_msg(serial->dev,
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    usb_sndctrlpipe(serial->dev, 0),
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    VENDOR_WRITE_REQUEST,
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    VENDOR_WRITE_REQUEST_TYPE,
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    0x0, index, NULL, 0, 100);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg ("0x40:0x1:0x0:0x%x  %d", index, i);
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (buf);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_open (struct usb_serial_port *port, struct file *filp)
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct termios tmp_termios;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s -  port %d", __FUNCTION__, port->number);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_clear_halt(serial->dev, port->write_urb->pipe);
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_clear_halt(serial->dev, port->read_urb->pipe);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf = kmalloc(10, GFP_KERNEL);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf==NULL)
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FISH(a,b,c,d)								\
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       b, a, c, d, buf, 1, 100);			\
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,result,buf[0]);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SOUP(a,b,c,d)								\
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),	\
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       b, a, c, d, NULL, 0, 100);			\
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->type == HX) {
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* HX chip */
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset upstream data pipes */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buf);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup termios */
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->tty) {
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl2303_set_termios (port, &tmp_termios);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	//FIXME: need to assert RTS and DTR if CRTSCTS off
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - submitting read urb", __FUNCTION__);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->read_urb->dev = serial->dev;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_submit_urb (port->read_urb, GFP_KERNEL);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl2303_close (port, NULL);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - submitting interrupt urb", __FUNCTION__);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->interrupt_in_urb->dev = serial->dev;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pl2303_close (port, NULL);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPROTO;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_close (struct usb_serial_port *port, struct file *filp)
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int c_cflag;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bps;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long timeout;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_t wait;						\
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wait for data to drain from the buffer */
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = PL2303_CLOSING_WAIT;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_entry(&wait, current);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_wait_queue(&port->tty->write_wait, &wait);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (;;) {
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_current_state(TASK_INTERRUPTIBLE);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pl2303_buf_data_avail(priv->buf) == 0
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		|| timeout == 0 || signal_pending(current)
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		|| !usb_get_intfdata(port->serial->interface))	/* disconnect */
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timeout = schedule_timeout(timeout);
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(&priv->lock, flags);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_current_state(TASK_RUNNING);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	remove_wait_queue(&port->tty->write_wait, &wait);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear out any remaining data in the buffer */
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pl2303_buf_clear(priv->buf);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wait for characters to drain from the device */
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* (this is long enough for the entire 256 byte */
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* pl2303 hardware buffer to drain with no flow */
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* control for data rates of 1200 bps or more, */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* for lower rates we should really know how much */
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* data is in the buffer to compute a delay */
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* that is not unnecessarily long) */
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bps = tty_get_baud_rate(port->tty);
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bps > 1200)
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timeout = max((HZ*2560)/bps,HZ/10);
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timeout = 2*HZ;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_current_state(TASK_INTERRUPTIBLE);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	schedule_timeout(timeout);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* shutdown our urbs */
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - shutting down urbs", __FUNCTION__);
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_kill_urb(port->write_urb);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_kill_urb(port->read_urb);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_kill_urb(port->interrupt_in_urb);
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->tty) {
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c_cflag = port->tty->termios->c_cflag;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (c_cflag & HUPCL) {
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* drop DTR and RTS */
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock_irqsave(&priv->lock, flags);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->line_control = 0;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore (&priv->lock, flags);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_control_lines (port->serial->dev, 0);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    unsigned int set, unsigned int clear)
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 control;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6806fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
6816fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
6826fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&priv->lock, flags);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&priv->lock, flags);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return set_control_lines (port->serial->dev, control);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mcr;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d)", __FUNCTION__, port->number);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7086fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner	if (!usb_get_intfdata(port->serial->interface))
7096fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner		return -ENODEV;
7106fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&priv->lock, flags);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr = priv->line_control;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&priv->lock, flags);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_RING)	? TIOCM_RI  : 0)
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - result = %x", __FUNCTION__, result);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int prevstatus;
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int changed;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&priv->lock, flags);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prevstatus = priv->line_status;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&priv->lock, flags);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		interruptible_sleep_on(&priv->delta_msr_wait);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* see if a signal did it */
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ERESTARTSYS;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave (&priv->lock, flags);
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = priv->line_status;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&priv->lock, flags);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		changed=prevstatus^status;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prevstatus = status;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTREACHED */
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case TIOCMIWAIT:
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return wait_modem_info(port, arg);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 state;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == 0)
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_OFF;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = BREAK_ON;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  0, NULL, 0, 100);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result)
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - error sending break = %d", __FUNCTION__, result);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_shutdown (struct usb_serial *serial)
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s", __FUNCTION__);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < serial->num_ports; ++i) {
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = usb_get_serial_port_data(serial->port[i]);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv) {
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pl2303_buf_free(priv->buf);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(priv);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			usb_set_serial_port_data(serial->port[i], NULL);
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
82097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port,
82197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned char *data,
82297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner				      unsigned int actual_length)
82397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{
82497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
82597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	struct pl2303_private *priv = usb_get_serial_port_data(port);
82697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned long flags;
82797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 status_idx = UART_STATE;
82897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	u8 length = UART_STATE;
82997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
83097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if ((le16_to_cpu(port->serial->dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
83197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	    (le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X65)) {
83297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner		length = 1;
83397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner		status_idx = 0;
83497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	}
83597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
83697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	if (actual_length < length)
83797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner		goto exit;
83897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
83997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner        /* Save off the uart status for others to look at */
84097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_lock_irqsave(&priv->lock, flags);
84197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	priv->line_status = data[status_idx];
84297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	spin_unlock_irqrestore(&priv->lock, flags);
84397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner
84497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerexit:
84597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	return;
84697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner}
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
85297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	unsigned int actual_length = urb->actual_length;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status;
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s (%d)", __FUNCTION__, port->number);
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (urb->status) {
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
87397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner	pl2303_update_line_status(port, data, actual_length);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = usb_submit_urb (urb, GFP_ATOMIC);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status)
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			__FUNCTION__, status);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tty;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 status;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tty_flag;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (urb->status) {
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!port->open_count) {
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s - port is closed, exiting.", __FUNCTION__);
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status == -EPROTO) {
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* PL2303 mysteriously fails with -EPROTO reschedule the read */
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->status = 0;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->dev = port->serial->dev;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = usb_submit_urb(urb, GFP_ATOMIC);
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (result)
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get tty_flag from status */
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_flag = TTY_NORMAL;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->line_status;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up_interruptible (&priv->delta_msr_wait);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* break takes precedence over parity, */
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* which takes precedence over framing errors */
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_BREAK_ERROR )
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_BREAK;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (status & UART_PARITY_ERROR)
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_PARITY;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (status & UART_FRAME_ERROR)
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_FRAME;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty = port->tty;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tty && urb->actual_length) {
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* overrun is special, not associated with a char */
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & UART_OVERRUN_ERROR)
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < urb->actual_length; ++i) {
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tty_flip_buffer_push(tty);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tty_insert_flip_char (tty, data[i], tty_flag);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flip_buffer_push (tty);
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Schedule the next read _if_ we are still open */
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port->open_count) {
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->dev = port->serial->dev;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = usb_submit_urb(urb, GFP_ATOMIC);
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_private *priv = usb_get_serial_port_data(port);
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s - port %d", __FUNCTION__, port->number);
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (urb->status) {
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* success */
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this urb is terminated, clean up */
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* error in the urb, so we have to resubmit it */
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - Overflow in write", __FUNCTION__);
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->transfer_buffer_length = 1;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->write_urb->dev = port->serial->dev;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (result)
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result);
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 0;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* send any buffered data */
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pl2303_send(port);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pl2303_buf_alloc
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a circular buffer and all associated memory.
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pl2303_buf *pb;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (size == 0)
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pb == NULL)
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pb->buf_buf = kmalloc(size, GFP_KERNEL);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pb->buf_buf == NULL) {
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(pb);
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pb->buf_size = size;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pb->buf_get = pb->buf_put = pb->buf_buf;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pb;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pl2303_buf_free
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free the buffer and all associated memory.
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_buf_free(struct pl2303_buf *pb)
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pb != NULL) {
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pb->buf_buf != NULL)
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(pb->buf_buf);
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(pb);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pl2303_buf_clear
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear out all data in the circular buffer.
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_buf_clear(struct pl2303_buf *pb)
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pb != NULL)
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pb->buf_get = pb->buf_put;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* equivalent to a get of all data available */
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pl2303_buf_data_avail
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return the number of bytes of data available in the circular
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer.
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pb != NULL)
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pl2303_buf_space_avail
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return the number of bytes of space available in the circular
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer.
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pb != NULL)
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pl2303_buf_put
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy data data from a user buffer and put it into the circular buffer.
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Restrict to the amount of space available.
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return the number of bytes copied.
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int count)
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int len;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pb == NULL)
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len  = pl2303_buf_space_avail(pb);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count > len)
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = len;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0)
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = pb->buf_buf + pb->buf_size - pb->buf_put;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count > len) {
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(pb->buf_put, buf, len);
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(pb->buf_buf, buf+len, count - len);
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pb->buf_put = pb->buf_buf + count - len;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(pb->buf_put, buf, count);
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count < len)
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pb->buf_put += count;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else /* count == len */
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pb->buf_put = pb->buf_buf;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pl2303_buf_get
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get data from the circular buffer and copy to the given buffer.
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Restrict to the amount of data available.
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return the number of bytes copied.
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int count)
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int len;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pb == NULL)
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = pl2303_buf_data_avail(pb);
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count > len)
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = len;
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count == 0)
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = pb->buf_buf + pb->buf_size - pb->buf_get;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count > len) {
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(buf, pb->buf_get, len);
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(buf+len, pb->buf_buf, count - len);
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pb->buf_get = pb->buf_buf + count - len;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(buf, pb->buf_get, count);
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count < len)
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pb->buf_get += count;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else /* count == len */
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pb->buf_get = pb->buf_buf;
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pl2303_init (void)
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_serial_register(&pl2303_device);
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_serial_register;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_register(&pl2303_driver);
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_usb_register;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info(DRIVER_DESC " " DRIVER_VERSION);
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register:
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_deregister(&pl2303_device);
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register:
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit pl2303_exit (void)
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_deregister (&pl2303_driver);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_serial_deregister (&pl2303_device);
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pl2303_init);
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl2303_exit);
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(DRIVER_VERSION);
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not");
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1222