cypress_m8.c 41.7 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
#include <linux/serial.h>
67
#include <linux/kfifo.h>
L
Linus Torvalds 已提交
68
#include <linux/delay.h>
A
Alan Cox 已提交
69
#include <linux/uaccess.h>
70
#include <asm/unaligned.h>
L
Linus Torvalds 已提交
71 72 73 74

#include "cypress_m8.h"


75
static int debug;
L
Linus Torvalds 已提交
76
static int stats;
77
static int interval;
78
static int unstable_bauds;
L
Linus Torvalds 已提交
79 80 81 82

/*
 * Version Information
 */
83
#define DRIVER_VERSION "v1.10"
L
Linus Torvalds 已提交
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

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

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

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

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

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

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

126 127 128 129 130
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 已提交
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 */
138
	struct kfifo write_fifo;	   /* write fifo */
L
Linus Torvalds 已提交
139
	int write_urb_in_use;		   /* write urb in use indicator */
140 141
	int write_urb_interval;            /* interval to use for write urb */
	int read_urb_interval;             /* interval to use for read urb */
142
	int comm_is_ok;                    /* true if communication is (still) ok */
L
Linus Torvalds 已提交
143 144 145 146 147
	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 */
148
	enum packet_format pkt_fmt;	   /* format to use for packet send / receive */
149
	int get_cfg_unsafe;		   /* If true, the CYPRESS_GET_CONFIG is unsafe */
A
Alan Cox 已提交
150 151
	int baud_rate;			   /* stores current baud rate in
					      integer form */
L
Linus Torvalds 已提交
152 153 154
	int isthrottled;		   /* if throttled, discard reads */
	wait_queue_head_t delta_msr_wait;  /* used for TIOCMIWAIT */
	char prev_status, diff_status;	   /* used for TIOCMIWAIT */
D
Daniel Mack 已提交
155
	/* we pass a pointer to this as the argument sent to
A
Alan Cox 已提交
156
	   cypress_set_termios old_termios */
A
Alan Cox 已提交
157
	struct ktermios tmp_termios; 	   /* stores the old termios settings */
L
Linus Torvalds 已提交
158 159 160
};

/* function prototypes for the Cypress USB to serial device */
A
Alan Cox 已提交
161 162 163
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);
164
static void cypress_release(struct usb_serial *serial);
165
static int  cypress_open(struct tty_struct *tty, struct usb_serial_port *port);
166 167
static void cypress_close(struct usb_serial_port *port);
static void cypress_dtr_rts(struct usb_serial_port *port, int on);
A
Alan Cox 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
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 已提交
185

186
static struct usb_serial_driver cypress_earthmate_device = {
187 188
	.driver = {
		.owner =		THIS_MODULE,
189
		.name =			"earthmate",
190
	},
191
	.description =			"DeLorme Earthmate USB",
192
	.usb_driver = 			&cypress_driver,
L
Linus Torvalds 已提交
193 194 195
	.id_table =			id_table_earthmate,
	.num_ports =			1,
	.attach =			cypress_earthmate_startup,
196
	.release =			cypress_release,
L
Linus Torvalds 已提交
197 198
	.open =				cypress_open,
	.close =			cypress_close,
199
	.dtr_rts =			cypress_dtr_rts,
L
Linus Torvalds 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212
	.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,
};

213
static struct usb_serial_driver cypress_hidcom_device = {
214 215
	.driver = {
		.owner =		THIS_MODULE,
216
		.name =			"cyphidcom",
217
	},
218
	.description =			"HID->COM RS232 Adapter",
219
	.usb_driver = 			&cypress_driver,
L
Linus Torvalds 已提交
220 221 222
	.id_table =			id_table_cyphidcomrs232,
	.num_ports =			1,
	.attach =			cypress_hidcom_startup,
223
	.release =			cypress_release,
L
Linus Torvalds 已提交
224 225
	.open =				cypress_open,
	.close =			cypress_close,
226
	.dtr_rts =			cypress_dtr_rts,
L
Linus Torvalds 已提交
227 228 229 230 231 232 233 234 235 236 237 238 239
	.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,
};

