11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB Cypress M8 driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	Copyright (C) 2004
5813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox * 	    Lonnie Mendez (dignome@gmail.com)
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Copyright (C) 2003,2004
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    Neil Whelchel (koyama@firstlight.net)
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 *
14813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox * See Documentation/usb/usb-serial.txt for more information on using this
15813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox * driver
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See http://geocities.com/i0xox0i for information on this driver and the
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * earthmate usb device.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox/* Thanks to Neil Whelchel for writing the first cypress m8 implementation
22813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox   for linux. */
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Thanks to cypress for providing references for the hid reports. */
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Thanks to Jiang Zhang for providing links and for general help. */
25813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox/* Code originates and was built up from ftdi_sio, belkin, pl2303 and others.*/
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
39a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
41117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold#include <linux/kfifo.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
43813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox#include <linux/uaccess.h>
440f2c2d7bbb51338fdcda9670795a6c6e348622d9Johan Hovold#include <asm/unaligned.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cypress_m8.h"
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4990ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool debug;
5090ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool stats;
513cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendezstatic int interval;
5290ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool unstable_bauds;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
57117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold#define DRIVER_VERSION "v1.10"
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>"
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Cypress USB to Serial Driver"
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* write buffer size defines */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CYPRESS_BUF_SIZE	1024
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
647d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table_earthmate[] = {
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
6625b6f08e3fa0d84e26a373a205cfdad208b54af7Lonnie Mendez	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }						/* Terminating entry */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
707d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table_cyphidcomrs232[] = {
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
726f6f06ee6ada13b0fb39c800f8567ff81d4e807dDmitry Shapin	{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }						/* Terminating entry */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
767d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table_nokiaca42v2[] = {
77a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
78a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	{ }						/* Terminating entry */
79a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez};
80a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez
817d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table_combined[] = {
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
8325b6f08e3fa0d84e26a373a205cfdad208b54af7Lonnie Mendez	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
856f6f06ee6ada13b0fb39c800f8567ff81d4e807dDmitry Shapin	{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
86a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }						/* Terminating entry */
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
90813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan CoxMODULE_DEVICE_TABLE(usb, id_table_combined);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver cypress_driver = {
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"cypress",
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =	usb_serial_probe,
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =	usb_serial_disconnect,
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =	id_table_combined,
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
993416eaa1f8f8d516b77de514e14cf8da256d28fbMike Iselyenum packet_format {
1003416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	packet_format_1,  /* b0:status, b1:payload count */
1013416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	packet_format_2   /* b0[7:3]:status, b0[2:0]:payload count */
1023416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely};
1033416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cypress_private {
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;		   /* private lock */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chiptype;			   /* identifier of device, for quirks/etc */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bytes_in;			   /* used for statistics */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bytes_out;			   /* used for statistics */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cmd_count;			   /* used for statistics */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cmd_ctrl;			   /* always set this to 1 before issuing a command */
111117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	struct kfifo write_fifo;	   /* write fifo */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int write_urb_in_use;		   /* write urb in use indicator */
1130257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely	int write_urb_interval;            /* interval to use for write urb */
1140257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely	int read_urb_interval;             /* interval to use for read urb */
11578aef519ed07797f94cff1d0d66dd01704474916Mike Isely	int comm_is_ok;                    /* true if communication is (still) ok */
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int termios_initialized;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 line_control;	   	   /* holds dtr / rts value */
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 current_status;	   	   /* received from last read - info on dsr,cts,cd,ri,etc */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 current_config;	   	   /* stores the current configuration byte */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 rx_flags;			   /* throttling - used from whiteheat/ftdi_sio */
1213416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	enum packet_format pkt_fmt;	   /* format to use for packet send / receive */
1223d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely	int get_cfg_unsafe;		   /* If true, the CYPRESS_GET_CONFIG is unsafe */
123813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	int baud_rate;			   /* stores current baud rate in
124813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					      integer form */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int isthrottled;		   /* if throttled, discard reads */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t delta_msr_wait;  /* used for TIOCMIWAIT */
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char prev_status, diff_status;	   /* used for TIOCMIWAIT */
1283ad2f3fbb961429d2aa627465ae4829758bc7e07Daniel Mack	/* we pass a pointer to this as the argument sent to
129813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	   cypress_set_termios old_termios */
130606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox	struct ktermios tmp_termios; 	   /* stores the old termios settings */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* function prototypes for the Cypress USB to serial device */
134813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int  cypress_earthmate_startup(struct usb_serial *serial);
135813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int  cypress_hidcom_startup(struct usb_serial *serial);
136813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int  cypress_ca42v2_startup(struct usb_serial *serial);
137f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void cypress_release(struct usb_serial *serial);
138a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int  cypress_open(struct tty_struct *tty, struct usb_serial_port *port);
139335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void cypress_close(struct usb_serial_port *port);
140335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void cypress_dtr_rts(struct usb_serial_port *port, int on);
141813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int  cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
142813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			const unsigned char *buf, int count);
143813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_send(struct usb_serial_port *port);
144813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int  cypress_write_room(struct tty_struct *tty);
14500a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int  cypress_ioctl(struct tty_struct *tty,
146813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			unsigned int cmd, unsigned long arg);
147813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_set_termios(struct tty_struct *tty,
148813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			struct usb_serial_port *port, struct ktermios *old);
14960b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int  cypress_tiocmget(struct tty_struct *tty);
15020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int  cypress_tiocmset(struct tty_struct *tty,
151813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			unsigned int set, unsigned int clear);
152813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int  cypress_chars_in_buffer(struct tty_struct *tty);
153813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_throttle(struct tty_struct *tty);
154813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_unthrottle(struct tty_struct *tty);
155813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_set_dead(struct usb_serial_port *port);
156813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_read_int_callback(struct urb *urb);
157813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_write_int_callback(struct urb *urb);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver cypress_earthmate_device = {
16018fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman	.driver = {
16118fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman		.owner =		THIS_MODULE,
162269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman		.name =			"earthmate",
16318fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman	},
164269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman	.description =			"DeLorme Earthmate USB",
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =			id_table_earthmate,
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.num_ports =			1,
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attach =			cypress_earthmate_startup,
168f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =			cypress_release,
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open =				cypress_open,
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.close =			cypress_close,
171335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.dtr_rts =			cypress_dtr_rts,
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write =			cypress_write,
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_room =			cypress_write_room,
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl =			cypress_ioctl,
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios =			cypress_set_termios,
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmget =			cypress_tiocmget,
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmset =			cypress_tiocmset,
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.chars_in_buffer =		cypress_chars_in_buffer,
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.throttle =		 	cypress_throttle,
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unthrottle =			cypress_unthrottle,
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_int_callback =		cypress_read_int_callback,
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_int_callback =		cypress_write_int_callback,
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver cypress_hidcom_device = {
18618fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman	.driver = {
18718fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman		.owner =		THIS_MODULE,
188269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman		.name =			"cyphidcom",
18918fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman	},
190269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman	.description =			"HID->COM RS232 Adapter",
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =			id_table_cyphidcomrs232,
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.num_ports =			1,
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attach =			cypress_hidcom_startup,
194f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =			cypress_release,
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open =				cypress_open,
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.close =			cypress_close,
197335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.dtr_rts =			cypress_dtr_rts,
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write =			cypress_write,
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_room =			cypress_write_room,
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl =			cypress_ioctl,
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios =			cypress_set_termios,
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmget =			cypress_tiocmget,
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmset =			cypress_tiocmset,
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.chars_in_buffer =		cypress_chars_in_buffer,
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.throttle =			cypress_throttle,
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unthrottle =			cypress_unthrottle,
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read_int_callback =		cypress_read_int_callback,
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_int_callback =		cypress_write_int_callback,
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendezstatic struct usb_serial_driver cypress_ca42v2_device = {
212a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.driver = {
213a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez		.owner =		THIS_MODULE,
214813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		.name =			"nokiaca42v2",
215a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	},
216a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.description =			"Nokia CA-42 V2 Adapter",
217a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.id_table =			id_table_nokiaca42v2,
218a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.num_ports =			1,
219a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.attach =			cypress_ca42v2_startup,
220f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release =			cypress_release,
221a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.open =				cypress_open,
222a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.close =			cypress_close,
223335f8514f200e63d689113d29cb7253a5c282967Alan Cox	.dtr_rts =			cypress_dtr_rts,
224a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.write =			cypress_write,
225a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.write_room =			cypress_write_room,
226a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.ioctl =			cypress_ioctl,
227a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.set_termios =			cypress_set_termios,
228a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.tiocmget =			cypress_tiocmget,
229a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.tiocmset =			cypress_tiocmset,
230a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.chars_in_buffer =		cypress_chars_in_buffer,
231a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.throttle =			cypress_throttle,
232a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.unthrottle =			cypress_unthrottle,
233a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.read_int_callback =		cypress_read_int_callback,
234a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	.write_int_callback =		cypress_write_int_callback,
235a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez};
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23708a4f6bc2e7046ce50849d7589b7d0763926d808Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = {
23808a4f6bc2e7046ce50849d7589b7d0763926d808Alan Stern	&cypress_earthmate_device, &cypress_hidcom_device,
23908a4f6bc2e7046ce50849d7589b7d0763926d808Alan Stern	&cypress_ca42v2_device, NULL
24008a4f6bc2e7046ce50849d7589b7d0763926d808Alan Stern};
24108a4f6bc2e7046ce50849d7589b7d0763926d808Alan Stern
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cypress serial helper functions
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2478873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Coxstatic int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
24892983c2121fb46f234add1c36b5e596779899d56Mike Isely{
24992983c2121fb46f234add1c36b5e596779899d56Mike Isely	struct cypress_private *priv;
25092983c2121fb46f234add1c36b5e596779899d56Mike Isely	priv = usb_get_serial_port_data(port);
25192983c2121fb46f234add1c36b5e596779899d56Mike Isely
252c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike Frysinger	if (unstable_bauds)
253c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike Frysinger		return new_rate;
254c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike Frysinger
25592983c2121fb46f234add1c36b5e596779899d56Mike Isely	/*
25692983c2121fb46f234add1c36b5e596779899d56Mike Isely	 * The general purpose firmware for the Cypress M8 allows for
25792983c2121fb46f234add1c36b5e596779899d56Mike Isely	 * a maximum speed of 57600bps (I have no idea whether DeLorme
25892983c2121fb46f234add1c36b5e596779899d56Mike Isely	 * chose to use the general purpose firmware or not), if you
25992983c2121fb46f234add1c36b5e596779899d56Mike Isely	 * need to modify this speed setting for your own project
26092983c2121fb46f234add1c36b5e596779899d56Mike Isely	 * please add your own chiptype and modify the code likewise.
26192983c2121fb46f234add1c36b5e596779899d56Mike Isely	 * The Cypress HID->COM device will work successfully up to
26292983c2121fb46f234add1c36b5e596779899d56Mike Isely	 * 115200bps (but the actual throughput is around 3kBps).
26392983c2121fb46f234add1c36b5e596779899d56Mike Isely	 */
26492983c2121fb46f234add1c36b5e596779899d56Mike Isely	if (port->serial->dev->speed == USB_SPEED_LOW) {
26592983c2121fb46f234add1c36b5e596779899d56Mike Isely		/*
26692983c2121fb46f234add1c36b5e596779899d56Mike Isely		 * Mike Isely <isely@pobox.com> 2-Feb-2008: The
26792983c2121fb46f234add1c36b5e596779899d56Mike Isely		 * Cypress app note that describes this mechanism
26892983c2121fb46f234add1c36b5e596779899d56Mike Isely		 * states the the low-speed part can't handle more
26992983c2121fb46f234add1c36b5e596779899d56Mike Isely		 * than 800 bytes/sec, in which case 4800 baud is the
27092983c2121fb46f234add1c36b5e596779899d56Mike Isely		 * safest speed for a part like that.
27192983c2121fb46f234add1c36b5e596779899d56Mike Isely		 */
27292983c2121fb46f234add1c36b5e596779899d56Mike Isely		if (new_rate > 4800) {
27392983c2121fb46f234add1c36b5e596779899d56Mike Isely			dbg("%s - failed setting baud rate, device incapable "
27492983c2121fb46f234add1c36b5e596779899d56Mike Isely			    "speed %d", __func__, new_rate);
27592983c2121fb46f234add1c36b5e596779899d56Mike Isely			return -1;
27692983c2121fb46f234add1c36b5e596779899d56Mike Isely		}
27792983c2121fb46f234add1c36b5e596779899d56Mike Isely	}
27892983c2121fb46f234add1c36b5e596779899d56Mike Isely	switch (priv->chiptype) {
27992983c2121fb46f234add1c36b5e596779899d56Mike Isely	case CT_EARTHMATE:
28092983c2121fb46f234add1c36b5e596779899d56Mike Isely		if (new_rate <= 600) {
28192983c2121fb46f234add1c36b5e596779899d56Mike Isely			/* 300 and 600 baud rates are supported under
28292983c2121fb46f234add1c36b5e596779899d56Mike Isely			 * the generic firmware, but are not used with
28392983c2121fb46f234add1c36b5e596779899d56Mike Isely			 * NMEA and SiRF protocols */
28492983c2121fb46f234add1c36b5e596779899d56Mike Isely			dbg("%s - failed setting baud rate, unsupported speed "
28592983c2121fb46f234add1c36b5e596779899d56Mike Isely			    "of %d on Earthmate GPS", __func__, new_rate);
28692983c2121fb46f234add1c36b5e596779899d56Mike Isely			return -1;
28792983c2121fb46f234add1c36b5e596779899d56Mike Isely		}
28892983c2121fb46f234add1c36b5e596779899d56Mike Isely		break;
28992983c2121fb46f234add1c36b5e596779899d56Mike Isely	default:
29092983c2121fb46f234add1c36b5e596779899d56Mike Isely		break;
29192983c2121fb46f234add1c36b5e596779899d56Mike Isely	}
29292983c2121fb46f234add1c36b5e596779899d56Mike Isely	return new_rate;
29392983c2121fb46f234add1c36b5e596779899d56Mike Isely}
29492983c2121fb46f234add1c36b5e596779899d56Mike Isely
29592983c2121fb46f234add1c36b5e596779899d56Mike Isely
296093cf723b2b06d774929ea07982f6a466ff22314Steven Cole/* This function can either set or retrieve the current serial line settings */
297813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_serial_control(struct tty_struct *tty,
29895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port, speed_t baud_rate, int data_bits,
29995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	int stop_bits, int parity_enable, int parity_type, int reset,
30095da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	int cypress_request_type)
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3023cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez	int new_baudrate = 0, retval = 0, tries = 0;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv;
3040954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold	u8 *feature_buffer;
3050954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold	const unsigned int feature_len = 5;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
308441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s", __func__);
309813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv = usb_get_serial_port_data(port);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31278aef519ed07797f94cff1d0d66dd01704474916Mike Isely	if (!priv->comm_is_ok)
31378aef519ed07797f94cff1d0d66dd01704474916Mike Isely		return -ENODEV;
31478aef519ed07797f94cff1d0d66dd01704474916Mike Isely
3150954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold	feature_buffer = kcalloc(feature_len, sizeof(u8), GFP_KERNEL);
3160954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold	if (!feature_buffer)
3170954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold		return -ENOMEM;
3180954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold
319813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	switch (cypress_request_type) {
320813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	case CYPRESS_SET_CONFIG:
321813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		/* 0 means 'Hang up' so doesn't change the true bit rate */
3222805eb13c3b5be7bd6ec7380502bc054b570afd5Mike Frysinger		new_baudrate = priv->baud_rate;
3232805eb13c3b5be7bd6ec7380502bc054b570afd5Mike Frysinger		if (baud_rate && baud_rate != priv->baud_rate) {
324813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			dbg("%s - baud rate is changing", __func__);
325813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			retval = analyze_baud_rate(port, baud_rate);
3262805eb13c3b5be7bd6ec7380502bc054b570afd5Mike Frysinger			if (retval >= 0) {
327813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				new_baudrate = retval;
328813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				dbg("%s - New baud rate set to %d",
329813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				    __func__, new_baudrate);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
331813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		}
332813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dbg("%s - baud rate is being sent as %d",
333813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					__func__, new_baudrate);
334813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
335813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		/* fill the feature_buffer with new configuration */
3360f2c2d7bbb51338fdcda9670795a6c6e348622d9Johan Hovold		put_unaligned_le32(new_baudrate, feature_buffer);
337813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		feature_buffer[4] |= data_bits;   /* assign data bits in 2 bit space ( max 3 ) */
338813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		/* 1 bit gap */
339813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		feature_buffer[4] |= (stop_bits << 3);   /* assign stop bits in 1 bit space */
340813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		feature_buffer[4] |= (parity_enable << 4);   /* assign parity flag in 1 bit space */
341813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		feature_buffer[4] |= (parity_type << 5);   /* assign parity type in 1 bit space */
342813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		/* 1 bit gap */
343813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		feature_buffer[4] |= (reset << 7);   /* assign reset at end of byte, 1 bit space */
344813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
345813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dbg("%s - device is being sent this feature report:",
346813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox								__func__);
347813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__,
348813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			feature_buffer[0], feature_buffer[1],
349813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			feature_buffer[2], feature_buffer[3],
350813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			feature_buffer[4]);
351813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
352813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		do {
353813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			retval = usb_control_msg(port->serial->dev,
354813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					usb_sndctrlpipe(port->serial->dev, 0),
355813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					HID_REQ_SET_REPORT,
356813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
357813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					0x0300, 0, feature_buffer,
3580954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold					feature_len, 500);
359813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
360813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			if (tries++ >= 3)
361813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				break;
362813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
3630954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold		} while (retval != feature_len &&
364813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			 retval != -ENODEV);
365813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
3660954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold		if (retval != feature_len) {
367194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			dev_err(&port->dev, "%s - failed sending serial "
368194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman				"line settings - %d\n", __func__, retval);
369813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			cypress_set_dead(port);
370813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		} else {
371813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			spin_lock_irqsave(&priv->lock, flags);
372813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			priv->baud_rate = new_baudrate;
373813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			priv->current_config = feature_buffer[4];
374813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			spin_unlock_irqrestore(&priv->lock, flags);
375813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			/* If we asked for a speed change encode it */
376813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			if (baud_rate)
377813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				tty_encode_baud_rate(tty,
378813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					new_baudrate, new_baudrate);
379813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		}
380813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	break;
381813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	case CYPRESS_GET_CONFIG:
382813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		if (priv->get_cfg_unsafe) {
383813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			/* Not implemented for this device,
384813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			   and if we try to do it we're likely
385813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			   to crash the hardware. */
3860954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold			retval = -ENOTTY;
3870954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold			goto out;
388813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		}
389813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dbg("%s - retreiving serial line settings", __func__);
390813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		do {
391813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			retval = usb_control_msg(port->serial->dev,
392813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					usb_rcvctrlpipe(port->serial->dev, 0),
393813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					HID_REQ_GET_REPORT,
394813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
395813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					0x0300, 0, feature_buffer,
3960954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold					feature_len, 500);
397813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
398813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			if (tries++ >= 3)
399813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				break;
4000954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold		} while (retval != feature_len
401813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox						&& retval != -ENODEV);
402813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
4030954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold		if (retval != feature_len) {
404194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			dev_err(&port->dev, "%s - failed to retrieve serial "
405194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman				"line settings - %d\n", __func__, retval);
406813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			cypress_set_dead(port);
4070954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold			goto out;
408813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		} else {
409813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			spin_lock_irqsave(&priv->lock, flags);
410813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			/* store the config in one byte, and later
411813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			   use bit masks to check values */
412813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			priv->current_config = feature_buffer[4];
4130f2c2d7bbb51338fdcda9670795a6c6e348622d9Johan Hovold			priv->baud_rate = get_unaligned_le32(feature_buffer);
414813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			spin_unlock_irqrestore(&priv->lock, flags);
415813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4173cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez	spin_lock_irqsave(&priv->lock, flags);
4183cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez	++priv->cmd_count;
4193cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez	spin_unlock_irqrestore(&priv->lock, flags);
4200954644bf5a5a2281746516ce0f5df988d504c31Johan Hovoldout:
4210954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold	kfree(feature_buffer);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_serial_control */
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42678aef519ed07797f94cff1d0d66dd01704474916Mike Iselystatic void cypress_set_dead(struct usb_serial_port *port)
42778aef519ed07797f94cff1d0d66dd01704474916Mike Isely{
42878aef519ed07797f94cff1d0d66dd01704474916Mike Isely	struct cypress_private *priv = usb_get_serial_port_data(port);
42978aef519ed07797f94cff1d0d66dd01704474916Mike Isely	unsigned long flags;
43078aef519ed07797f94cff1d0d66dd01704474916Mike Isely
43178aef519ed07797f94cff1d0d66dd01704474916Mike Isely	spin_lock_irqsave(&priv->lock, flags);
43278aef519ed07797f94cff1d0d66dd01704474916Mike Isely	if (!priv->comm_is_ok) {
43378aef519ed07797f94cff1d0d66dd01704474916Mike Isely		spin_unlock_irqrestore(&priv->lock, flags);
43478aef519ed07797f94cff1d0d66dd01704474916Mike Isely		return;
43578aef519ed07797f94cff1d0d66dd01704474916Mike Isely	}
43678aef519ed07797f94cff1d0d66dd01704474916Mike Isely	priv->comm_is_ok = 0;
43778aef519ed07797f94cff1d0d66dd01704474916Mike Isely	spin_unlock_irqrestore(&priv->lock, flags);
43878aef519ed07797f94cff1d0d66dd01704474916Mike Isely
439194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman	dev_err(&port->dev, "cypress_m8 suspending failing port %d - "
440194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman		"interval might be too short\n", port->number);
44178aef519ed07797f94cff1d0d66dd01704474916Mike Isely}
44278aef519ed07797f94cff1d0d66dd01704474916Mike Isely
44378aef519ed07797f94cff1d0d66dd01704474916Mike Isely
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cypress serial driver functions
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
449813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int generic_startup(struct usb_serial *serial)
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv;
4520257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely	struct usb_serial_port *port = serial->port[0];
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
454441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
456813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!priv)
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46078aef519ed07797f94cff1d0d66dd01704474916Mike Isely	priv->comm_is_ok = !0;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&priv->lock);
462117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	if (kfifo_alloc(&priv->write_fifo, CYPRESS_BUF_SIZE, GFP_KERNEL)) {
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(priv);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_head(&priv->delta_msr_wait);
467813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
468813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	usb_reset_configuration(serial->dev);
469813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->cmd_ctrl = 0;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->line_control = 0;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->termios_initialized = 0;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rx_flags = 0;
4743416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	/* Default packet format setting is determined by packet size.
4753416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	   Anything with a size larger then 9 must have a separate
4763416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	   count field since the 3 bit count field is otherwise too
4773416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	   small.  Otherwise we can use the slightly more compact
4783416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	   format.  This is in accordance with the cypress_m8 serial
4793416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	   converter app note. */
480813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	if (port->interrupt_out_size > 9)
4813416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		priv->pkt_fmt = packet_format_1;
482813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	else
4833416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		priv->pkt_fmt = packet_format_2;
484813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
4850257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely	if (interval > 0) {
4860257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely		priv->write_urb_interval = interval;
4870257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely		priv->read_urb_interval = interval;
4880257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely		dbg("%s - port %d read & write intervals forced to %d",
489813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		    __func__, port->number, interval);
4900257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely	} else {
4910257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely		priv->write_urb_interval = port->interrupt_out_urb->interval;
4920257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely		priv->read_urb_interval = port->interrupt_in_urb->interval;
4930257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely		dbg("%s - port %d intervals: read=%d write=%d",
494813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		    __func__, port->number,
495813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		    priv->read_urb_interval, priv->write_urb_interval);
4960257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely	}
4970257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely	usb_set_serial_port_data(port, priv);
498813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
499b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	return 0;
500b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez}
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
503813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_earthmate_startup(struct usb_serial *serial)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv;
5063d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely	struct usb_serial_port *port = serial->port[0];
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
508441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s", __func__);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (generic_startup(serial)) {
511441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - Failed setting up port %d", __func__,
5123d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely				port->number);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5163d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely	priv = usb_get_serial_port_data(port);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->chiptype = CT_EARTHMATE;
5183416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	/* All Earthmate devices use the separated-count packet
5193416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	   format!  Idiotic. */
5203416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	priv->pkt_fmt = packet_format_1;
521813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	if (serial->dev->descriptor.idProduct !=
522813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) {
5233d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely		/* The old original USB Earthmate seemed able to
5243d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely		   handle GET_CONFIG requests; everything they've
5253d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely		   produced since that time crashes if this command is
5263d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely		   attempted :-( */
5273d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely		dbg("%s - Marking this device as unsafe for GET_CONFIG "
5283d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely		    "commands", __func__);
5293d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely		priv->get_cfg_unsafe = !0;
5303d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely	}
531b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez
532b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	return 0;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_earthmate_startup */
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
536813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_hidcom_startup(struct usb_serial *serial)
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
540441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s", __func__);
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (generic_startup(serial)) {
543441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - Failed setting up port %d", __func__,
544b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez				serial->port[0]->number);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv = usb_get_serial_port_data(serial->port[0]);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->chiptype = CT_CYPHIDCOM;
550813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
551b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	return 0;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_hidcom_startup */
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
555813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_ca42v2_startup(struct usb_serial *serial)
556a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez{
557a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	struct cypress_private *priv;
558a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez
559441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s", __func__);
560a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez
561a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	if (generic_startup(serial)) {
562441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - Failed setting up port %d", __func__,
563a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez				serial->port[0]->number);
564a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez		return 1;
565a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	}
566a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez
567a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	priv = usb_get_serial_port_data(serial->port[0]);
568a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	priv->chiptype = CT_CA42V2;
569a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez
570a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez	return 0;
571a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez} /* cypress_ca42v2_startup */
572a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez
573a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez
574f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void cypress_release(struct usb_serial *serial)
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
578813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	dbg("%s - port %d", __func__, serial->port[0]->number);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* all open ports are closed at this point */
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv = usb_get_serial_port_data(serial->port[0]);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv) {
585117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold		kfifo_free(&priv->write_fifo);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(priv);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_serial *serial = port->serial;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result = 0;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
598441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60078aef519ed07797f94cff1d0d66dd01704474916Mike Isely	if (!priv->comm_is_ok)
60178aef519ed07797f94cff1d0d66dd01704474916Mike Isely		return -EIO;
60278aef519ed07797f94cff1d0d66dd01704474916Mike Isely
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear halts before open */
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_clear_halt(serial->dev, 0x81);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_clear_halt(serial->dev, 0x02);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset read/write statistics */
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->bytes_in = 0;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->bytes_out = 0;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->cmd_count = 0;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rx_flags = 0;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
615335f8514f200e63d689113d29cb7253a5c282967Alan Cox	/* Set termios */
616fe1ae7fdd2ee603f2d95f04e09a68f7f79045127Alan Cox	cypress_send(port);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	if (tty)
61995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		cypress_set_termios(tty, port, &priv->tmp_termios);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup the port and start reading from the device */
622813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	if (!port->interrupt_in_urb) {
623194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman		dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n",
624194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			__func__);
625813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		return -1;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
630813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		port->interrupt_in_urb->transfer_buffer,
631813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		port->interrupt_in_urb->transfer_buffer_length,
6320257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely		cypress_read_int_callback, port, priv->read_urb_interval);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
635813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	if (result) {
636813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dev_err(&port->dev,
637813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			"%s - failed submitting read urb, error %d\n",
638813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox							__func__, result);
63978aef519ed07797f94cff1d0d66dd01704474916Mike Isely		cypress_set_dead(port);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
641335f8514f200e63d689113d29cb7253a5c282967Alan Cox	port->port.drain_delay = 256;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_open */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
645335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void cypress_dtr_rts(struct usb_serial_port *port, int on)
646335f8514f200e63d689113d29cb7253a5c282967Alan Cox{
647335f8514f200e63d689113d29cb7253a5c282967Alan Cox	struct cypress_private *priv = usb_get_serial_port_data(port);
648335f8514f200e63d689113d29cb7253a5c282967Alan Cox	/* drop dtr and rts */
649335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_lock_irq(&priv->lock);
650335f8514f200e63d689113d29cb7253a5c282967Alan Cox	if (on == 0)
651335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control = 0;
652335f8514f200e63d689113d29cb7253a5c282967Alan Cox	else
653335f8514f200e63d689113d29cb7253a5c282967Alan Cox		priv->line_control = CONTROL_DTR | CONTROL_RTS;
654335f8514f200e63d689113d29cb7253a5c282967Alan Cox	priv->cmd_ctrl = 1;
655335f8514f200e63d689113d29cb7253a5c282967Alan Cox	spin_unlock_irq(&priv->lock);
656335f8514f200e63d689113d29cb7253a5c282967Alan Cox	cypress_write(NULL, port, NULL, 0);
657335f8514f200e63d689113d29cb7253a5c282967Alan Cox}
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
659335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void cypress_close(struct usb_serial_port *port)
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
662117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	unsigned long flags;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
664441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6669e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum	/* writing is potentially harmful, lock must be taken */
6679e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum	mutex_lock(&port->serial->disc_mutex);
6689e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum	if (port->serial->disconnected) {
6699e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum		mutex_unlock(&port->serial->disc_mutex);
6709e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum		return;
6719e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum	}
672117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	spin_lock_irqsave(&priv->lock, flags);
673117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	kfifo_reset_out(&priv->write_fifo);
674117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	spin_unlock_irqrestore(&priv->lock, flags);
675117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold
676441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - stopping urbs", __func__);
677813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	usb_kill_urb(port->interrupt_in_urb);
678813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	usb_kill_urb(port->interrupt_out_urb);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (stats)
681813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
682813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			priv->bytes_in, priv->bytes_out, priv->cmd_count);
6839e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum	mutex_unlock(&port->serial->disc_mutex);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_close */
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
68795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
68895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox					const unsigned char *buf, int count)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
691813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
692441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d, %d bytes", __func__, port->number, count);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* line control commands, which need to be executed immediately,
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   are not put into the buffer for obvious reasons.
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->cmd_ctrl) {
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = 0;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto finish;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
701813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!count)
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return count;
704813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
705117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	count = kfifo_in_locked(&priv->write_fifo, buf, count, &priv->lock);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfinish:
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cypress_send(port);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_write */
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cypress_send(struct usb_serial_port *port)
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count = 0, result, offset, actual_size;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
719813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
72078aef519ed07797f94cff1d0d66dd01704474916Mike Isely	if (!priv->comm_is_ok)
72178aef519ed07797f94cff1d0d66dd01704474916Mike Isely		return;
72278aef519ed07797f94cff1d0d66dd01704474916Mike Isely
723441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
724813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	dbg("%s - interrupt out size is %d", __func__,
725813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox						port->interrupt_out_size);
726813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->write_urb_in_use) {
729441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - can't write, urb in use", __func__);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear buffer */
736813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	memset(port->interrupt_out_urb->transfer_buffer, 0,
737813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox						port->interrupt_out_size);
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
7403416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	switch (priv->pkt_fmt) {
7413416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	default:
7423416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	case packet_format_1:
7433416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		/* this is for the CY7C64013... */
7443416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		offset = 2;
7453416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		port->interrupt_out_buffer[0] = priv->line_control;
7463416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		break;
7473416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	case packet_format_2:
7483416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		/* this is for the CY7C63743... */
7493416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		offset = 1;
7503416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		port->interrupt_out_buffer[0] = priv->line_control;
7513416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		break;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->line_control & CONTROL_RESET)
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RESET;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->cmd_ctrl) {
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->cmd_count++;
759441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - line control command being issued", __func__);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto send;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
765117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	count = kfifo_out_locked(&priv->write_fifo,
766117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold					&port->interrupt_out_buffer[offset],
767117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold					port->interrupt_out_size - offset,
768117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold					&priv->lock);
769813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	if (count == 0)
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7723416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	switch (priv->pkt_fmt) {
7733416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	default:
7743416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	case packet_format_1:
7753416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		port->interrupt_out_buffer[1] = count;
7763416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		break;
7773416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	case packet_format_2:
7783416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		port->interrupt_out_buffer[0] |= count;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - count is %d", __func__, count);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssend:
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 1;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->cmd_ctrl)
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		actual_size = 1;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7913416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		actual_size = count +
7923416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely			      (priv->pkt_fmt == packet_format_1 ? 2 : 1);
7933416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely
794813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	usb_serial_debug_data(debug, &port->dev, __func__,
795813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		port->interrupt_out_size,
796813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		port->interrupt_out_urb->transfer_buffer);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7989aa8dae7b1fa7af099a403fc3766e068a0ea6d68Mike Isely	usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
7999aa8dae7b1fa7af099a403fc3766e068a0ea6d68Mike Isely		usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
8009aa8dae7b1fa7af099a403fc3766e068a0ea6d68Mike Isely		port->interrupt_out_buffer, port->interrupt_out_size,
8019aa8dae7b1fa7af099a403fc3766e068a0ea6d68Mike Isely		cypress_write_int_callback, port, priv->write_urb_interval);
802813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result) {
80422a416c4e0f2179b57028e084ac0ed2c110333bdJohan Hovold		dev_err_console(port,
805813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				"%s - failed submitting write urb, error %d\n",
806813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox							__func__, result);
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->write_urb_in_use = 0;
80878aef519ed07797f94cff1d0d66dd01704474916Mike Isely		cypress_set_dead(port);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
812813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	if (priv->cmd_ctrl)
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->cmd_ctrl = 0;
814813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
815813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	/* do not count the line control and size bytes */
816813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	priv->bytes_out += count;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
819cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev	usb_serial_port_softint(port);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_send */
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* returns how much space is available in the soft buffer */
82495da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int cypress_write_room(struct tty_struct *tty)
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
82695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int room = 0;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
834117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	room = kfifo_avail(&priv->write_fifo);
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
837441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, room);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return room;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
84260b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int cypress_tiocmget(struct tty_struct *tty)
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
84495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 status, control;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int result = 0;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
849813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
850441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control = priv->line_control;
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = priv->current_status;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = ((control & CONTROL_DTR)        ? TIOCM_DTR : 0)
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| ((control & CONTROL_RTS)       ? TIOCM_RTS : 0)
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| ((status & UART_CTS)        ? TIOCM_CTS : 0)
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| ((status & UART_DSR)        ? TIOCM_DSR : 0)
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| ((status & UART_RI)         ? TIOCM_RI  : 0)
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| ((status & UART_CD)         ? TIOCM_CD  : 0);
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
864441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - result = %x", __func__, result);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
87020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int cypress_tiocmset(struct tty_struct *tty,
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unsigned int set, unsigned int clear)
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
87395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
876813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
877441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_RTS)
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_RTS;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (set & TIOCM_DTR)
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control |= CONTROL_DTR;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_RTS)
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_RTS;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (clear & TIOCM_DTR)
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~CONTROL_DTR;
8888873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox	priv->cmd_ctrl = 1;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	return cypress_write(tty, port, NULL, 0);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89500a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int cypress_ioctl(struct tty_struct *tty,
89695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox					unsigned int cmd, unsigned long arg)
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
89895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
904813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	/* This code comes from drivers/char/serial.c and ftdi_sio.c */
905813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	case TIOCMIWAIT:
906813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		while (priv != NULL) {
907813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			interruptible_sleep_on(&priv->delta_msr_wait);
908813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			/* see if a signal did it */
909813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			if (signal_pending(current))
910813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				return -ERESTARTSYS;
911813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			else {
912813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				char diff = priv->diff_status;
913813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				if (diff == 0)
914813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					return -EIO; /* no change => error */
915813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
916813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				/* consume all events */
917813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				priv->diff_status = 0;
918813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
919813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				/* return 0 if caller wanted to know about
920813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				   these bits */
921813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				if (((arg & TIOCM_RNG) && (diff & UART_RI)) ||
922813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				    ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
923813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				    ((arg & TIOCM_CD) && (diff & UART_CD)) ||
924813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				    ((arg & TIOCM_CTS) && (diff & UART_CTS)))
925813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox					return 0;
926813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				/* otherwise caller can't care less about what
927813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				 * happened, and so we continue to wait for
928813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				 * more events.
929813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				 */
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
931813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		}
932813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		return 0;
933813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	default:
934813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		break;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
936441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_ioctl */
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
94195da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void cypress_set_termios(struct tty_struct *tty,
94295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port, struct ktermios *old_termios)
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int data_bits, stop_bits, parity_type, parity_enable;
9468873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox	unsigned cflag, iflag;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 oldlines;
9493cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez	int linechange = 0;
950b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez
951441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
954fe1ae7fdd2ee603f2d95f04e09a68f7f79045127Alan Cox	/* We can't clean this one up as we don't know the device type
955fe1ae7fdd2ee603f2d95f04e09a68f7f79045127Alan Cox	   early enough */
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!priv->termios_initialized) {
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->chiptype == CT_EARTHMATE) {
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(tty->termios) = tty_std_termios;
959b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
960b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez				CLOCAL;
9618873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox			tty->termios->c_ispeed = 4800;
9628873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox			tty->termios->c_ospeed = 4800;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (priv->chiptype == CT_CYPHIDCOM) {
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(tty->termios) = tty_std_termios;
965b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
966b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez				CLOCAL;
9678873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox			tty->termios->c_ispeed = 9600;
9688873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox			tty->termios->c_ospeed = 9600;
969a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez		} else if (priv->chiptype == CT_CA42V2) {
970a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez			*(tty->termios) = tty_std_termios;
971a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
972a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez				CLOCAL;
9738873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox			tty->termios->c_ispeed = 9600;
9748873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox			tty->termios->c_ospeed = 9600;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->termios_initialized = 1;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9808873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox	/* Unsupported features need clearing */
9818873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox	tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS);
9828873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cflag = tty->termios->c_cflag;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iflag = tty->termios->c_iflag;
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if there are new settings */
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_termios) {
9888873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox		spin_lock_irqsave(&priv->lock, flags);
9898873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox		priv->tmp_termios = *(tty->termios);
9908873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox		spin_unlock_irqrestore(&priv->lock, flags);
9918873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox	}
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set number of data bits, parity, stop bits */
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* when parity is disabled the parity type bit is ignored */
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
996b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	/* 1 means 2 stop bits, 0 means 1 stop bit */
997b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	stop_bits = cflag & CSTOPB ? 1 : 0;
998b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cflag & PARENB) {
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parity_enable = 1;
1001b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez		/* 1 means odd parity, 0 means even parity */
1002b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez		parity_type = cflag & PARODD ? 1 : 0;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parity_enable = parity_type = 0;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
100677336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox	switch (cflag & CSIZE) {
100777336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox	case CS5:
100877336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox		data_bits = 0;
100977336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox		break;
101077336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox	case CS6:
101177336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox		data_bits = 1;
101277336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox		break;
101377336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox	case CS7:
101477336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox		data_bits = 2;
101577336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox		break;
101677336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox	case CS8:
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data_bits = 3;
101877336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox		break;
101977336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox	default:
1020194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman		dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n",
1021194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			__func__);
102277336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox		data_bits = 3;
102377336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox	}
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	oldlines = priv->line_control;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cflag & CBAUD) == B0) {
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* drop dtr and rts */
1028441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - dropping the lines, baud rate 0bps", __func__);
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
10308873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox	} else
10313cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez		priv->line_control = (CONTROL_DTR | CONTROL_RTS);
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1034b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, "
1035441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			"%d data_bits (+5)", __func__, stop_bits,
1036b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			parity_enable, parity_type, data_bits);
1037b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez
1038813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	cypress_serial_control(tty, port, tty_get_baud_rate(tty),
1039813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			data_bits, stop_bits,
1040813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			parity_enable, parity_type,
1041813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			0, CYPRESS_SET_CONFIG);
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1043b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	/* we perform a CYPRESS_GET_CONFIG so that the current settings are
1044b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	 * filled into the private structure this should confirm that all is
1045b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	 * working if it returns what we just set */
104695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	cypress_serial_control(tty, port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1048b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	/* Here we can define custom tty settings for devices; the main tty
1049b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	 * termios flag base comes from empeg.c */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	spin_lock_irqsave(&priv->lock, flags);
1052813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) {
1053b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez		dbg("Using custom termios settings for a baud rate of "
1054b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez				"4800bps.");
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* define custom termios settings for NMEA protocol */
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty->termios->c_iflag /* input modes - */
1058b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			&= ~(IGNBRK  /* disable ignore break */
1059b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| BRKINT     /* disable break causes interrupt */
1060b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| PARMRK     /* disable mark parity errors */
1061b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| ISTRIP     /* disable clear high bit of input char */
1062b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| INLCR      /* disable translate NL to CR */
1063b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| IGNCR      /* disable ignore CR */
1064b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| ICRNL      /* disable translate CR to NL */
1065b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| IXON);     /* disable enable XON/XOFF flow control */
1066b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty->termios->c_oflag /* output modes */
1068b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			&= ~OPOST;    /* disable postprocess output char */
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1070b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez		tty->termios->c_lflag /* line discipline modes */
1071b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			&= ~(ECHO     /* disable echo input characters */
1072b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| ECHONL      /* disable echo new line */
1073b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| ICANON      /* disable erase, kill, werase, and rprnt
1074b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez					 special characters */
1075b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| ISIG        /* disable interrupt, quit, and suspend
1076b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez					 special characters */
1077b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			| IEXTEN);    /* disable non-POSIX special characters */
10783cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez	} /* CT_CYPHIDCOM: Application should handle this for device */
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	linechange = (priv->line_control != oldlines);
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if necessary, set lines */
10843cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez	if (linechange) {
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->cmd_ctrl = 1;
108695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		cypress_write(tty, port, NULL, 0);
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_set_termios */
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1090b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* returns amount of data still left in soft buffer */
109295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int cypress_chars_in_buffer(struct tty_struct *tty)
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
109495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chars = 0;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1099441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
1100813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
1102117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold	chars = kfifo_len(&priv->write_fifo);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1105441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, chars);
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return chars;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111095da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void cypress_throttle(struct tty_struct *tty)
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
111295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1115441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1117638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum	spin_lock_irq(&priv->lock);
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rx_flags = THROTTLED;
1119638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum	spin_unlock_irq(&priv->lock);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
112395da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void cypress_unthrottle(struct tty_struct *tty)
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
112595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int actually_throttled, result;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1129441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum	spin_lock_irq(&priv->lock);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rx_flags = 0;
1134638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum	spin_unlock_irq(&priv->lock);
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
113678aef519ed07797f94cff1d0d66dd01704474916Mike Isely	if (!priv->comm_is_ok)
113778aef519ed07797f94cff1d0d66dd01704474916Mike Isely		return;
113878aef519ed07797f94cff1d0d66dd01704474916Mike Isely
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (actually_throttled) {
1140638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
114178aef519ed07797f94cff1d0d66dd01704474916Mike Isely		if (result) {
1142b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			dev_err(&port->dev, "%s - failed submitting read urb, "
1143441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison					"error %d\n", __func__, result);
114478aef519ed07797f94cff1d0d66dd01704474916Mike Isely			cypress_set_dead(port);
114578aef519ed07797f94cff1d0d66dd01704474916Mike Isely		}
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11507d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void cypress_read_int_callback(struct urb *urb)
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1152cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port = urb->context;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tty_struct *tty;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = urb->transfer_buffer;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1157b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	char tty_flag = TTY_NORMAL;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int havedata = 0;
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bytes = 0;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0;
11628d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman	int status = urb->status;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1164441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11668d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman	switch (status) {
116778aef519ed07797f94cff1d0d66dd01704474916Mike Isely	case 0: /* success */
116878aef519ed07797f94cff1d0d66dd01704474916Mike Isely		break;
116978aef519ed07797f94cff1d0d66dd01704474916Mike Isely	case -ECONNRESET:
117078aef519ed07797f94cff1d0d66dd01704474916Mike Isely	case -ENOENT:
117178aef519ed07797f94cff1d0d66dd01704474916Mike Isely	case -ESHUTDOWN:
117278aef519ed07797f94cff1d0d66dd01704474916Mike Isely		/* precursor to disconnect so just go away */
117378aef519ed07797f94cff1d0d66dd01704474916Mike Isely		return;
117478aef519ed07797f94cff1d0d66dd01704474916Mike Isely	case -EPIPE:
11754d2fae8b3597bc787f1f1c06637ce5ab8187e5a7Alan Stern		/* Can't call usb_clear_halt while in_interrupt */
11764d2fae8b3597bc787f1f1c06637ce5ab8187e5a7Alan Stern		/* FALLS THROUGH */
117778aef519ed07797f94cff1d0d66dd01704474916Mike Isely	default:
117878aef519ed07797f94cff1d0d66dd01704474916Mike Isely		/* something ugly is going on... */
1179813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dev_err(&urb->dev->dev,
1180813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			"%s - unexpected nonzero read status received: %d\n",
1181813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox							__func__, status);
118278aef519ed07797f94cff1d0d66dd01704474916Mike Isely		cypress_set_dead(port);
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->rx_flags & THROTTLED) {
1188441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - now throttling", __func__);
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->rx_flags |= ACTUALLY_THROTTLED;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11954a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty = tty_port_tty_get(&port->port);
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tty) {
1197441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - bad tty pointer - exiting", __func__);
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
12023416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	result = urb->actual_length;
12033416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	switch (priv->pkt_fmt) {
12043416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	default:
12053416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	case packet_format_1:
12063416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		/* This is for the CY7C64013... */
12073416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		priv->current_status = data[0] & 0xF8;
12083416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		bytes = data[1] + 2;
12093416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		i = 2;
12103416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		if (bytes > 2)
12113416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely			havedata = 1;
12123416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		break;
12133416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	case packet_format_2:
12143416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		/* This is for the CY7C63743... */
12153416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		priv->current_status = data[0] & 0xF8;
12163416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		bytes = (data[0] & 0x07) + 1;
12173416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		i = 1;
12183416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		if (bytes > 1)
12193416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely			havedata = 1;
12203416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		break;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
12233416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	if (result < bytes) {
12243416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		dbg("%s - wrong packet size - received %d bytes but packet "
12253416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		    "said %d bytes", __func__, result, bytes);
12263416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely		goto continue_read;
12273416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely	}
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1229813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	usb_serial_debug_data(debug, &port->dev, __func__,
1230813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox						urb->actual_length, data);
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check to see if status has changed */
12346768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely	if (priv->current_status != priv->prev_status) {
12356768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely		priv->diff_status |= priv->current_status ^
12366768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely			priv->prev_status;
12376768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely		wake_up_interruptible(&priv->delta_msr_wait);
12386768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely		priv->prev_status = priv->current_status;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1240b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	spin_unlock_irqrestore(&priv->lock, flags);
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1242b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	/* hangup, as defined in acm.c... this might be a bad place for it
1243b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	 * though */
1244b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	if (tty && !(tty->termios->c_cflag & CLOCAL) &&
1245b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			!(priv->current_status & UART_CD)) {
1246441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - calling hangup", __func__);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_hangup(tty);
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto continue_read;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	/* There is one error bit... I'm assuming it is a parity error
1252b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	 * indicator as the generic firmware will set this bit to 1 if a
1253b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	 * parity error occurs.
1254b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	 * I can not find reference to any other error events. */
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->current_status & CYP_ERROR) {
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_flag = TTY_PARITY;
1259441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - Parity Error detected", __func__);
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->lock, flags);
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* process read if there is data other than line status */
1264a108bfcb372d8c4452701039308fb95747911c59Alan Cox	if (tty && bytes > i) {
1265a108bfcb372d8c4452701039308fb95747911c59Alan Cox		tty_insert_flip_string_fixed_flag(tty, data + i,
126670ced221cc9f041481f129e63cc5b1dedb0ff959Johan Hovold				tty_flag, bytes - i);
12674a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox		tty_flip_buffer_push(tty);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->lock, flags);
1271b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	/* control and status byte(s) are also counted */
1272b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez	priv->bytes_in += bytes;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->lock, flags);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscontinue_read:
12764a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty_kref_put(tty);
1277b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez
12781f87158e44e79e62c8250f278c225ce4ab695f4bAlan Stern	/* Continue trying to always read */
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12801f87158e44e79e62c8250f278c225ce4ab695f4bAlan Stern	if (priv->comm_is_ok) {
1281b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez		usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
1282b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez				usb_rcvintpipe(port->serial->dev,
1283b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez					port->interrupt_in_endpointAddress),
1284b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez				port->interrupt_in_urb->transfer_buffer,
1285b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez				port->interrupt_in_urb->transfer_buffer_length,
1286813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				cypress_read_int_callback, port,
1287813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox				priv->read_urb_interval);
1288b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
12891f87158e44e79e62c8250f278c225ce4ab695f4bAlan Stern		if (result && result != -EPERM) {
1290b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez			dev_err(&urb->dev->dev, "%s - failed resubmitting "
1291441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison					"read urb, error %d\n", __func__,
1292b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez					result);
129378aef519ed07797f94cff1d0d66dd01704474916Mike Isely			cypress_set_dead(port);
129478aef519ed07797f94cff1d0d66dd01704474916Mike Isely		}
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_read_int_callback */
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void cypress_write_int_callback(struct urb *urb)
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1301cdc97792289179974af6dda781c855696358d307Ming Lei	struct usb_serial_port *port = urb->context;
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cypress_private *priv = usb_get_serial_port_data(port);
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
13048d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman	int status = urb->status;
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1306441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
13078d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman
13088d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman	switch (status) {
1309813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	case 0:
1310813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		/* success */
1311813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		break;
1312813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	case -ECONNRESET:
1313813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	case -ENOENT:
1314813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	case -ESHUTDOWN:
1315813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		/* this urb is terminated, clean up */
1316813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dbg("%s - urb shutting down with status: %d",
1317813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox						__func__, status);
1318813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		priv->write_urb_in_use = 0;
1319813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		return;
1320813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	case -EPIPE: /* no break needed; clear halt and resubmit */
1321813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		if (!priv->comm_is_ok)
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1323813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		usb_clear_halt(port->serial->dev, 0x02);
1324813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		/* error in the urb, so we have to resubmit it */
1325813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dbg("%s - nonzero write bulk status received: %d",
1326813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			__func__, status);
1327813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		port->interrupt_out_urb->transfer_buffer_length = 1;
1328813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
1329813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		if (!result)
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
1331813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dev_err(&urb->dev->dev,
1332813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			"%s - failed resubmitting write urb, error %d\n",
1333813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox							__func__, result);
1334813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		cypress_set_dead(port);
1335813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		break;
1336813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox	default:
1337813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		dev_err(&urb->dev->dev,
1338813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox			 "%s - unexpected nonzero write status received: %d\n",
1339813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox							__func__, status);
1340813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		cypress_set_dead(port);
1341813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox		break;
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->write_urb_in_use = 0;
1344813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* send any buffered data */
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cypress_send(port);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13497e3131f897969f94f605f3e929e2da35202c86d6Greg Kroah-Hartmanmodule_usb_serial_driver(cypress_driver, serial_drivers);
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan CoxMODULE_AUTHOR(DRIVER_AUTHOR);
1352813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan CoxMODULE_DESCRIPTION(DRIVER_DESC);
1353813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan CoxMODULE_VERSION(DRIVER_VERSION);
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR);
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not");
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(stats, bool, S_IRUGO | S_IWUSR);
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(stats, "Enable statistics or not");
13603cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendezmodule_param(interval, int, S_IRUGO | S_IWUSR);
13613cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie MendezMODULE_PARM_DESC(interval, "Overrides interrupt interval");
1362c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike Frysingermodule_param(unstable_bauds, bool, S_IRUGO | S_IWUSR);
1363c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike FrysingerMODULE_PARM_DESC(unstable_bauds, "Allow unstable baud rates");
1364