cypress_m8.c 45.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*
 * USB Cypress M8 driver
 *
 * 	Copyright (C) 2004
A
Alan Cox 已提交
5
 * 	    Lonnie Mendez (dignome@gmail.com)
L
Linus Torvalds 已提交
6 7 8 9 10 11 12 13
 *	Copyright (C) 2003,2004
 *	    Neil Whelchel (koyama@firstlight.net)
 *
 * 	This program is free software; you can redistribute it and/or modify
 * 	it under the terms of the GNU General Public License as published by
 * 	the Free Software Foundation; either version 2 of the License, or
 * 	(at your option) any later version.
 *
A
Alan Cox 已提交
14 15
 * See Documentation/usb/usb-serial.txt for more information on using this
 * driver
L
Linus Torvalds 已提交
16 17 18 19
 *
 * See http://geocities.com/i0xox0i for information on this driver and the
 * earthmate usb device.
 *
20 21
 *  Lonnie Mendez <dignome@gmail.com>
 *  4-29-2005
A
Alan Cox 已提交
22 23 24 25 26 27 28
 *	Fixed problem where setting or retreiving the serial config would fail
 *	with EPIPE.  Removed CRTS toggling so the driver behaves more like
 *	other usbserial adapters.  Issued new interval of 1ms instead of the
 *	default 10ms.  As a result, transfer speed has been substantially
 *	increased from avg. 850bps to avg. 3300bps.  initial termios has also
 *	been modified.  Cleaned up code and formatting issues so it is more
 *	readable.  Replaced the C++ style comments.
L
Linus Torvalds 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
 *
 *  Lonnie Mendez <dignome@gmail.com>
 *  12-15-2004
 *	Incorporated write buffering from pl2303 driver.  Fixed bug with line
 *	handling so both lines are raised in cypress_open. (was dropping rts)
 *      Various code cleanups made as well along with other misc bug fixes.
 *
 *  Lonnie Mendez <dignome@gmail.com>
 *  04-10-2004
 *	Driver modified to support dynamic line settings.  Various improvments
 *      and features.
 *
 *  Neil Whelchel
 *  10-2003
 *	Driver first released.
 *
 */

A
Alan Cox 已提交
47 48
/* Thanks to Neil Whelchel for writing the first cypress m8 implementation
   for linux. */
L
Linus Torvalds 已提交
49 50
/* Thanks to cypress for providing references for the hid reports. */
/* Thanks to Jiang Zhang for providing links and for general help. */
A
Alan Cox 已提交
51
/* Code originates and was built up from ftdi_sio, belkin, pl2303 and others.*/
L
Linus Torvalds 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64


#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
65
#include <linux/usb/serial.h>
L
Linus Torvalds 已提交
66 67
#include <linux/serial.h>
#include <linux/delay.h>
A
Alan Cox 已提交
68
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
69 70 71 72

#include "cypress_m8.h"


73
static int debug;
L
Linus Torvalds 已提交
74
static int stats;
75
static int interval;
L
Linus Torvalds 已提交
76 77 78 79

/*
 * Version Information
 */
80
#define DRIVER_VERSION "v1.09"
L
Linus Torvalds 已提交
81 82 83 84 85 86 87 88 89
#define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>"
#define DRIVER_DESC "Cypress USB to Serial Driver"

/* write buffer size defines */
#define CYPRESS_BUF_SIZE	1024
#define CYPRESS_CLOSING_WAIT	(30*HZ)

static struct usb_device_id id_table_earthmate [] = {
	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
90
	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
L
Linus Torvalds 已提交
91 92 93 94 95
	{ }						/* Terminating entry */
};