240 241 242
static struct usb_serial_driver cypress_ca42v2_device = {
	.driver = {
		.owner =		THIS_MODULE,
A
Alan Cox 已提交
243
		.name =			"nokiaca42v2",
244 245
	},
	.description =			"Nokia CA-42 V2 Adapter",
246
	.usb_driver = 			&cypress_driver,
247 248 249
	.id_table =			id_table_nokiaca42v2,
	.num_ports =			1,
	.attach =			cypress_ca42v2_startup,
250
	.release =			cypress_release,
251 252
	.open =				cypress_open,
	.close =			cypress_close,
253
	.dtr_rts =			cypress_dtr_rts,
254 255 256 257 258 259 260 261 262 263 264 265
	.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 已提交
266 267 268 269 270 271

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


A
Alan Cox 已提交
272
static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
273 274 275 276
{
	struct cypress_private *priv;
	priv = usb_get_serial_port_data(port);

277 278 279
	if (unstable_bauds)
		return new_rate;

280 281 282 283 284 285 286 287 288 289 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
	/*
	 * 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;
}


321
/* This function can either set or retrieve the current serial line settings */
A
Alan Cox 已提交
322
static int cypress_serial_control(struct tty_struct *tty,
A
Alan Cox 已提交
323 324 325
	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 已提交
326
{
327
	int new_baudrate = 0, retval = 0, tries = 0;
L
Linus Torvalds 已提交
328
	struct cypress_private *priv;
329 330
	u8 *feature_buffer;
	const unsigned int feature_len = 5;
L
Linus Torvalds 已提交
331 332
	unsigned long flags;

333
	dbg("%s", __func__);
A
Alan Cox 已提交
334

L
Linus Torvalds 已提交
335 336
	priv = usb_get_serial_port_data(port);

337 338 339
	if (!priv->comm_is_ok)
		return -ENODEV;

340 341 342 343
	feature_buffer = kcalloc(feature_len, sizeof(u8), GFP_KERNEL);
	if (!feature_buffer)
		return -ENOMEM;

A
Alan Cox 已提交
344 345 346
	switch (cypress_request_type) {
	case CYPRESS_SET_CONFIG:
		/* 0 means 'Hang up' so doesn't change the true bit rate */
347 348
		new_baudrate = priv->baud_rate;
		if (baud_rate && baud_rate != priv->baud_rate) {
A
Alan Cox 已提交
349 350
			dbg("%s - baud rate is changing", __func__);
			retval = analyze_baud_rate(port, baud_rate);
351
			if (retval >= 0) {
A
Alan Cox 已提交
352 353 354
				new_baudrate = retval;
				dbg("%s - New baud rate set to %d",
				    __func__, new_baudrate);
L
Linus Torvalds 已提交
355
			}
A
Alan Cox 已提交
356 357 358 359 360
		}
		dbg("%s - baud rate is being sent as %d",
					__func__, new_baudrate);

		/* fill the feature_buffer with new configuration */
361
		put_unaligned_le32(new_baudrate, feature_buffer);
A
Alan Cox 已提交
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
		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,
383
					feature_len, 500);
A
Alan Cox 已提交
384 385 386 387

			if (tries++ >= 3)
				break;

388
		} while (retval != feature_len &&
A
Alan Cox 已提交
389 390
			 retval != -ENODEV);

391
		if (retval != feature_len) {
392 393
			dev_err(&port->dev, "%s - failed sending serial "
				"line settings - %d\n", __func__, retval);
A
Alan Cox 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
			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. */
411 412
			retval = -ENOTTY;
			goto out;
A
Alan Cox 已提交
413 414 415 416 417 418 419 420
		}
		dbg("%s - retreiving serial line settings", __func__);
		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,
421
					feature_len, 500);
A
Alan Cox 已提交
422 423 424

			if (tries++ >= 3)
				break;
425
		} while (retval != feature_len
A
Alan Cox 已提交
426 427
						&& retval != -ENODEV);

428
		if (retval != feature_len) {
429 430
			dev_err(&port->dev, "%s - failed to retrieve serial "
				"line settings - %d\n", __func__, retval);
A
Alan Cox 已提交
431
			cypress_set_dead(port);
432
			goto out;
A
Alan Cox 已提交
433 434 435 436 437
		} 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];
438
			priv->baud_rate = get_unaligned_le32(feature_buffer);
A
Alan Cox 已提交
439 440
			spin_unlock_irqrestore(&priv->lock, flags);
		}
L
Linus Torvalds 已提交
441
	}
442 443 444
	spin_lock_irqsave(&priv->lock, flags);
	++priv->cmd_count;
	spin_unlock_irqrestore(&priv->lock, flags);
445 446
out:
	kfree(feature_buffer);
L
Linus Torvalds 已提交
447 448 449 450
	return retval;
} /* cypress_serial_control */


451 452 453 454 455 456 457 458 459 460 461 462 463
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);

464 465
	dev_err(&port->dev, "cypress_m8 suspending failing port %d - "
		"interval might be too short\n", port->number);
466 467 468
}


L
Linus Torvalds 已提交
469 470 471 472 473
/*****************************************************************************
 * Cypress serial driver functions
 *****************************************************************************/


A
Alan Cox 已提交
474
static int generic_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
475 476
{
	struct cypress_private *priv;
477
	struct usb_serial_port *port = serial->port[0];
L
Linus Torvalds 已提交
478

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

A
Alan Cox 已提交
481
	priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
L
Linus Torvalds 已提交
482 483 484
	if (!priv)
		return -ENOMEM;

485
	priv->comm_is_ok = !0;
L
Linus Torvalds 已提交
486
	spin_lock_init(&priv->lock);
487
	if (kfifo_alloc(&priv->write_fifo, CYPRESS_BUF_SIZE, GFP_KERNEL)) {
L
Linus Torvalds 已提交
488 489 490 491
		kfree(priv);
		return -ENOMEM;
	}
	init_waitqueue_head(&priv->delta_msr_wait);
A
Alan Cox 已提交
492 493 494

	usb_reset_configuration(serial->dev);

L
Linus Torvalds 已提交
495 496 497 498
	priv->cmd_ctrl = 0;
	priv->line_control = 0;
	priv->termios_initialized = 0;
	priv->rx_flags = 0;
499 500 501 502 503 504
	/* 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 已提交
505
	if (port->interrupt_out_size > 9)
506
		priv->pkt_fmt = packet_format_1;
A
Alan Cox 已提交
507
	else
508
		priv->pkt_fmt = packet_format_2;
A
Alan Cox 已提交
509

510 511 512 513
	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 已提交
514
		    __func__, port->number, interval);
515 516 517 518
	} 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 已提交
519 520
		    __func__, port->number,
		    priv->read_urb_interval, priv->write_urb_interval);
521 522
	}
	usb_set_serial_port_data(port, priv);
A
Alan Cox 已提交
523

524 525
	return 0;
}
L
Linus Torvalds 已提交
526 527


A
Alan Cox 已提交
528
static int cypress_earthmate_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
529 530
{
	struct cypress_private *priv;
531
	struct usb_serial_port *port = serial->port[0];
L
Linus Torvalds 已提交
532

533
	dbg("%s", __func__);
L
Linus Torvalds 已提交
534 535

	if (generic_startup(serial)) {
536
		dbg("%s - Failed setting up port %d", __func__,
537
				port->number);
L
Linus Torvalds 已提交
538 539 540
		return 1;
	}

541
	priv = usb_get_serial_port_data(port);
L
Linus Torvalds 已提交
542
	priv->chiptype = CT_EARTHMATE;
543 544 545
	/* All Earthmate devices use the separated-count packet
	   format!  Idiotic. */
	priv->pkt_fmt = packet_format_1;
A
Alan Cox 已提交
546 547
	if (serial->dev->descriptor.idProduct !=
				cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) {
548 549 550 551 552 553 554 555
		/* 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;
	}
556 557

	return 0;
L
Linus Torvalds 已提交
558 559 560
} /* cypress_earthmate_startup */


A
Alan Cox 已提交
561
static int cypress_hidcom_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
562 563 564
{
	struct cypress_private *priv;

565
	dbg("%s", __func__);
L
Linus Torvalds 已提交
566 567

	if (generic_startup(serial)) {
568
		dbg("%s - Failed setting up port %d", __func__,
569
				serial->port[0]->number);
L
Linus Torvalds 已提交
570 571 572 573 574
		return 1;
	}

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

576
	return 0;
L
Linus Torvalds 已提交
577 578 579
} /* cypress_hidcom_startup */


A
Alan Cox 已提交
580
static int cypress_ca42v2_startup(struct usb_serial *serial)
581 582 583
{
	struct cypress_private *priv;

584
	dbg("%s", __func__);
585 586

	if (generic_startup(serial)) {
587
		dbg("%s - Failed setting up port %d", __func__,
588 589 590 591 592 593 594 595 596 597 598
				serial->port[0]->number);
		return 1;
	}

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

	return 0;
} /* cypress_ca42v2_startup */


599
static void cypress_release(struct usb_serial *serial)
L
Linus Torvalds 已提交
600 601 602
{
	struct cypress_private *priv;

A
Alan Cox 已提交
603
	dbg("%s - port %d", __func__, serial->port[0]->number);
L
Linus Torvalds 已提交
604 605 606 607 608 609

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

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

	if (priv) {
610
		kfifo_free(&priv->write_fifo);
L
Linus Torvalds 已提交
611 612 613 614 615
		kfree(priv);
	}
}


616
static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
L
Linus Torvalds 已提交
617 618 619 620 621 622
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
	struct usb_serial *serial = port->serial;
	unsigned long flags;
	int result = 0;

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

625 626 627
	if (!priv->comm_is_ok)
		return -EIO;

L
Linus Torvalds 已提交
628 629 630 631 632 633 634 635 636 637 638 639
	/* 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);

640
	/* Set termios */
A
Alan Cox 已提交
641
	cypress_send(port);
L
Linus Torvalds 已提交
642

A
Alan Cox 已提交
643 644
	if (tty)
		cypress_set_termios(tty, port, &priv->tmp_termios);
L
Linus Torvalds 已提交
645 646

	/* setup the port and start reading from the device */
A
Alan Cox 已提交
647
	if (!port->interrupt_in_urb) {
648 649
		dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n",
			__func__);
A
Alan Cox 已提交
650
		return -1;
L
Linus Torvalds 已提交
651 652 653 654
	}

	usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
		usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
A
Alan Cox 已提交
655 656
		port->interrupt_in_urb->transfer_buffer,
		port->interrupt_in_urb->transfer_buffer_length,
657
		cypress_read_int_callback, port, priv->read_urb_interval);