static struct usb_device_id id_table_cyphidcomrs232 [] = {
	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
96
	{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
L
Linus Torvalds 已提交
97 98 99
	{ }						/* Terminating entry */
};

100 101 102 103 104
static struct usb_device_id id_table_nokiaca42v2 [] = {
	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
	{ }						/* Terminating entry */
};

L
Linus Torvalds 已提交
105 106
static struct usb_device_id id_table_combined [] = {
	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
107
	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
L
Linus Torvalds 已提交
108
	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
109
	{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
110
	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
L
Linus Torvalds 已提交
111 112 113
	{ }						/* Terminating entry */
};

A
Alan Cox 已提交
114
MODULE_DEVICE_TABLE(usb, id_table_combined);
L
Linus Torvalds 已提交
115 116 117 118 119 120

static struct usb_driver cypress_driver = {
	.name =		"cypress",
	.probe =	usb_serial_probe,
	.disconnect =	usb_serial_disconnect,
	.id_table =	id_table_combined,
121
	.no_dynamic_id = 	1,
L
Linus Torvalds 已提交
122 123
};

124 125 126 127 128
enum packet_format {
	packet_format_1,  /* b0:status, b1:payload count */
	packet_format_2   /* b0[7:3]:status, b0[2:0]:payload count */
};

L
Linus Torvalds 已提交
129 130 131 132 133 134 135 136 137
struct cypress_private {
	spinlock_t lock;		   /* private lock */
	int chiptype;			   /* identifier of device, for quirks/etc */
	int bytes_in;			   /* used for statistics */
	int bytes_out;			   /* used for statistics */
	int cmd_count;			   /* used for statistics */
	int cmd_ctrl;			   /* always set this to 1 before issuing a command */
	struct cypress_buf *buf;	   /* write buffer */
	int write_urb_in_use;		   /* write urb in use indicator */
138 139
	int write_urb_interval;            /* interval to use for write urb */
	int read_urb_interval;             /* interval to use for read urb */
140
	int comm_is_ok;                    /* true if communication is (still) ok */
L
Linus Torvalds 已提交
141 142 143 144 145
	int termios_initialized;
	__u8 line_control;	   	   /* holds dtr / rts value */
	__u8 current_status;	   	   /* received from last read - info on dsr,cts,cd,ri,etc */
	__u8 current_config;	   	   /* stores the current configuration byte */
	__u8 rx_flags;			   /* throttling - used from whiteheat/ftdi_sio */
146
	enum packet_format pkt_fmt;	   /* format to use for packet send / receive */
147
	int get_cfg_unsafe;		   /* If true, the CYPRESS_GET_CONFIG is unsafe */
A
Alan Cox 已提交
148 149
	int baud_rate;			   /* stores current baud rate in
					      integer form */
L
Linus Torvalds 已提交
150 151 152
	int isthrottled;		   /* if throttled, discard reads */
	wait_queue_head_t delta_msr_wait;  /* used for TIOCMIWAIT */
	char prev_status, diff_status;	   /* used for TIOCMIWAIT */
A
Alan Cox 已提交
153 154
	/* we pass a pointer to this as the arguement sent to
	   cypress_set_termios old_termios */
A
Alan Cox 已提交
155
	struct ktermios tmp_termios; 	   /* stores the old termios settings */
L
Linus Torvalds 已提交
156 157 158 159 160 161 162 163 164 165 166
};

/* write buffer structure */
struct cypress_buf {
	unsigned int	buf_size;
	char		*buf_buf;
	char		*buf_get;
	char		*buf_put;
};

/* function prototypes for the Cypress USB to serial device */
A
Alan Cox 已提交
167 168 169
static int  cypress_earthmate_startup(struct usb_serial *serial);
static int  cypress_hidcom_startup(struct usb_serial *serial);
static int  cypress_ca42v2_startup(struct usb_serial *serial);
170
static void cypress_release(struct usb_serial *serial);
171
static int  cypress_open(struct tty_struct *tty, struct usb_serial_port *port);
172 173
static void cypress_close(struct usb_serial_port *port);
static void cypress_dtr_rts(struct usb_serial_port *port, int on);
A
Alan Cox 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
static int  cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
			const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
static int  cypress_write_room(struct tty_struct *tty);
static int  cypress_ioctl(struct tty_struct *tty, struct file *file,
			unsigned int cmd, unsigned long arg);
static void cypress_set_termios(struct tty_struct *tty,
			struct usb_serial_port *port, struct ktermios *old);
static int  cypress_tiocmget(struct tty_struct *tty, struct file *file);
static int  cypress_tiocmset(struct tty_struct *tty, struct file *file,
			unsigned int set, unsigned int clear);
static int  cypress_chars_in_buffer(struct tty_struct *tty);
static void cypress_throttle(struct tty_struct *tty);
static void cypress_unthrottle(struct tty_struct *tty);
static void cypress_set_dead(struct usb_serial_port *port);
static void cypress_read_int_callback(struct urb *urb);
static void cypress_write_int_callback(struct urb *urb);
L
Linus Torvalds 已提交
191 192
/* write buffer functions */
static struct cypress_buf *cypress_buf_alloc(unsigned int size);
A
Alan Cox 已提交
193 194 195 196 197 198 199 200
static void cypress_buf_free(struct cypress_buf *cb);
static void cypress_buf_clear(struct cypress_buf *cb);
static unsigned int cypress_buf_data_avail(struct cypress_buf *cb);
static unsigned int cypress_buf_space_avail(struct cypress_buf *cb);
static unsigned int cypress_buf_put(struct cypress_buf *cb,
					const char *buf, unsigned int count);
static unsigned int cypress_buf_get(struct cypress_buf *cb,
					char *buf, unsigned int count);
L
Linus Torvalds 已提交
201 202


203
static struct usb_serial_driver cypress_earthmate_device = {
204 205
	.driver = {
		.owner =		THIS_MODULE,
206
		.name =			"earthmate",
207
	},
208
	.description =			"DeLorme Earthmate USB",
209
	.usb_driver = 			&cypress_driver,
L
Linus Torvalds 已提交
210 211 212
	.id_table =			id_table_earthmate,
	.num_ports =			1,
	.attach =			cypress_earthmate_startup,
213
	.release =			cypress_release,
L
Linus Torvalds 已提交
214 215
	.open =				cypress_open,
	.close =			cypress_close,
216
	.dtr_rts =			cypress_dtr_rts,
L
Linus Torvalds 已提交
217 218 219 220 221 222 223 224 225 226 227 228 229
	.write =			cypress_write,
	.write_room =			cypress_write_room,
	.ioctl =			cypress_ioctl,
	.set_termios =			cypress_set_termios,
	.tiocmget =			cypress_tiocmget,
	.tiocmset =			cypress_tiocmset,
	.chars_in_buffer =		cypress_chars_in_buffer,
	.throttle =		 	cypress_throttle,
	.unthrottle =			cypress_unthrottle,
	.read_int_callback =		cypress_read_int_callback,
	.write_int_callback =		cypress_write_int_callback,
};

230
static struct usb_serial_driver cypress_hidcom_device = {
231 232
	.driver = {
		.owner =		THIS_MODULE,
233
		.name =			"cyphidcom",
234
	},
235
	.description =			"HID->COM RS232 Adapter",
236
	.usb_driver = 			&cypress_driver,
L
Linus Torvalds 已提交
237 238 239
	.id_table =			id_table_cyphidcomrs232,
	.num_ports =			1,
	.attach =			cypress_hidcom_startup,
240
	.release =			cypress_release,
L
Linus Torvalds 已提交
241 242
	.open =				cypress_open,
	.close =			cypress_close,
243
	.dtr_rts =			cypress_dtr_rts,
L
Linus Torvalds 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256
	.write =			cypress_write,
	.write_room =			cypress_write_room,
	.ioctl =			cypress_ioctl,
	.set_termios =			cypress_set_termios,
	.tiocmget =			cypress_tiocmget,
	.tiocmset =			cypress_tiocmset,
	.chars_in_buffer =		cypress_chars_in_buffer,
	.throttle =			cypress_throttle,
	.unthrottle =			cypress_unthrottle,
	.read_int_callback =		cypress_read_int_callback,
	.write_int_callback =		cypress_write_int_callback,
};

257 258 259
static struct usb_serial_driver cypress_ca42v2_device = {
	.driver = {
		.owner =		THIS_MODULE,
A
Alan Cox 已提交
260
		.name =			"nokiaca42v2",
261 262
	},
	.description =			"Nokia CA-42 V2 Adapter",
263
	.usb_driver = 			&cypress_driver,
264 265 266
	.id_table =			id_table_nokiaca42v2,
	.num_ports =			1,
	.attach =			cypress_ca42v2_startup,
267
	.release =			cypress_release,
268 269
	.open =				cypress_open,
	.close =			cypress_close,
270
	.dtr_rts =			cypress_dtr_rts,
271 272 273 274 275 276 277 278 279 280 281 282
	.write =			cypress_write,
	.write_room =			cypress_write_room,
	.ioctl =			cypress_ioctl,
	.set_termios =			cypress_set_termios,
	.tiocmget =			cypress_tiocmget,
	.tiocmset =			cypress_tiocmset,
	.chars_in_buffer =		cypress_chars_in_buffer,
	.throttle =			cypress_throttle,
	.unthrottle =			cypress_unthrottle,
	.read_int_callback =		cypress_read_int_callback,
	.write_int_callback =		cypress_write_int_callback,
};
L
Linus Torvalds 已提交
283 284 285 286 287 288

/*****************************************************************************
 * Cypress serial helper functions
 *****************************************************************************/


A
Alan Cox 已提交
289
static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
{
	struct cypress_private *priv;
	priv = usb_get_serial_port_data(port);

	/*
	 * The general purpose firmware for the Cypress M8 allows for
	 * a maximum speed of 57600bps (I have no idea whether DeLorme
	 * chose to use the general purpose firmware or not), if you
	 * need to modify this speed setting for your own project
	 * please add your own chiptype and modify the code likewise.
	 * The Cypress HID->COM device will work successfully up to
	 * 115200bps (but the actual throughput is around 3kBps).
	 */
	if (port->serial->dev->speed == USB_SPEED_LOW) {
		/*
		 * Mike Isely <isely@pobox.com> 2-Feb-2008: The
		 * Cypress app note that describes this mechanism
		 * states the the low-speed part can't handle more
		 * than 800 bytes/sec, in which case 4800 baud is the
		 * safest speed for a part like that.
		 */
		if (new_rate > 4800) {
			dbg("%s - failed setting baud rate, device incapable "
			    "speed %d", __func__, new_rate);
			return -1;
		}
	}
	switch (priv->chiptype) {
	case CT_EARTHMATE:
		if (new_rate <= 600) {
			/* 300 and 600 baud rates are supported under
			 * the generic firmware, but are not used with
			 * NMEA and SiRF protocols */
			dbg("%s - failed setting baud rate, unsupported speed "
			    "of %d on Earthmate GPS", __func__, new_rate);
			return -1;
		}
		break;
	default:
		break;
	}
	return new_rate;
}


335
/* This function can either set or retrieve the current serial line settings */
A
Alan Cox 已提交
336
static int cypress_serial_control(struct tty_struct *tty,
A
Alan Cox 已提交
337 338 339
	struct usb_serial_port *port, speed_t baud_rate, int data_bits,
	int stop_bits, int parity_enable, int parity_type, int reset,
	int cypress_request_type)
L
Linus Torvalds 已提交
340
{
341
	int new_baudrate = 0, retval = 0, tries = 0;
L
Linus Torvalds 已提交
342
	struct cypress_private *priv;
343
	__u8 feature_buffer[5];
L
Linus Torvalds 已提交
344 345
	unsigned long flags;

346
	dbg("%s", __func__);
A
Alan Cox 已提交
347

L
Linus Torvalds 已提交
348 349
	priv = usb_get_serial_port_data(port);

350 351 352
	if (!priv->comm_is_ok)
		return -ENODEV;

A
Alan Cox 已提交
353 354 355 356 357
	switch (cypress_request_type) {
	case CYPRESS_SET_CONFIG:
		new_baudrate = priv->baud_rate;
		/* 0 means 'Hang up' so doesn't change the true bit rate */
		if (baud_rate == 0)
358
			new_baudrate = priv->baud_rate;
A
Alan Cox 已提交
359 360 361 362 363 364 365 366
		/* Change of speed ? */
		else if (baud_rate != priv->baud_rate) {
			dbg("%s - baud rate is changing", __func__);
			retval = analyze_baud_rate(port, baud_rate);
			if (retval >=  0) {
				new_baudrate = retval;
				dbg("%s - New baud rate set to %d",
				    __func__, new_baudrate);
L
Linus Torvalds 已提交
367
			}
A
Alan Cox 已提交
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
		}
		dbg("%s - baud rate is being sent as %d",
					__func__, new_baudrate);

		memset(feature_buffer, 0, sizeof(feature_buffer));
		/* fill the feature_buffer with new configuration */
		*((u_int32_t *)feature_buffer) = new_baudrate;
		feature_buffer[4] |= data_bits;   /* assign data bits in 2 bit space ( max 3 ) */
		/* 1 bit gap */
		feature_buffer[4] |= (stop_bits << 3);   /* assign stop bits in 1 bit space */
		feature_buffer[4] |= (parity_enable << 4);   /* assign parity flag in 1 bit space */
		feature_buffer[4] |= (parity_type << 5);   /* assign parity type in 1 bit space */
		/* 1 bit gap */
		feature_buffer[4] |= (reset << 7);   /* assign reset at end of byte, 1 bit space */

		dbg("%s - device is being sent this feature report:",
								__func__);
		dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__,
			feature_buffer[0], feature_buffer[1],
			feature_buffer[2], feature_buffer[3],
			feature_buffer[4]);

		do {
			retval = usb_control_msg(port->serial->dev,
					usb_sndctrlpipe(port->serial->dev, 0),
					HID_REQ_SET_REPORT,
					USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
					0x0300, 0, feature_buffer,
					sizeof(feature_buffer), 500);

			if (tries++ >= 3)
				break;

		} while (retval != sizeof(feature_buffer) &&
			 retval != -ENODEV);

		if (retval != sizeof(feature_buffer)) {
405 406
			dev_err(&port->dev, "%s - failed sending serial "
				"line settings - %d\n", __func__, retval);
A
Alan Cox 已提交
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
			cypress_set_dead(port);
		} else {
			spin_lock_irqsave(&priv->lock, flags);
			priv->baud_rate = new_baudrate;
			priv->current_config = feature_buffer[4];
			spin_unlock_irqrestore(&priv->lock, flags);
			/* If we asked for a speed change encode it */
			if (baud_rate)
				tty_encode_baud_rate(tty,
					new_baudrate, new_baudrate);
		}
	break;
	case CYPRESS_GET_CONFIG:
		if (priv->get_cfg_unsafe) {
			/* Not implemented for this device,
			   and if we try to do it we're likely
			   to crash the hardware. */
			return -ENOTTY;
		}
		dbg("%s - retreiving serial line settings", __func__);
		/* set initial values in feature buffer */
		memset(feature_buffer, 0, sizeof(feature_buffer));

		do {
			retval = usb_control_msg(port->serial->dev,
					usb_rcvctrlpipe(port->serial->dev, 0),
					HID_REQ_GET_REPORT,
					USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
					0x0300, 0, feature_buffer,
					sizeof(feature_buffer), 500);

			if (tries++ >= 3)
				break;
		} while (retval != sizeof(feature_buffer)
						&& retval != -ENODEV);

		if (retval != sizeof(feature_buffer)) {
444 445
			dev_err(&port->dev, "%s - failed to retrieve serial "
				"line settings - %d\n", __func__, retval);
A
Alan Cox 已提交
446 447 448 449 450 451 452 453 454 455
			cypress_set_dead(port);
			return retval;
		} else {
			spin_lock_irqsave(&priv->lock, flags);
			/* store the config in one byte, and later
			   use bit masks to check values */
			priv->current_config = feature_buffer[4];
			priv->baud_rate = *((u_int32_t *)feature_buffer);
			spin_unlock_irqrestore(&priv->lock, flags);
		}
L
Linus Torvalds 已提交
456
	}
457 458 459 460
	spin_lock_irqsave(&priv->lock, flags);
	++priv->cmd_count;
	spin_unlock_irqrestore(&priv->lock, flags);

L
Linus Torvalds 已提交
461 462 463 464
	return retval;
} /* cypress_serial_control */


465 466 467 468 469 470 471 472 473 474 475 476 477
static void cypress_set_dead(struct usb_serial_port *port)
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
	if (!priv->comm_is_ok) {
		spin_unlock_irqrestore(&priv->lock, flags);
		return;
	}
	priv->comm_is_ok = 0;
	spin_unlock_irqrestore(&priv->lock, flags);

478 479
	dev_err(&port->dev, "cypress_m8 suspending failing port %d - "
		"interval might be too short\n", port->number);
480 481 482
}