L
Linus Torvalds 已提交
658 659
	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);

A
Alan Cox 已提交
660 661 662 663
	if (result) {
		dev_err(&port->dev,
			"%s - failed submitting read urb, error %d\n",
							__func__, result);
664
		cypress_set_dead(port);
L
Linus Torvalds 已提交
665
	}
666
	port->port.drain_delay = 256;
L
Linus Torvalds 已提交
667 668 669
	return result;
} /* cypress_open */

670 671 672 673 674 675 676 677 678 679 680 681 682
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 */
	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 已提交
683

684
static void cypress_close(struct usb_serial_port *port)
L
Linus Torvalds 已提交
685 686
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
687
	unsigned long flags;
L
Linus Torvalds 已提交
688

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

691 692 693 694 695 696
	/* 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;
	}
697 698 699 700
	spin_lock_irqsave(&priv->lock, flags);
	kfifo_reset_out(&priv->write_fifo);
	spin_unlock_irqrestore(&priv->lock, flags);

701
	dbg("%s - stopping urbs", __func__);
A
Alan Cox 已提交
702 703
	usb_kill_urb(port->interrupt_in_urb);
	usb_kill_urb(port->interrupt_out_urb);
L
Linus Torvalds 已提交
704 705

	if (stats)
A
Alan Cox 已提交
706 707
		dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
			priv->bytes_in, priv->bytes_out, priv->cmd_count);
708
	mutex_unlock(&port->serial->disc_mutex);
L
Linus Torvalds 已提交
709 710 711
} /* cypress_close */


A
Alan Cox 已提交
712 713
static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
					const unsigned char *buf, int count)
L
Linus Torvalds 已提交
714 715
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
A
Alan Cox 已提交
716

717
	dbg("%s - port %d, %d bytes", __func__, port->number, count);
L
Linus Torvalds 已提交
718 719 720 721 722 723 724 725

	/* 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 已提交
726

L
Linus Torvalds 已提交
727 728
	if (!count)
		return count;
A
Alan Cox 已提交
729

730
	count = kfifo_in_locked(&priv->write_fifo, buf, count, &priv->lock);
L
Linus Torvalds 已提交
731 732 733 734 735 736 737 738 739 740 741 742 743

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 已提交
744

745 746 747
	if (!priv->comm_is_ok)
		return;

748
	dbg("%s - port %d", __func__, port->number);
A
Alan Cox 已提交
749 750 751
	dbg("%s - interrupt out size is %d", __func__,
						port->interrupt_out_size);

L
Linus Torvalds 已提交
752 753
	spin_lock_irqsave(&priv->lock, flags);
	if (priv->write_urb_in_use) {
754
		dbg("%s - can't write, urb in use", __func__);
L
Linus Torvalds 已提交
755 756 757 758 759 760
		spin_unlock_irqrestore(&priv->lock, flags);
		return;
	}
	spin_unlock_irqrestore(&priv->lock, flags);

	/* clear buffer */
A
Alan Cox 已提交
761 762
	memset(port->interrupt_out_urb->transfer_buffer, 0,
						port->interrupt_out_size);
L
Linus Torvalds 已提交
763 764

	spin_lock_irqsave(&priv->lock, flags);
765 766 767 768 769 770 771 772 773 774 775 776
	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 已提交
777 778 779 780 781 782 783
	}

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

	if (priv->cmd_ctrl) {
		priv->cmd_count++;
784
		dbg("%s - line control command being issued", __func__);
L
Linus Torvalds 已提交
785 786 787 788 789
		spin_unlock_irqrestore(&priv->lock, flags);
		goto send;
	} else
		spin_unlock_irqrestore(&priv->lock, flags);

790 791 792 793
	count = kfifo_out_locked(&priv->write_fifo,
					&port->interrupt_out_buffer[offset],
					port->interrupt_out_size - offset,
					&priv->lock);
A
Alan Cox 已提交
794
	if (count == 0)
L
Linus Torvalds 已提交
795 796
		return;

797 798 799 800 801 802 803
	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 已提交
804 805
	}

806
	dbg("%s - count is %d", __func__, count);