L
Linus Torvalds 已提交
483 484 485 486 487
/*****************************************************************************
 * Cypress serial driver functions
 *****************************************************************************/


A
Alan Cox 已提交
488
static int generic_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
489 490
{
	struct cypress_private *priv;
491
	struct usb_serial_port *port = serial->port[0];
L
Linus Torvalds 已提交
492

493
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
494

A
Alan Cox 已提交
495
	priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
L
Linus Torvalds 已提交
496 497 498
	if (!priv)
		return -ENOMEM;

499
	priv->comm_is_ok = !0;
L
Linus Torvalds 已提交
500 501 502 503 504 505 506
	spin_lock_init(&priv->lock);
	priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
	if (priv->buf == NULL) {
		kfree(priv);
		return -ENOMEM;
	}
	init_waitqueue_head(&priv->delta_msr_wait);
A
Alan Cox 已提交
507 508 509

	usb_reset_configuration(serial->dev);

L
Linus Torvalds 已提交
510 511 512 513
	priv->cmd_ctrl = 0;
	priv->line_control = 0;
	priv->termios_initialized = 0;
	priv->rx_flags = 0;
514 515 516 517 518 519
	/* Default packet format setting is determined by packet size.
	   Anything with a size larger then 9 must have a separate
	   count field since the 3 bit count field is otherwise too
	   small.  Otherwise we can use the slightly more compact
	   format.  This is in accordance with the cypress_m8 serial
	   converter app note. */
A
Alan Cox 已提交
520
	if (port->interrupt_out_size > 9)
521
		priv->pkt_fmt = packet_format_1;
A
Alan Cox 已提交
522
	else
523
		priv->pkt_fmt = packet_format_2;
A
Alan Cox 已提交
524

525 526 527 528
	if (interval > 0) {
		priv->write_urb_interval = interval;
		priv->read_urb_interval = interval;
		dbg("%s - port %d read & write intervals forced to %d",
A
Alan Cox 已提交
529
		    __func__, port->number, interval);
530 531 532 533
	} else {
		priv->write_urb_interval = port->interrupt_out_urb->interval;
		priv->read_urb_interval = port->interrupt_in_urb->interval;
		dbg("%s - port %d intervals: read=%d write=%d",
A
Alan Cox 已提交
534 535
		    __func__, port->number,
		    priv->read_urb_interval, priv->write_urb_interval);
536 537
	}
	usb_set_serial_port_data(port, priv);
A
Alan Cox 已提交
538

539 540
	return 0;
}
L
Linus Torvalds 已提交
541 542


A
Alan Cox 已提交
543
static int cypress_earthmate_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
544 545
{
	struct cypress_private *priv;
546
	struct usb_serial_port *port = serial->port[0];
L
Linus Torvalds 已提交
547

548
	dbg("%s", __func__);
L
Linus Torvalds 已提交
549 550

	if (generic_startup(serial)) {
551
		dbg("%s - Failed setting up port %d", __func__,
552
				port->number);
L
Linus Torvalds 已提交
553 554 555
		return 1;
	}

556
	priv = usb_get_serial_port_data(port);
L
Linus Torvalds 已提交
557
	priv->chiptype = CT_EARTHMATE;
558 559 560
	/* All Earthmate devices use the separated-count packet
	   format!  Idiotic. */
	priv->pkt_fmt = packet_format_1;
A
Alan Cox 已提交
561 562
	if (serial->dev->descriptor.idProduct !=
				cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) {
563 564 565 566 567 568 569 570
		/* The old original USB Earthmate seemed able to
		   handle GET_CONFIG requests; everything they've
		   produced since that time crashes if this command is
		   attempted :-( */
		dbg("%s - Marking this device as unsafe for GET_CONFIG "
		    "commands", __func__);
		priv->get_cfg_unsafe = !0;
	}
571 572

	return 0;
L
Linus Torvalds 已提交
573 574 575
} /* cypress_earthmate_startup */


A
Alan Cox 已提交
576
static int cypress_hidcom_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
577 578 579
{
	struct cypress_private *priv;

580
	dbg("%s", __func__);
L
Linus Torvalds 已提交
581 582

	if (generic_startup(serial)) {
583
		dbg("%s - Failed setting up port %d", __func__,
584
				serial->port[0]->number);
L
Linus Torvalds 已提交
585 586 587 588 589
		return 1;
	}

	priv = usb_get_serial_port_data(serial->port[0]);
	priv->chiptype = CT_CYPHIDCOM;
A
Alan Cox 已提交
590

591
	return 0;
L
Linus Torvalds 已提交
592 593 594
} /* cypress_hidcom_startup */


A
Alan Cox 已提交
595
static int cypress_ca42v2_startup(struct usb_serial *serial)
596 597 598
{
	struct cypress_private *priv;

599
	dbg("%s", __func__);
600 601

	if (generic_startup(serial)) {
602
		dbg("%s - Failed setting up port %d", __func__,
603 604 605 606 607 608 609 610 611 612 613
				serial->port[0]->number);
		return 1;
	}

	priv = usb_get_serial_port_data(serial->port[0]);
	priv->chiptype = CT_CA42V2;

	return 0;
} /* cypress_ca42v2_startup */


614
static void cypress_release(struct usb_serial *serial)
L
Linus Torvalds 已提交
615 616 617
{
	struct cypress_private *priv;

A
Alan Cox 已提交
618
	dbg("%s - port %d", __func__, serial->port[0]->number);
L
Linus Torvalds 已提交
619 620 621 622 623 624 625 626 627 628 629 630

	/* all open ports are closed at this point */

	priv = usb_get_serial_port_data(serial->port[0]);

	if (priv) {
		cypress_buf_free(priv->buf);
		kfree(priv);
	}
}


631
static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
L
Linus Torvalds 已提交
632 633 634 635 636 637
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
	struct usb_serial *serial = port->serial;
	unsigned long flags;
	int result = 0;

638
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
639

640 641 642
	if (!priv->comm_is_ok)
		return -EIO;

L
Linus Torvalds 已提交
643 644 645 646 647 648 649 650 651 652 653 654
	/* clear halts before open */
	usb_clear_halt(serial->dev, 0x81);
	usb_clear_halt(serial->dev, 0x02);

	spin_lock_irqsave(&priv->lock, flags);
	/* reset read/write statistics */
	priv->bytes_in = 0;
	priv->bytes_out = 0;
	priv->cmd_count = 0;
	priv->rx_flags = 0;
	spin_unlock_irqrestore(&priv->lock, flags);

655
	/* Set termios */
A
Alan Cox 已提交
656
	cypress_send(port);
L
Linus Torvalds 已提交
657

A
Alan Cox 已提交
658 659
	if (tty)
		cypress_set_termios(tty, port, &priv->tmp_termios);
L
Linus Torvalds 已提交
660 661

	/* setup the port and start reading from the device */
A
Alan Cox 已提交
662
	if (!port->interrupt_in_urb) {
663 664
		dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n",
			__func__);
A
Alan Cox 已提交
665
		return -1;
L
Linus Torvalds 已提交
666 667 668 669
	}

	usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
		usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
A
Alan Cox 已提交
670 671
		port->interrupt_in_urb->transfer_buffer,
		port->interrupt_in_urb->transfer_buffer_length,
672
		cypress_read_int_callback, port, priv->read_urb_interval);
L
Linus Torvalds 已提交
673 674
	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);

A
Alan Cox 已提交
675 676 677 678
	if (result) {
		dev_err(&port->dev,
			"%s - failed submitting read urb, error %d\n",
							__func__, result);
679
		cypress_set_dead(port);
L
Linus Torvalds 已提交
680
	}
681
	port->port.drain_delay = 256;
L
Linus Torvalds 已提交
682 683 684
	return result;
} /* cypress_open */

685 686 687 688 689 690 691 692 693 694 695 696 697 698
static void cypress_dtr_rts(struct usb_serial_port *port, int on)
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
	/* drop dtr and rts */
	priv = usb_get_serial_port_data(port);
	spin_lock_irq(&priv->lock);
	if (on == 0)
		priv->line_control = 0;
	else 
		priv->line_control = CONTROL_DTR | CONTROL_RTS;
	priv->cmd_ctrl = 1;
	spin_unlock_irq(&priv->lock);
	cypress_write(NULL, port, NULL, 0);
}
L
Linus Torvalds 已提交
699

700
static void cypress_close(struct usb_serial_port *port)
L
Linus Torvalds 已提交
701 702 703
{
	struct cypress_private *priv = usb_get_serial_port_data(port);

704
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
705

706 707 708 709 710 711
	/* writing is potentially harmful, lock must be taken */
	mutex_lock(&port->serial->disc_mutex);
	if (port->serial->disconnected) {
		mutex_unlock(&port->serial->disc_mutex);
		return;
	}
712
	cypress_buf_clear(priv->buf);
713
	dbg("%s - stopping urbs", __func__);
A
Alan Cox 已提交
714 715
	usb_kill_urb(port->interrupt_in_urb);
	usb_kill_urb(port->interrupt_out_urb);
L
Linus Torvalds 已提交
716 717 718


	if (stats)
A
Alan Cox 已提交
719 720
		dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
			priv->bytes_in, priv->bytes_out, priv->cmd_count);
721
	mutex_unlock(&port->serial->disc_mutex);
L
Linus Torvalds 已提交
722 723 724
} /* cypress_close */


A
Alan Cox 已提交
725 726
static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
					const unsigned char *buf, int count)
L
Linus Torvalds 已提交
727 728 729
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
A
Alan Cox 已提交
730

731
	dbg("%s - port %d, %d bytes", __func__, port->number, count);
L
Linus Torvalds 已提交
732 733 734 735 736 737 738 739

	/* line control commands, which need to be executed immediately,
	   are not put into the buffer for obvious reasons.
	 */
	if (priv->cmd_ctrl) {
		count = 0;
		goto finish;
	}
A
Alan Cox 已提交
740

L
Linus Torvalds 已提交
741 742
	if (!count)
		return count;
A
Alan Cox 已提交
743

L
Linus Torvalds 已提交
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
	spin_lock_irqsave(&priv->lock, flags);
	count = cypress_buf_put(priv->buf, buf, count);
	spin_unlock_irqrestore(&priv->lock, flags);

finish:
	cypress_send(port);

	return count;
} /* cypress_write */