L
Linus Torvalds 已提交
807 808 809 810 811 812 813 814 815

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
816 817 818
		actual_size = count +
			      (priv->pkt_fmt == packet_format_1 ? 2 : 1);

A
Alan Cox 已提交
819 820 821
	usb_serial_debug_data(debug, &port->dev, __func__,
		port->interrupt_out_size,
		port->interrupt_out_urb->transfer_buffer);
L
Linus Torvalds 已提交
822

823 824 825 826
	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 已提交
827
	result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
L
Linus Torvalds 已提交
828
	if (result) {
A
Alan Cox 已提交
829 830 831
		dev_err(&port->dev,
				"%s - failed submitting write urb, error %d\n",
							__func__, result);
L
Linus Torvalds 已提交
832
		priv->write_urb_in_use = 0;
833
		cypress_set_dead(port);
L
Linus Torvalds 已提交
834 835 836
	}

	spin_lock_irqsave(&priv->lock, flags);
A
Alan Cox 已提交
837
	if (priv->cmd_ctrl)
L
Linus Torvalds 已提交
838
		priv->cmd_ctrl = 0;
A
Alan Cox 已提交
839 840 841

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

844
	usb_serial_port_softint(port);
L
Linus Torvalds 已提交
845 846 847 848
} /* cypress_send */


/* returns how much space is available in the soft buffer */
A
Alan Cox 已提交
849
static int cypress_write_room(struct tty_struct *tty)
L
Linus Torvalds 已提交
850
{
A
Alan Cox 已提交
851
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
852 853 854 855
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int room = 0;
	unsigned long flags;

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

	spin_lock_irqsave(&priv->lock, flags);
859
	room = kfifo_avail(&priv->write_fifo);
L
Linus Torvalds 已提交
860 861
	spin_unlock_irqrestore(&priv->lock, flags);

862
	dbg("%s - returns %d", __func__, room);
L
Linus Torvalds 已提交
863 864 865 866
	return room;
}


A
Alan Cox 已提交
867
static int cypress_tiocmget(struct tty_struct *tty, struct file *file)
L
Linus Torvalds 已提交
868
{
A
Alan Cox 已提交
869
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
870 871 872 873
	struct cypress_private *priv = usb_get_serial_port_data(port);
	__u8 status, control;
	unsigned int result = 0;
	unsigned long flags;
A
Alan Cox 已提交
874

875
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
876 877 878 879 880 881 882 883 884 885 886 887 888

	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);

889
	dbg("%s - result = %x", __func__, result);
L
Linus Torvalds 已提交
890 891 892 893 894

	return result;
}


A
Alan Cox 已提交
895
static int cypress_tiocmset(struct tty_struct *tty, struct file *file,
L
Linus Torvalds 已提交
896 897
			       unsigned int set, unsigned int clear)
{
A
Alan Cox 已提交
898
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
899 900
	struct cypress_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
A
Alan Cox 已提交
901

902
	dbg("%s - port %d", __func__, port->number);
L
Linus Torvalds 已提交
903 904 905 906 907 908 909 910 911 912

	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 已提交
913
	priv->cmd_ctrl = 1;
L
Linus Torvalds 已提交
914 915
	spin_unlock_irqrestore(&priv->lock, flags);

A
Alan Cox 已提交
916
	return cypress_write(tty, port, NULL, 0);
L
Linus Torvalds 已提交
917 918 919
}