static void cypress_send(struct usb_serial_port *port)
{
	int count = 0, result, offset, actual_size;
	struct cypress_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
A
Alan Cox 已提交
760

761 762 763
	if (!priv->comm_is_ok)
		return;

764
	dbg("%s - port %d", __func__, port->number);
A
Alan Cox 已提交
765 766 767
	dbg("%s - interrupt out size is %d", __func__,
						port->interrupt_out_size);

L
Linus Torvalds 已提交
768 769
	spin_lock_irqsave(&priv->lock, flags);
	if (priv->write_urb_in_use) {
770
		dbg("%s - can't write, urb in use", __func__);
L
Linus Torvalds 已提交
771 772 773 774 775 776
		spin_unlock_irqrestore(&priv->lock, flags);
		return;
	}
	spin_unlock_irqrestore(&priv->lock, flags);

	/* clear buffer */
A
Alan Cox 已提交
777 778
	memset(port->interrupt_out_urb->transfer_buffer, 0,
						port->interrupt_out_size);
L
Linus Torvalds 已提交
779 780

	spin_lock_irqsave(&priv->lock, flags);
781 782 783 784 785 786 787 788 789 790 791 792
	switch (priv->pkt_fmt) {
	default:
	case packet_format_1:
		/* this is for the CY7C64013... */
		offset = 2;
		port->interrupt_out_buffer[0] = priv->line_control;
		break;
	case packet_format_2:
		/* this is for the CY7C63743... */
		offset = 1;
		port->interrupt_out_buffer[0] = priv->line_control;
		break;
L
Linus Torvalds 已提交
793 794 795 796 797 798 799
	}

	if (priv->line_control & CONTROL_RESET)
		priv->line_control &= ~CONTROL_RESET;

	if (priv->cmd_ctrl) {
		priv->cmd_count++;
800
		dbg("%s - line control command being issued", __func__);
L
Linus Torvalds 已提交
801 802 803 804 805 806 807 808
		spin_unlock_irqrestore(&priv->lock, flags);
		goto send;
	} else
		spin_unlock_irqrestore(&priv->lock, flags);

	count = cypress_buf_get(priv->buf, &port->interrupt_out_buffer[offset],
				port->interrupt_out_size-offset);

A
Alan Cox 已提交
809
	if (count == 0)
L
Linus Torvalds 已提交
810 811
		return;

812 813 814 815 816 817 818
	switch (priv->pkt_fmt) {
	default:
	case packet_format_1:
		port->interrupt_out_buffer[1] = count;
		break;
	case packet_format_2:
		port->interrupt_out_buffer[0] |= count;
L
Linus Torvalds 已提交
819 820
	}

821
	dbg("%s - count is %d", __func__, count);
L
Linus Torvalds 已提交
822 823 824 825 826 827 828 829 830

send:
	spin_lock_irqsave(&priv->lock, flags);
	priv->write_urb_in_use = 1;
	spin_unlock_irqrestore(&priv->lock, flags);

	if (priv->cmd_ctrl)
		actual_size = 1;
	else
831 832 833
		actual_size = count +
			      (priv->pkt_fmt == packet_format_1 ? 2 : 1);

A
Alan Cox 已提交
834 835 836
	usb_serial_debug_data(debug, &port->dev, __func__,
		port->interrupt_out_size,
		port->interrupt_out_urb->transfer_buffer);
L
Linus Torvalds 已提交
837

838 839 840 841
	usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
		usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
		port->interrupt_out_buffer, port->interrupt_out_size,
		cypress_write_int_callback, port, priv->write_urb_interval);
A
Alan Cox 已提交
842
	result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
L
Linus Torvalds 已提交
843
	if (result) {
A
Alan Cox 已提交
844 845 846
		dev_err(&port->dev,
				"%s - failed submitting write urb, error %d\n",
							__func__, result);
L
Linus Torvalds 已提交
847
		priv->write_urb_in_use = 0;
848
		cypress_set_dead(port);
L
Linus Torvalds 已提交
849 850 851
	}

	spin_lock_irqsave(&priv->lock, flags);
A
Alan Cox 已提交
852
	if (priv->cmd_ctrl)
L
Linus Torvalds 已提交
853
		priv->cmd_ctrl = 0;
A
Alan Cox 已提交
854 855 856

	/* do not count the line control and size bytes */
	priv->bytes_out += count;
L
Linus Torvalds 已提交
857 858
	spin_unlock_irqrestore(&priv->lock, flags);

859
	usb_serial_port_softint(port);
L
Linus Torvalds 已提交
860 861 862 863
} /* cypress_send */


/* returns how much space is available in the soft buffer */
A
Alan Cox 已提交
864
static int cypress_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
865
{
A
Alan Cox 已提交
866
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
867 868 869 870
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int room = 0;
	unsigned long flags;

871
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
872 873 874 875 876

	spin_lock_irqsave(&priv->lock, flags);
	room = cypress_buf_space_avail(priv->buf);
	spin_unlock_irqrestore(&priv->lock, flags);

877
	dbg("%s - returns %d", __func__, room);
L
Linus Torvalds 已提交
878 879 880 881
	return room;
}


A
Alan Cox 已提交
882
static int cypress_tiocmget(struct tty_struct *tty, struct file *file)
L
Linus Torvalds 已提交
883
{
A
Alan Cox 已提交
884
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
885 886 887 888
	struct cypress_private *priv = usb_get_serial_port_data(port);
	__u8 status, control;
	unsigned int result = 0;
	unsigned long flags;
A
Alan Cox 已提交
889

890
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
891 892 893 894 895 896 897 898 899 900 901 902 903

	spin_lock_irqsave(&priv->lock, flags);
	control = priv->line_control;
	status = priv->current_status;
	spin_unlock_irqrestore(&priv->lock, flags);

	result = ((control & CONTROL_DTR)        ? TIOCM_DTR : 0)
		| ((control & CONTROL_RTS)       ? TIOCM_RTS : 0)
		| ((status & UART_CTS)        ? TIOCM_CTS : 0)
		| ((status & UART_DSR)        ? TIOCM_DSR : 0)
		| ((status & UART_RI)         ? TIOCM_RI  : 0)
		| ((status & UART_CD)         ? TIOCM_CD  : 0);

904
	dbg("%s - result = %x", __func__, result);
L
Linus Torvalds 已提交
905 906 907 908 909

	return result;
}


A
Alan Cox 已提交
910
static int cypress_tiocmset(struct tty_struct *tty, struct file *file,
L
Linus Torvalds 已提交
911 912
			       unsigned int set, unsigned int clear)
{
A
Alan Cox 已提交
913
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
914 915
	struct cypress_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
A
Alan Cox 已提交
916

917
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
918 919 920 921 922 923 924 925 926 927

	spin_lock_irqsave(&priv->lock, flags);
	if (set & TIOCM_RTS)
		priv->line_control |= CONTROL_RTS;
	if (set & TIOCM_DTR)
		priv->line_control |= CONTROL_DTR;
	if (clear & TIOCM_RTS)
		priv->line_control &= ~CONTROL_RTS;
	if (clear & TIOCM_DTR)
		priv->line_control &= ~CONTROL_DTR;
A
Alan Cox 已提交
928
	priv->cmd_ctrl = 1;
L
Linus Torvalds 已提交
929 930
	spin_unlock_irqrestore(&priv->lock, flags);

A
Alan Cox 已提交
931
	return cypress_write(tty, port, NULL, 0);
L
Linus Torvalds 已提交
932 933 934
}


A
Alan Cox 已提交
935
static int cypress_ioctl(struct tty_struct *tty, struct file *file,
A
Alan Cox 已提交
936
					unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
937
{
A
Alan Cox 已提交
938
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
939 940
	struct cypress_private *priv = usb_get_serial_port_data(port);

941
	dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
L
Linus Torvalds 已提交
942 943

	switch (cmd) {
A
Alan Cox 已提交
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
	/* This code comes from drivers/char/serial.c and ftdi_sio.c */
	case TIOCMIWAIT:
		while (priv != NULL) {
			interruptible_sleep_on(&priv->delta_msr_wait);
			/* see if a signal did it */
			if (signal_pending(current))
				return -ERESTARTSYS;
			else {
				char diff = priv->diff_status;
				if (diff == 0)
					return -EIO; /* no change => error */

				/* consume all events */
				priv->diff_status = 0;

				/* return 0 if caller wanted to know about
				   these bits */
				if (((arg & TIOCM_RNG) && (diff & UART_RI)) ||
				    ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
				    ((arg & TIOCM_CD) && (diff & UART_CD)) ||
				    ((arg & TIOCM_CTS) && (diff & UART_CTS)))
					return 0;
				/* otherwise caller can't care less about what
				 * happened, and so we continue to wait for
				 * more events.
				 */
L
Linus Torvalds 已提交
970
			}
A
Alan Cox 已提交
971 972 973 974
		}
		return 0;
	default:
		break;
L
Linus Torvalds 已提交
975
	}
976
	dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd);
L
Linus Torvalds 已提交
977 978 979 980
	return -ENOIOCTLCMD;
} /* cypress_ioctl */


A
Alan Cox 已提交
981 982
static void cypress_set_termios(struct tty_struct *tty,
	struct usb_serial_port *port, struct ktermios *old_termios)
L
Linus Torvalds 已提交
983 984 985
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int data_bits, stop_bits, parity_type, parity_enable;
A
Alan Cox 已提交
986
	unsigned cflag, iflag;