A
Alan Cox 已提交
920
static int cypress_ioctl(struct tty_struct *tty, struct file *file,
A
Alan Cox 已提交
921
					unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
922
{
A
Alan Cox 已提交
923
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
924 925
	struct cypress_private *priv = usb_get_serial_port_data(port);

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

	switch (cmd) {
A
Alan Cox 已提交
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
	/* 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 已提交
955
			}
A
Alan Cox 已提交
956 957 958 959
		}
		return 0;
	default:
		break;
L
Linus Torvalds 已提交
960
	}
961
	dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd);
L
Linus Torvalds 已提交
962 963 964 965
	return -ENOIOCTLCMD;
} /* cypress_ioctl */


A
Alan Cox 已提交
966 967
static void cypress_set_termios(struct tty_struct *tty,
	struct usb_serial_port *port, struct ktermios *old_termios)
L
Linus Torvalds 已提交
968 969 970
{
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int data_bits, stop_bits, parity_type, parity_enable;
A
Alan Cox 已提交
971
	unsigned cflag, iflag;
L
Linus Torvalds 已提交
972 973
	unsigned long flags;
	__u8 oldlines;
974
	int linechange = 0;
975

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

	spin_lock_irqsave(&priv->lock, flags);
A
Alan Cox 已提交
979 980
	/* We can't clean this one up as we don't know the device type
	   early enough */
L
Linus Torvalds 已提交
981 982 983
	if (!priv->termios_initialized) {
		if (priv->chiptype == CT_EARTHMATE) {
			*(tty->termios) = tty_std_termios;
984 985
			tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
				CLOCAL;
A
Alan Cox 已提交
986 987
			tty->termios->c_ispeed = 4800;
			tty->termios->c_ospeed = 4800;
L
Linus Torvalds 已提交
988 989
		} else if (priv->chiptype == CT_CYPHIDCOM) {
			*(tty->termios) = tty_std_termios;
990 991
			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
				CLOCAL;
A
Alan Cox 已提交
992 993
			tty->termios->c_ispeed = 9600;
			tty->termios->c_ospeed = 9600;
994 995 996 997
		} else if (priv->chiptype == CT_CA42V2) {
			*(tty->termios) = tty_std_termios;
			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
				CLOCAL;
A
Alan Cox 已提交
998 999
			tty->termios->c_ispeed = 9600;
			tty->termios->c_ospeed = 9600;
L
Linus Torvalds 已提交
1000 1001 1002 1003 1004
		}
		priv->termios_initialized = 1;
	}
	spin_unlock_irqrestore(&priv->lock, flags);

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

L
Linus Torvalds 已提交
1008 1009 1010 1011 1012
	cflag = tty->termios->c_cflag;
	iflag = tty->termios->c_iflag;

	/* check if there are new settings */
	if (old_termios) {
A
Alan Cox 已提交
1013 1014 1015 1016
		spin_lock_irqsave(&priv->lock, flags);
		priv->tmp_termios = *(tty->termios);
		spin_unlock_irqrestore(&priv->lock, flags);
	}
L
Linus Torvalds 已提交
1017 1018 1019 1020

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

1021 1022 1023
	/* 1 means 2 stop bits, 0 means 1 stop bit */
	stop_bits = cflag & CSTOPB ? 1 : 0;

L
Linus Torvalds 已提交
1024 1025
	if (cflag & PARENB) {
		parity_enable = 1;
1026 1027
		/* 1 means odd parity, 0 means even parity */
		parity_type = cflag & PARODD ? 1 : 0;
L
Linus Torvalds 已提交
1028 1029 1030
	} else
		parity_enable = parity_type = 0;

1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
	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 已提交
1042
		data_bits = 3;
1043 1044
		break;
	default:
1045 1046
		dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n",
			__func__);
1047 1048
		data_bits = 3;
	}
L
Linus Torvalds 已提交
1049 1050 1051 1052
	spin_lock_irqsave(&priv->lock, flags);
	oldlines = priv->line_control;
	if ((cflag & CBAUD) == B0) {
		/* drop dtr and rts */
1053
		dbg("%s - dropping the lines, baud rate 0bps", __func__);
L
Linus Torvalds 已提交
1054
		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
A
Alan Cox 已提交
1055
	} else
1056
		priv->line_control = (CONTROL_DTR | CONTROL_RTS);
L
Linus Torvalds 已提交
1057 1058
	spin_unlock_irqrestore(&priv->lock, flags);

1059
	dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, "
1060
			"%d data_bits (+5)", __func__, stop_bits,
1061 1062
			parity_enable, parity_type, data_bits);

A
Alan Cox 已提交
1063 1064 1065 1066
	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 已提交
1067

1068 1069 1070
	/* 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 已提交
1071
	cypress_serial_control(tty, port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
L
Linus Torvalds 已提交
1072

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

1076
	spin_lock_irqsave(&priv->lock, flags);
A
Alan Cox 已提交
1077
	if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) {
1078 1079
		dbg("Using custom termios settings for a baud rate of "
				"4800bps.");
L
Linus Torvalds 已提交
1080 1081 1082
		/* define custom termios settings for NMEA protocol */

		tty->termios->c_iflag /* input modes - */
1083 1084 1085 1086 1087 1088 1089 1090 1091
			&= ~(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 已提交
1092
		tty->termios->c_oflag /* output modes */
1093
			&= ~OPOST;    /* disable postprocess output char */
L
Linus Torvalds 已提交
1094

1095 1096 1097 1098 1099 1100 1101 1102
		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 */
1103
	} /* CT_CYPHIDCOM: Application should handle this for device */
L
Linus Torvalds 已提交
1104 1105 1106 1107 1108

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

	/* if necessary, set lines */
1109
	if (linechange) {
L
Linus Torvalds 已提交
1110
		priv->cmd_ctrl = 1;
A
Alan Cox 已提交
1111
		cypress_write(tty, port, NULL, 0);
L
Linus Torvalds 已提交
1112 1113 1114
	}
} /* cypress_set_termios */

1115