L
Linus Torvalds 已提交
987 988
	unsigned long flags;
	__u8 oldlines;
989
	int linechange = 0;
990

991
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
992 993

	spin_lock_irqsave(&priv->lock, flags);
A
Alan Cox 已提交
994 995
	/* We can't clean this one up as we don't know the device type
	   early enough */
L
Linus Torvalds 已提交
996 997 998
	if (!priv->termios_initialized) {
		if (priv->chiptype == CT_EARTHMATE) {
			*(tty->termios) = tty_std_termios;
999 1000
			tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
				CLOCAL;
A
Alan Cox 已提交
1001 1002
			tty->termios->c_ispeed = 4800;
			tty->termios->c_ospeed = 4800;
L
Linus Torvalds 已提交
1003 1004
		} else if (priv->chiptype == CT_CYPHIDCOM) {
			*(tty->termios) = tty_std_termios;
1005 1006
			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
				CLOCAL;
A
Alan Cox 已提交
1007 1008
			tty->termios->c_ispeed = 9600;
			tty->termios->c_ospeed = 9600;
1009 1010 1011 1012
		} else if (priv->chiptype == CT_CA42V2) {
			*(tty->termios) = tty_std_termios;
			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
				CLOCAL;
A
Alan Cox 已提交
1013 1014
			tty->termios->c_ispeed = 9600;
			tty->termios->c_ospeed = 9600;
L
Linus Torvalds 已提交
1015 1016 1017 1018 1019
		}
		priv->termios_initialized = 1;
	}
	spin_unlock_irqrestore(&priv->lock, flags);

A
Alan Cox 已提交
1020 1021 1022
	/* Unsupported features need clearing */
	tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS);

L
Linus Torvalds 已提交
1023 1024 1025 1026 1027
	cflag = tty->termios->c_cflag;
	iflag = tty->termios->c_iflag;

	/* check if there are new settings */
	if (old_termios) {
A
Alan Cox 已提交
1028 1029 1030 1031
		spin_lock_irqsave(&priv->lock, flags);
		priv->tmp_termios = *(tty->termios);
		spin_unlock_irqrestore(&priv->lock, flags);
	}
L
Linus Torvalds 已提交
1032 1033 1034 1035

	/* set number of data bits, parity, stop bits */
	/* when parity is disabled the parity type bit is ignored */

1036 1037 1038
	/* 1 means 2 stop bits, 0 means 1 stop bit */
	stop_bits = cflag & CSTOPB ? 1 : 0;

L
Linus Torvalds 已提交
1039 1040
	if (cflag & PARENB) {
		parity_enable = 1;
1041 1042
		/* 1 means odd parity, 0 means even parity */
		parity_type = cflag & PARODD ? 1 : 0;
L
Linus Torvalds 已提交
1043 1044 1045
	} else
		parity_enable = parity_type = 0;

1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
	switch (cflag & CSIZE) {
	case CS5:
		data_bits = 0;
		break;
	case CS6:
		data_bits = 1;
		break;
	case CS7:
		data_bits = 2;
		break;
	case CS8:
L
Linus Torvalds 已提交
1057
		data_bits = 3;
1058 1059
		break;
	default:
1060 1061
		dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n",
			__func__);
1062 1063
		data_bits = 3;
	}
L
Linus Torvalds 已提交
1064 1065 1066 1067
	spin_lock_irqsave(&priv->lock, flags);
	oldlines = priv->line_control;
	if ((cflag & CBAUD) == B0) {
		/* drop dtr and rts */
1068
		dbg("%s - dropping the lines, baud rate 0bps", __func__);
L
Linus Torvalds 已提交
1069
		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
A
Alan Cox 已提交
1070
	} else
1071
		priv->line_control = (CONTROL_DTR | CONTROL_RTS);
L
Linus Torvalds 已提交
1072 1073
	spin_unlock_irqrestore(&priv->lock, flags);

1074
	dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, "
1075
			"%d data_bits (+5)", __func__, stop_bits,
1076 1077
			parity_enable, parity_type, data_bits);

A
Alan Cox 已提交
1078 1079 1080 1081
	cypress_serial_control(tty, port, tty_get_baud_rate(tty),
			data_bits, stop_bits,
			parity_enable, parity_type,
			0, CYPRESS_SET_CONFIG);
L
Linus Torvalds 已提交
1082

1083 1084 1085
	/* we perform a CYPRESS_GET_CONFIG so that the current settings are
	 * filled into the private structure this should confirm that all is
	 * working if it returns what we just set */
A
Alan Cox 已提交
1086
	cypress_serial_control(tty, port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
L
Linus Torvalds 已提交
1087

1088 1089
	/* Here we can define custom tty settings for devices; the main tty
	 * termios flag base comes from empeg.c */
L
Linus Torvalds 已提交
1090

1091
	spin_lock_irqsave(&priv->lock, flags);
A
Alan Cox 已提交
1092
	if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) {
1093 1094
		dbg("Using custom termios settings for a baud rate of "
				"4800bps.");
L
Linus Torvalds 已提交
1095 1096 1097
		/* define custom termios settings for NMEA protocol */

		tty->termios->c_iflag /* input modes - */
1098 1099 1100 1101 1102 1103 1104 1105 1106
			&= ~(IGNBRK  /* disable ignore break */
			| BRKINT     /* disable break causes interrupt */
			| PARMRK     /* disable mark parity errors */
			| ISTRIP     /* disable clear high bit of input char */
			| INLCR      /* disable translate NL to CR */
			| IGNCR      /* disable ignore CR */
			| ICRNL      /* disable translate CR to NL */
			| IXON);     /* disable enable XON/XOFF flow control */

L
Linus Torvalds 已提交
1107
		tty->termios->c_oflag /* output modes */
1108
			&= ~OPOST;    /* disable postprocess output char */
L
Linus Torvalds 已提交
1109

1110 1111 1112 1113 1114 1115 1116 1117
		tty->termios->c_lflag /* line discipline modes */
			&= ~(ECHO     /* disable echo input characters */
			| ECHONL      /* disable echo new line */
			| ICANON      /* disable erase, kill, werase, and rprnt
					 special characters */
			| ISIG        /* disable interrupt, quit, and suspend
					 special characters */
			| IEXTEN);    /* disable non-POSIX special characters */
1118
	} /* CT_CYPHIDCOM: Application should handle this for device */
L
Linus Torvalds 已提交
1119 1120 1121 1122 1123

	linechange = (priv->line_control != oldlines);
	spin_unlock_irqrestore(&priv->lock, flags);

	/* if necessary, set lines */
1124
	if (linechange) {
L
Linus Torvalds 已提交
1125
		priv->cmd_ctrl = 1;
A
Alan Cox 已提交
1126
		cypress_write(tty, port, NULL, 0);
L
Linus Torvalds 已提交
1127 1128 1129
	}
} /* cypress_set_termios */

1130

L
Linus Torvalds 已提交
1131
/* returns amount of data still left in soft buffer */
A
Alan Cox 已提交
1132
static int cypress_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1133
{
A
Alan Cox 已提交
1134
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1135 1136 1137 1138
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int chars = 0;
	unsigned long flags;

1139
	dbg("%s - port %d", __func__, port->number);
A
Alan Cox 已提交
1140

L
Linus Torvalds 已提交
1141 1142 1143 1144
	spin_lock_irqsave(&priv->lock, flags);
	chars = cypress_buf_data_avail(priv->buf);
	spin_unlock_irqrestore(&priv->lock, flags);

1145
	dbg("%s - returns %d", __func__, chars);
L
Linus Torvalds 已提交
1146 1147 1148 1149
	return chars;
}


A
Alan Cox 已提交
1150
static void cypress_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
1151
{
A
Alan Cox 已提交
1152
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1153 1154
	struct cypress_private *priv = usb_get_serial_port_data(port);

1155
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
1156

1157
	spin_lock_irq(&priv->lock);
L
Linus Torvalds 已提交
1158
	priv->rx_flags = THROTTLED;
1159
	spin_unlock_irq(&priv->lock);
L
Linus Torvalds 已提交
1160 1161 1162
}