L
Linus Torvalds 已提交
1116
/* returns amount of data still left in soft buffer */
A
Alan Cox 已提交
1117
static int cypress_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1118
{
A
Alan Cox 已提交
1119
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1120 1121 1122 1123
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int chars = 0;
	unsigned long flags;

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

L
Linus Torvalds 已提交
1126
	spin_lock_irqsave(&priv->lock, flags);
1127
	chars = kfifo_len(&priv->write_fifo);
L
Linus Torvalds 已提交
1128 1129
	spin_unlock_irqrestore(&priv->lock, flags);

1130
	dbg("%s - returns %d", __func__, chars);
L
Linus Torvalds 已提交
1131 1132 1133 1134
	return chars;
}


A
Alan Cox 已提交
1135
static void cypress_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
1136
{
A
Alan Cox 已提交
1137
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1138 1139
	struct cypress_private *priv = usb_get_serial_port_data(port);

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

1142
	spin_lock_irq(&priv->lock);
L
Linus Torvalds 已提交
1143
	priv->rx_flags = THROTTLED;
1144
	spin_unlock_irq(&priv->lock);
L
Linus Torvalds 已提交
1145 1146 1147
}


A
Alan Cox 已提交
1148
static void cypress_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
1149
{
A
Alan Cox 已提交
1150
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
1151 1152 1153
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int actually_throttled, result;

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

1156
	spin_lock_irq(&priv->lock);
L
Linus Torvalds 已提交
1157 1158
	actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
	priv->rx_flags = 0;
1159
	spin_unlock_irq(&priv->lock);
L
Linus Torvalds 已提交
1160

1161 1162 1163
	if (!priv->comm_is_ok)
		return;

L
Linus Torvalds 已提交
1164 1165 1166
	if (actually_throttled) {
		port->interrupt_in_urb->dev = port->serial->dev;

1167
		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
1168
		if (result) {
1169
			dev_err(&port->dev, "%s - failed submitting read urb, "
1170
					"error %d\n", __func__, result);
1171 1172
			cypress_set_dead(port);
		}
L
Linus Torvalds 已提交
1173 1174 1175 1176
	}
}


1177
static void cypress_read_int_callback(struct urb *urb)
L
Linus Torvalds 已提交
1178
{
1179
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
1180 1181 1182 1183
	struct cypress_private *priv = usb_get_serial_port_data(port);
	struct tty_struct *tty;
	unsigned char *data = urb->transfer_buffer;
	unsigned long flags;
1184
	char tty_flag = TTY_NORMAL;
L
Linus Torvalds 已提交
1185 1186 1187 1188
	int havedata = 0;
	int bytes = 0;
	int result;
	int i = 0;
1189
	int status = urb->status;
L
Linus Torvalds 已提交
1190

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

1193
	switch (status) {
1194 1195 1196 1197 1198 1199 1200 1201
	case 0: /* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* precursor to disconnect so just go away */
		return;
	case -EPIPE:
1202 1203
		/* Can't call usb_clear_halt while in_interrupt */
		/* FALLS THROUGH */
1204 1205
	default:
		/* something ugly is going on... */
A
Alan Cox 已提交
1206 1207 1208
		dev_err(&urb->dev->dev,
			"%s - unexpected nonzero read status received: %d\n",
							__func__, status);
1209
		cypress_set_dead(port);
L
Linus Torvalds 已提交
1210 1211 1212 1213 1214
		return;
	}

	spin_lock_irqsave(&priv->lock, flags);
	if (priv->rx_flags & THROTTLED) {
1215
		dbg("%s - now throttling", __func__);
L
Linus Torvalds 已提交
1216 1217 1218 1219 1220 1221
		priv->rx_flags |= ACTUALLY_THROTTLED;
		spin_unlock_irqrestore(&priv->lock, flags);
		return;
	}
	spin_unlock_irqrestore(&priv->lock, flags);

A
Alan Cox 已提交
1222
	tty = tty_port_tty_get(&port->port);
L
Linus Torvalds 已提交
1223
	if (!tty) {
1224
		dbg("%s - bad tty pointer - exiting", __func__);
L
Linus Torvalds 已提交
1225 1226 1227 1228
		return;
	}

	spin_lock_irqsave(&priv->lock, flags);
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
	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 已提交
1248 1249
	}
	spin_unlock_irqrestore(&priv->lock, flags);
1250 1251 1252 1253 1254
	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 已提交
1255

A
Alan Cox 已提交
1256 1257
	usb_serial_debug_data(debug, &port->dev, __func__,
						urb->actual_length, data);
L
Linus Torvalds 已提交
1258 1259 1260

	spin_lock_irqsave(&priv->lock, flags);
	/* check to see if status has changed */
1261 1262 1263 1264 1265
	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 已提交
1266
	}
1267
	spin_unlock_irqrestore(&priv->lock, flags);
L
Linus Torvalds 已提交
1268