A
Alan Cox 已提交
1163
static void cypress_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
1164
{
A
Alan Cox 已提交
1165
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1166 1167 1168
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int actually_throttled, result;

1169
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
1170

1171
	spin_lock_irq(&priv->lock);
L
Linus Torvalds 已提交
1172 1173
	actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
	priv->rx_flags = 0;
1174
	spin_unlock_irq(&priv->lock);
L
Linus Torvalds 已提交
1175

1176 1177 1178
	if (!priv->comm_is_ok)
		return;

L
Linus Torvalds 已提交
1179 1180 1181
	if (actually_throttled) {
		port->interrupt_in_urb->dev = port->serial->dev;

1182
		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
1183
		if (result) {
1184
			dev_err(&port->dev, "%s - failed submitting read urb, "
1185
					"error %d\n", __func__, result);
1186 1187
			cypress_set_dead(port);
		}
L
Linus Torvalds 已提交
1188 1189 1190 1191
	}
}


1192
static void cypress_read_int_callback(struct urb *urb)
L
Linus Torvalds 已提交
1193
{
1194
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
1195 1196 1197 1198
	struct cypress_private *priv = usb_get_serial_port_data(port);
	struct tty_struct *tty;
	unsigned char *data = urb->transfer_buffer;
	unsigned long flags;
1199
	char tty_flag = TTY_NORMAL;
L
Linus Torvalds 已提交
1200 1201 1202 1203
	int havedata = 0;
	int bytes = 0;
	int result;
	int i = 0;
1204
	int status = urb->status;
L
Linus Torvalds 已提交
1205

1206
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
1207

1208
	switch (status) {
1209 1210 1211 1212 1213 1214 1215 1216
	case 0: /* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* precursor to disconnect so just go away */
		return;
	case -EPIPE:
1217 1218
		/* Can't call usb_clear_halt while in_interrupt */
		/* FALLS THROUGH */
1219 1220
	default:
		/* something ugly is going on... */
A
Alan Cox 已提交
1221 1222 1223
		dev_err(&urb->dev->dev,
			"%s - unexpected nonzero read status received: %d\n",
							__func__, status);
1224
		cypress_set_dead(port);
L
Linus Torvalds 已提交
1225 1226 1227 1228 1229
		return;
	}

	spin_lock_irqsave(&priv->lock, flags);
	if (priv->rx_flags & THROTTLED) {
1230
		dbg("%s - now throttling", __func__);
L
Linus Torvalds 已提交
1231 1232 1233 1234 1235 1236
		priv->rx_flags |= ACTUALLY_THROTTLED;
		spin_unlock_irqrestore(&priv->lock, flags);
		return;
	}
	spin_unlock_irqrestore(&priv->lock, flags);

A
Alan Cox 已提交
1237
	tty = tty_port_tty_get(&port->port);
L
Linus Torvalds 已提交
1238
	if (!tty) {
1239
		dbg("%s - bad tty pointer - exiting", __func__);
L
Linus Torvalds 已提交
1240 1241 1242 1243
		return;
	}

	spin_lock_irqsave(&priv->lock, flags);
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
	result = urb->actual_length;
	switch (priv->pkt_fmt) {
	default:
	case packet_format_1:
		/* This is for the CY7C64013... */
		priv->current_status = data[0] & 0xF8;
		bytes = data[1] + 2;
		i = 2;
		if (bytes > 2)
			havedata = 1;
		break;
	case packet_format_2:
		/* This is for the CY7C63743... */
		priv->current_status = data[0] & 0xF8;
		bytes = (data[0] & 0x07) + 1;
		i = 1;
		if (bytes > 1)
			havedata = 1;
		break;
L
Linus Torvalds 已提交
1263 1264
	}
	spin_unlock_irqrestore(&priv->lock, flags);
1265 1266 1267 1268 1269
	if (result < bytes) {
		dbg("%s - wrong packet size - received %d bytes but packet "
		    "said %d bytes", __func__, result, bytes);
		goto continue_read;
	}
L
Linus Torvalds 已提交
1270

A
Alan Cox 已提交
1271 1272
	usb_serial_debug_data(debug, &port->dev, __func__,
						urb->actual_length, data);
L
Linus Torvalds 已提交
1273 1274 1275

	spin_lock_irqsave(&priv->lock, flags);
	/* check to see if status has changed */
1276 1277 1278 1279 1280
	if (priv->current_status != priv->prev_status) {
		priv->diff_status |= priv->current_status ^
			priv->prev_status;
		wake_up_interruptible(&priv->delta_msr_wait);
		priv->prev_status = priv->current_status;
L
Linus Torvalds 已提交
1281
	}
1282
	spin_unlock_irqrestore(&priv->lock, flags);
L
Linus Torvalds 已提交
1283

1284 1285 1286 1287
	/* hangup, as defined in acm.c... this might be a bad place for it
	 * though */
	if (tty && !(tty->termios->c_cflag & CLOCAL) &&
			!(priv->current_status & UART_CD)) {
1288
		dbg("%s - calling hangup", __func__);
L
Linus Torvalds 已提交
1289 1290 1291 1292
		tty_hangup(tty);
		goto continue_read;
	}

1293 1294 1295 1296
	/* There is one error bit... I'm assuming it is a parity error
	 * indicator as the generic firmware will set this bit to 1 if a
	 * parity error occurs.
	 * I can not find reference to any other error events. */
L
Linus Torvalds 已提交
1297 1298 1299 1300
	spin_lock_irqsave(&priv->lock, flags);
	if (priv->current_status & CYP_ERROR) {
		spin_unlock_irqrestore(&priv->lock, flags);
		tty_flag = TTY_PARITY;
1301
		dbg("%s - Parity Error detected", __func__);
L
Linus Torvalds 已提交
1302 1303 1304 1305 1306
	} else
		spin_unlock_irqrestore(&priv->lock, flags);

	/* process read if there is data other than line status */
	if (tty && (bytes > i)) {
A
Alan Cox 已提交
1307
		bytes = tty_buffer_request_room(tty, bytes);
L
Linus Torvalds 已提交
1308
		for (; i < bytes ; ++i) {
1309 1310
			dbg("pushing byte number %d - %d - %c", i, data[i],
					data[i]);
L
Linus Torvalds 已提交
1311 1312
			tty_insert_flip_char(tty, data[i], tty_flag);
		}
A
Alan Cox 已提交
1313
		tty_flip_buffer_push(tty);
L
Linus Torvalds 已提交
1314 1315 1316
	}

	spin_lock_irqsave(&priv->lock, flags);
1317 1318
	/* control and status byte(s) are also counted */
	priv->bytes_in += bytes;
L
Linus Torvalds 已提交
1319 1320 1321
	spin_unlock_irqrestore(&priv->lock, flags);

continue_read:
A
Alan Cox 已提交
1322
	tty_kref_put(tty);
1323 1324

	/* Continue trying to always read... unless the port has closed. */
L
Linus Torvalds 已提交
1325

A
Alan Cox 已提交
1326
	if (port->port.count > 0 && priv->comm_is_ok) {
1327 1328 1329 1330 1331
		usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
				usb_rcvintpipe(port->serial->dev,
					port->interrupt_in_endpointAddress),
				port->interrupt_in_urb->transfer_buffer,
				port->interrupt_in_urb->transfer_buffer_length,
A
Alan Cox 已提交
1332 1333
				cypress_read_int_callback, port,
				priv->read_urb_interval);
1334
		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
1335
		if (result) {
1336
			dev_err(&urb->dev->dev, "%s - failed resubmitting "
1337
					"read urb, error %d\n", __func__,
1338
					result);
1339 1340
			cypress_set_dead(port);
		}
L
Linus Torvalds 已提交
1341
	}
1342

L
Linus Torvalds 已提交
1343 1344 1345 1346
	return;
} /* cypress_read_int_callback */