1269 1270 1271 1272
	/* 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)) {
1273
		dbg("%s - calling hangup", __func__);
L
Linus Torvalds 已提交
1274 1275 1276 1277
		tty_hangup(tty);
		goto continue_read;
	}

1278 1279 1280 1281
	/* 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 已提交
1282 1283 1284 1285
	spin_lock_irqsave(&priv->lock, flags);
	if (priv->current_status & CYP_ERROR) {
		spin_unlock_irqrestore(&priv->lock, flags);
		tty_flag = TTY_PARITY;
1286
		dbg("%s - Parity Error detected", __func__);
L
Linus Torvalds 已提交
1287 1288 1289 1290
	} else
		spin_unlock_irqrestore(&priv->lock, flags);

	/* process read if there is data other than line status */
1291 1292
	if (tty && bytes > i) {
		tty_insert_flip_string_fixed_flag(tty, data + i,
1293
				tty_flag, bytes - i);
A
Alan Cox 已提交
1294
		tty_flip_buffer_push(tty);
L
Linus Torvalds 已提交
1295 1296 1297
	}

	spin_lock_irqsave(&priv->lock, flags);
1298 1299
	/* control and status byte(s) are also counted */
	priv->bytes_in += bytes;
L
Linus Torvalds 已提交
1300 1301 1302
	spin_unlock_irqrestore(&priv->lock, flags);

continue_read:
A
Alan Cox 已提交
1303
	tty_kref_put(tty);
1304

1305
	/* Continue trying to always read */
L
Linus Torvalds 已提交
1306

1307
	if (priv->comm_is_ok) {
1308 1309 1310 1311 1312
		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 已提交
1313 1314
				cypress_read_int_callback, port,
				priv->read_urb_interval);
1315
		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
1316
		if (result && result != -EPERM) {
1317
			dev_err(&urb->dev->dev, "%s - failed resubmitting "
1318
					"read urb, error %d\n", __func__,
1319
					result);
1320 1321
			cypress_set_dead(port);
		}
L
Linus Torvalds 已提交
1322
	}
1323

L
Linus Torvalds 已提交
1324 1325 1326 1327
	return;
} /* cypress_read_int_callback */


1328
static void cypress_write_int_callback(struct urb *urb)
L
Linus Torvalds 已提交
1329
{
1330
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
1331 1332
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int result;
1333
	int status = urb->status;
L
Linus Torvalds 已提交
1334

1335
	dbg("%s - port %d", __func__, port->number);
1336 1337

	switch (status) {
A
Alan Cox 已提交
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
	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 已提交
1351
			break;
A
Alan Cox 已提交
1352 1353 1354 1355 1356 1357 1358 1359
		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 已提交
1360
			return;
A
Alan Cox 已提交
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
		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 已提交
1372 1373
	}
	priv->write_urb_in_use = 0;
A
Alan Cox 已提交
1374

L
Linus Torvalds 已提交
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
	/* send any buffered data */
	cypress_send(port);
}


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

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

1388
	dbg("%s", __func__);
A
Alan Cox 已提交
1389

L
Linus Torvalds 已提交
1390 1391 1392 1393 1394 1395
	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;
1396 1397 1398
	retval = usb_serial_register(&cypress_ca42v2_device);
	if (retval)
		goto failed_ca42v2_register;
L
Linus Torvalds 已提交
1399 1400 1401 1402
	retval = usb_register(&cypress_driver);
	if (retval)
		goto failed_usb_register;

1403 1404
	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
	       DRIVER_DESC "\n");
L
Linus Torvalds 已提交
1405
	return 0;
1406

L
Linus Torvalds 已提交
1407
failed_usb_register:
1408
	usb_serial_deregister(&cypress_ca42v2_device);
1409
failed_ca42v2_register:
L
Linus Torvalds 已提交
1410
	usb_serial_deregister(&cypress_hidcom_device);
1411
failed_hidcom_register:
L
Linus Torvalds 已提交
1412
	usb_serial_deregister(&cypress_earthmate_device);
1413
failed_em_register:
L
Linus Torvalds 已提交
1414 1415 1416 1417
	return retval;
}


A
Alan Cox 已提交
1418
static void __exit cypress_exit(void)
L
Linus Torvalds 已提交
1419
{
1420
	dbg("%s", __func__);
L
Linus Torvalds 已提交
1421

A
Alan Cox 已提交
1422 1423 1424 1425
	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 已提交
1426 1427 1428 1429 1430 1431
}


module_init(cypress_init);
module_exit(cypress_exit);

A
Alan Cox 已提交
1432 1433 1434
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
L
Linus Torvalds 已提交
1435 1436 1437 1438 1439 1440
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");
1441 1442
module_param(interval, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(interval, "Overrides interrupt interval");
1443 1444
module_param(unstable_bauds, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(unstable_bauds, "Allow unstable baud rates");