1347
static void cypress_write_int_callback(struct urb *urb)
L
Linus Torvalds 已提交
1348
{
1349
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
1350 1351
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int result;
1352
	int status = urb->status;
L
Linus Torvalds 已提交
1353

1354
	dbg("%s - port %d", __func__, port->number);
1355 1356

	switch (status) {
A
Alan Cox 已提交
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
	case 0:
		/* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* this urb is terminated, clean up */
		dbg("%s - urb shutting down with status: %d",
						__func__, status);
		priv->write_urb_in_use = 0;
		return;
	case -EPIPE: /* no break needed; clear halt and resubmit */
		if (!priv->comm_is_ok)
L
Linus Torvalds 已提交
1370
			break;
A
Alan Cox 已提交
1371 1372 1373 1374 1375 1376 1377 1378
		usb_clear_halt(port->serial->dev, 0x02);
		/* error in the urb, so we have to resubmit it */
		dbg("%s - nonzero write bulk status received: %d",
			__func__, status);
		port->interrupt_out_urb->transfer_buffer_length = 1;
		port->interrupt_out_urb->dev = port->serial->dev;
		result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
		if (!result)
L
Linus Torvalds 已提交
1379
			return;
A
Alan Cox 已提交
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
		dev_err(&urb->dev->dev,
			"%s - failed resubmitting write urb, error %d\n",
							__func__, result);
		cypress_set_dead(port);
		break;
	default:
		dev_err(&urb->dev->dev,
			 "%s - unexpected nonzero write status received: %d\n",
							__func__, status);
		cypress_set_dead(port);
		break;
L
Linus Torvalds 已提交
1391 1392
	}
	priv->write_urb_in_use = 0;
A
Alan Cox 已提交
1393

L
Linus Torvalds 已提交
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
	/* send any buffered data */
	cypress_send(port);
}


/*****************************************************************************
 * Write buffer functions - buffering code from pl2303 used
 *****************************************************************************/

/*
 * cypress_buf_alloc
 *
 * Allocate a circular buffer and all associated memory.
 */

static struct cypress_buf *cypress_buf_alloc(unsigned int size)
{

	struct cypress_buf *cb;


	if (size == 0)
		return NULL;

1418
	cb = kmalloc(sizeof(struct cypress_buf), GFP_KERNEL);
L
Linus Torvalds 已提交
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
	if (cb == NULL)
		return NULL;

	cb->buf_buf = kmalloc(size, GFP_KERNEL);
	if (cb->buf_buf == NULL) {
		kfree(cb);
		return NULL;
	}

	cb->buf_size = size;
	cb->buf_get = cb->buf_put = cb->buf_buf;

	return cb;

}


/*
 * cypress_buf_free
 *
 * Free the buffer and all associated memory.
 */

static void cypress_buf_free(struct cypress_buf *cb)
{
1444 1445
	if (cb) {
		kfree(cb->buf_buf);
L
Linus Torvalds 已提交
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
		kfree(cb);
	}
}


/*
 * cypress_buf_clear
 *
 * Clear out all data in the circular buffer.
 */

static void cypress_buf_clear(struct cypress_buf *cb)
{
	if (cb != NULL)
		cb->buf_get = cb->buf_put;
		/* equivalent to a get of all data available */
}


/*
 * cypress_buf_data_avail
 *
 * Return the number of bytes of data available in the circular
 * buffer.
 */

static unsigned int cypress_buf_data_avail(struct cypress_buf *cb)
{
	if (cb != NULL)
A
Alan Cox 已提交
1475 1476
		return (cb->buf_size + cb->buf_put - cb->buf_get)
							% cb->buf_size;
L
Linus Torvalds 已提交
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
	else
		return 0;
}


/*
 * cypress_buf_space_avail
 *
 * Return the number of bytes of space available in the circular
 * buffer.
 */

static unsigned int cypress_buf_space_avail(struct cypress_buf *cb)
{
	if (cb != NULL)
A
Alan Cox 已提交
1492 1493
		return (cb->buf_size + cb->buf_get - cb->buf_put - 1)
							% cb->buf_size;
L
Linus Torvalds 已提交
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
	else
		return 0;
}


/*
 * cypress_buf_put
 *
 * Copy data data from a user buffer and put it into the circular buffer.
 * Restrict to the amount of space available.
 *
 * Return the number of bytes copied.
 */

static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf,
	unsigned int count)
{

	unsigned int len;


	if (cb == NULL)
		return 0;

	len  = cypress_buf_space_avail(cb);
	if (count > len)
		count = len;

	if (count == 0)
		return 0;

	len = cb->buf_buf + cb->buf_size - cb->buf_put;
	if (count > len) {
		memcpy(cb->buf_put, buf, len);
		memcpy(cb->buf_buf, buf+len, count - len);
		cb->buf_put = cb->buf_buf + count - len;
	} else {
		memcpy(cb->buf_put, buf, count);
		if (count < len)
			cb->buf_put += count;
		else /* count == len */
			cb->buf_put = cb->buf_buf;
	}

	return count;

}


/*
 * cypress_buf_get
 *
 * Get data from the circular buffer and copy to the given buffer.
 * Restrict to the amount of data available.
 *
 * Return the number of bytes copied.
 */

static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf,
	unsigned int count)
{

	unsigned int len;


	if (cb == NULL)
		return 0;

	len = cypress_buf_data_avail(cb);
	if (count > len)
		count = len;

	if (count == 0)
		return 0;

	len = cb->buf_buf + cb->buf_size - cb->buf_get;
	if (count > len) {
		memcpy(buf, cb->buf_get, len);
		memcpy(buf+len, cb->buf_buf, count - len);
		cb->buf_get = cb->buf_buf + count - len;
	} else {
		memcpy(buf, cb->buf_get, count);
		if (count < len)
			cb->buf_get += count;
		else /* count == len */
			cb->buf_get = cb->buf_buf;
	}

	return count;

}

/*****************************************************************************
 * Module functions
 *****************************************************************************/

static int __init cypress_init(void)
{
	int retval;
A
Alan Cox 已提交
1593

1594
	dbg("%s", __func__);
A
Alan Cox 已提交
1595

L
Linus Torvalds 已提交
1596 1597 1598 1599 1600 1601
	retval = usb_serial_register(&cypress_earthmate_device);
	if (retval)
		goto failed_em_register;
	retval = usb_serial_register(&cypress_hidcom_device);
	if (retval)
		goto failed_hidcom_register;
1602 1603 1604
	retval = usb_serial_register(&cypress_ca42v2_device);
	if (retval)
		goto failed_ca42v2_register;
L
Linus Torvalds 已提交
1605 1606 1607 1608
	retval = usb_register(&cypress_driver);
	if (retval)
		goto failed_usb_register;

1609 1610
	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
	       DRIVER_DESC "\n");
L
Linus Torvalds 已提交
1611
	return 0;
1612

L
Linus Torvalds 已提交
1613
failed_usb_register:
1614
	usb_serial_deregister(&cypress_ca42v2_device);
1615
failed_ca42v2_register:
L
Linus Torvalds 已提交
1616
	usb_serial_deregister(&cypress_hidcom_device);
1617
failed_hidcom_register:
L
Linus Torvalds 已提交
1618
	usb_serial_deregister(&cypress_earthmate_device);
1619
failed_em_register:
L
Linus Torvalds 已提交
1620 1621 1622 1623
	return retval;
}


A
Alan Cox 已提交
1624
static void __exit cypress_exit(void)
L
Linus Torvalds 已提交
1625
{
1626
	dbg("%s", __func__);
L
Linus Torvalds 已提交
1627

A
Alan Cox 已提交
1628 1629 1630 1631
	usb_deregister(&cypress_driver);
	usb_serial_deregister(&cypress_earthmate_device);
	usb_serial_deregister(&cypress_hidcom_device);
	usb_serial_deregister(&cypress_ca42v2_device);
L
Linus Torvalds 已提交
1632 1633 1634 1635 1636 1637
}


module_init(cypress_init);
module_exit(cypress_exit);

A
Alan Cox 已提交
1638 1639 1640
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
L
Linus Torvalds 已提交
1641 1642 1643 1644 1645 1646
MODULE_LICENSE("GPL");

module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
module_param(stats, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(stats, "Enable statistics or not");
1647 1648
module_param(interval, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(interval, "Overrides interrupt interval");