mct_u232.c 26.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*
 * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver
 *
 *   Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
 *
 *   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.
 *
 * This program is largely derived from the Belkin USB Serial Adapter Driver
 * (see belkin_sa.[ch]). All of the information about the device was acquired
 * by using SniffUSB on Windows98. For technical details see mct_u232.h.
 *
 * William G. Greathouse and Greg Kroah-Hartman provided great help on how to
 * do the reverse engineering and how to write a USB serial device driver.
 *
 * TO BE DONE, TO BE CHECKED:
 *   DTR/RTS signal handling may be incomplete or incorrect. I have mainly
 *   implemented what I have seen with SniffUSB or found in belkin_sa.c.
 *   For further TODOs check also belkin_sa.c.
 */

#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/spinlock.h>
A
Alan Cox 已提交
33
#include <linux/uaccess.h>
34
#include <asm/unaligned.h>
L
Linus Torvalds 已提交
35
#include <linux/usb.h>
36
#include <linux/usb/serial.h>
37 38
#include <linux/serial.h>
#include <linux/ioctl.h>
L
Linus Torvalds 已提交
39 40 41 42 43
#include "mct_u232.h"

/*
 * Version Information
 */
44
#define DRIVER_VERSION "z2.1"		/* Linux in-kernel version */
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52
#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
#define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"

static int debug;

/*
 * Function prototypes
 */
A
Alan Cox 已提交
53
static int  mct_u232_startup(struct usb_serial *serial);
54
static void mct_u232_release(struct usb_serial *serial);
55
static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port);
56 57
static void mct_u232_close(struct usb_serial_port *port);
static void mct_u232_dtr_rts(struct usb_serial_port *port, int on);
A
Alan Cox 已提交
58 59 60 61
static void mct_u232_read_int_callback(struct urb *urb);
static void mct_u232_set_termios(struct tty_struct *tty,
			struct usb_serial_port *port, struct ktermios *old);
static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);
62
static int  mct_u232_tiocmget(struct tty_struct *tty);
63
static int  mct_u232_tiocmset(struct tty_struct *tty,
A
Alan Cox 已提交
64
			unsigned int set, unsigned int clear);
65
static int  mct_u232_ioctl(struct tty_struct *tty,
66 67 68
			unsigned int cmd, unsigned long arg);
static int  mct_u232_get_icount(struct tty_struct *tty,
			struct serial_icounter_struct *icount);
A
Alan Cox 已提交
69 70
static void mct_u232_throttle(struct tty_struct *tty);
static void mct_u232_unthrottle(struct tty_struct *tty);
71 72


L
Linus Torvalds 已提交
73 74 75
/*
 * All of the device info needed for the MCT USB-RS232 converter.
 */
76
static const struct usb_device_id id_table_combined[] = {
L
Linus Torvalds 已提交
77 78 79 80 81 82 83
	{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
	{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
	{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
	{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
	{ }		/* Terminating entry */
};

A
Alan Cox 已提交
84
MODULE_DEVICE_TABLE(usb, id_table_combined);
L
Linus Torvalds 已提交
85 86 87 88 89 90

static struct usb_driver mct_u232_driver = {
	.name =		"mct_u232",
	.probe =	usb_serial_probe,
	.disconnect =	usb_serial_disconnect,
	.id_table =	id_table_combined,
91
	.no_dynamic_id = 	1,
L
Linus Torvalds 已提交
92 93
};

94
static struct usb_serial_driver mct_u232_device = {
95 96
	.driver = {
		.owner =	THIS_MODULE,
97
		.name =		"mct_u232",
98
	},
99
	.description =	     "MCT U232",
100
	.usb_driver = 	     &mct_u232_driver,
L
Linus Torvalds 已提交
101 102 103 104
	.id_table =	     id_table_combined,
	.num_ports =	     1,
	.open =		     mct_u232_open,
	.close =	     mct_u232_close,
105
	.dtr_rts =	     mct_u232_dtr_rts,
106 107
	.throttle =	     mct_u232_throttle,
	.unthrottle =	     mct_u232_unthrottle,
L
Linus Torvalds 已提交
108 109 110 111 112 113
	.read_int_callback = mct_u232_read_int_callback,
	.set_termios =	     mct_u232_set_termios,
	.break_ctl =	     mct_u232_break_ctl,
	.tiocmget =	     mct_u232_tiocmget,
	.tiocmset =	     mct_u232_tiocmset,
	.attach =	     mct_u232_startup,
114
	.release =	     mct_u232_release,
115 116
	.ioctl =             mct_u232_ioctl,
	.get_icount =        mct_u232_get_icount,
L
Linus Torvalds 已提交
117 118 119 120 121 122 123 124
};

struct mct_u232_private {
	spinlock_t lock;
	unsigned int	     control_state; /* Modem Line Setting (TIOCM) */
	unsigned char        last_lcr;      /* Line Control Register */
	unsigned char	     last_lsr;      /* Line Status Register */
	unsigned char	     last_msr;      /* Modem Status Register */
125
	unsigned int	     rx_flags;      /* Throttling flags */
126 127 128
	struct async_icount  icount;
	wait_queue_head_t    msr_wait;	/* for handling sleeping while waiting
						for msr change to happen */
L
Linus Torvalds 已提交
129 130
};

131 132
#define THROTTLED		0x01

L
Linus Torvalds 已提交
133 134 135 136 137 138 139 140 141 142
/*
 * Handle vendor specific USB requests
 */

#define WDR_TIMEOUT 5000 /* default urb timeout */

/*
 * Later day 2.6.0-test kernels have new baud rates like B230400 which
 * we do not know how to support. We ignore them for the moment.
 */
A
Alan Cox 已提交
143 144
static int mct_u232_calculate_baud_rate(struct usb_serial *serial,
					speed_t value, speed_t *result)
L
Linus Torvalds 已提交
145
{
146 147
	*result = value;

L
Linus Torvalds 已提交
148
	if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
A
Alan Cox 已提交
149
		|| le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
L
Linus Torvalds 已提交
150
		switch (value) {
A
Alan Cox 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
		case 300:
			return 0x01;
		case 600:
			return 0x02; /* this one not tested */
		case 1200:
			return 0x03;
		case 2400:
			return 0x04;
		case 4800:
			return 0x06;
		case 9600:
			return 0x08;
		case 19200:
			return 0x09;
		case 38400:
			return 0x0a;
		case 57600:
			return 0x0b;
		case 115200:
			return 0x0c;
L
Linus Torvalds 已提交
171
		default:
172
			*result = 9600;
L
Linus Torvalds 已提交
173 174 175
			return 0x08;
		}
	} else {
176 177 178
		/* FIXME: Can we use any divider - should we do
		   divider = 115200/value;
		   real baud = 115200/divider */
L
Linus Torvalds 已提交
179
		switch (value) {
180 181 182 183 184 185 186 187 188 189 190 191
		case 300: break;
		case 600: break;
		case 1200: break;
		case 2400: break;
		case 4800: break;
		case 9600: break;
		case 19200: break;
		case 38400: break;
		case 57600: break;
		case 115200: break;
		default:
			value = 9600;
192
			*result = 9600;
L
Linus Torvalds 已提交
193 194 195 196 197
		}
		return 115200/value;
	}
}

A
Alan Cox 已提交
198 199
static int mct_u232_set_baud_rate(struct tty_struct *tty,
	struct usb_serial *serial, struct usb_serial_port *port, speed_t value)
L
Linus Torvalds 已提交
200
{
201
	unsigned int divisor;
A
Alan Cox 已提交
202
	int rc;
203
	unsigned char *buf;
A
Alan Cox 已提交
204 205 206
	unsigned char cts_enable_byte = 0;
	speed_t speed;

207 208 209
	buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
	if (buf == NULL)
		return -ENOMEM;
A
Alan Cox 已提交
210

211 212
	divisor = mct_u232_calculate_baud_rate(serial, value, &speed);
	put_unaligned_le32(cpu_to_le32(divisor), buf);
A
Alan Cox 已提交
213 214 215
	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
				MCT_U232_SET_BAUD_RATE_REQUEST,
				MCT_U232_SET_REQUEST_TYPE,
216
				0, 0, buf, MCT_U232_SET_BAUD_RATE_SIZE,
A
Alan Cox 已提交
217
				WDR_TIMEOUT);
218
	if (rc < 0)	/*FIXME: What value speed results */
219 220
		dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)\n",
			value, rc);
221
	else
A
Alan Cox 已提交
222
		tty_encode_baud_rate(tty, speed, speed);
L
Linus Torvalds 已提交
223 224 225 226 227 228 229
	dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);

	/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
	   always sends two extra USB 'device request' messages after the
	   'baud rate change' message.  The actual functionality of the
	   request codes in these messages is not fully understood but these
	   particular codes are never seen in any operation besides a baud
230 231 232 233 234 235 236
	   rate change.  Both of these messages send a single byte of data.
	   In the first message, the value of this byte is always zero.

	   The second message has been determined experimentally to control
	   whether data will be transmitted to a device which is not asserting
	   the 'CTS' signal.  If the second message's data byte is zero, data
	   will be transmitted even if 'CTS' is not asserted (i.e. no hardware
A
Alan Cox 已提交
237 238 239
	   flow control).  if the second message's data byte is nonzero (a
	   value of 1 is used by this driver), data will not be transmitted to
	   a device which is not asserting 'CTS'.
240
	*/
L
Linus Torvalds 已提交
241

242
	buf[0] = 0;
L
Linus Torvalds 已提交
243
	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
A
Alan Cox 已提交
244 245
				MCT_U232_SET_UNKNOWN1_REQUEST,
				MCT_U232_SET_REQUEST_TYPE,
246
				0, 0, buf, MCT_U232_SET_UNKNOWN1_SIZE,
A
Alan Cox 已提交
247
				WDR_TIMEOUT);
L
Linus Torvalds 已提交
248
	if (rc < 0)
249 250 251
		dev_err(&port->dev, "Sending USB device request code %d "
			"failed (error = %d)\n", MCT_U232_SET_UNKNOWN1_REQUEST,
			rc);
L
Linus Torvalds 已提交
252

A
Alan Cox 已提交
253
	if (port && C_CRTSCTS(tty))
254 255
	   cts_enable_byte = 1;

A
Alan Cox 已提交
256 257
	dbg("set_baud_rate: send second control message, data = %02X",
							cts_enable_byte);
258
	buf[0] = cts_enable_byte;
L
Linus Torvalds 已提交
259
	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
A
Alan Cox 已提交
260 261
			MCT_U232_SET_CTS_REQUEST,
			MCT_U232_SET_REQUEST_TYPE,
262
			0, 0, buf, MCT_U232_SET_CTS_SIZE,
A
Alan Cox 已提交
263
			WDR_TIMEOUT);
L
Linus Torvalds 已提交
264
	if (rc < 0)
265 266
		dev_err(&port->dev, "Sending USB device request code %d "
			"failed (error = %d)\n", MCT_U232_SET_CTS_REQUEST, rc);
L
Linus Torvalds 已提交
267

268
	kfree(buf);
A
Alan Cox 已提交
269
	return rc;
L
Linus Torvalds 已提交
270 271 272 273
} /* mct_u232_set_baud_rate */

static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
{
A
Alan Cox 已提交
274
	int rc;
275 276 277 278 279 280 281
	unsigned char *buf;

	buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
	if (buf == NULL)
		return -ENOMEM;

	buf[0] = lcr;
A
Alan Cox 已提交
282 283 284
	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
			MCT_U232_SET_LINE_CTRL_REQUEST,
			MCT_U232_SET_REQUEST_TYPE,
285
			0, 0, buf, MCT_U232_SET_LINE_CTRL_SIZE,
A
Alan Cox 已提交
286
			WDR_TIMEOUT);
L
Linus Torvalds 已提交
287
	if (rc < 0)
288 289
		dev_err(&serial->dev->dev,
			"Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc);
L
Linus Torvalds 已提交
290
	dbg("set_line_ctrl: 0x%x", lcr);
291
	kfree(buf);
A
Alan Cox 已提交
292
	return rc;
L
Linus Torvalds 已提交
293 294 295 296 297
} /* mct_u232_set_line_ctrl */

static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
				   unsigned int control_state)
{
A
Alan Cox 已提交
298
	int rc;
299 300 301 302 303 304
	unsigned char mcr;
	unsigned char *buf;

	buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
	if (buf == NULL)
		return -ENOMEM;
L
Linus Torvalds 已提交
305

306
	mcr = MCT_U232_MCR_NONE;
L
Linus Torvalds 已提交
307 308 309 310 311
	if (control_state & TIOCM_DTR)
		mcr |= MCT_U232_MCR_DTR;
	if (control_state & TIOCM_RTS)
		mcr |= MCT_U232_MCR_RTS;

312
	buf[0] = mcr;
A
Alan Cox 已提交
313 314 315
	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
			MCT_U232_SET_MODEM_CTRL_REQUEST,
			MCT_U232_SET_REQUEST_TYPE,
316
			0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE,
A
Alan Cox 已提交
317
			WDR_TIMEOUT);
L
Linus Torvalds 已提交
318
	if (rc < 0)
319 320
		dev_err(&serial->dev->dev,
			"Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
L
Linus Torvalds 已提交
321 322
	dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);

323
	kfree(buf);
A
Alan Cox 已提交
324
	return rc;
L
Linus Torvalds 已提交
325 326
} /* mct_u232_set_modem_ctrl */

A
Alan Cox 已提交
327 328
static int mct_u232_get_modem_stat(struct usb_serial *serial,
						unsigned char *msr)
L
Linus Torvalds 已提交
329
{
A
Alan Cox 已提交
330
	int rc;
331 332 333 334 335 336 337
	unsigned char *buf;

	buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
	if (buf == NULL) {
		*msr = 0;
		return -ENOMEM;
	}
A
Alan Cox 已提交
338 339 340
	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
			MCT_U232_GET_MODEM_STAT_REQUEST,
			MCT_U232_GET_REQUEST_TYPE,
341
			0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
A
Alan Cox 已提交
342
			WDR_TIMEOUT);
L
Linus Torvalds 已提交
343
	if (rc < 0) {
344 345
		dev_err(&serial->dev->dev,
			"Get MODEM STATus failed (error = %d)\n", rc);
L
Linus Torvalds 已提交
346
		*msr = 0;
347 348
	} else {
		*msr = buf[0];
L
Linus Torvalds 已提交
349 350
	}
	dbg("get_modem_stat: 0x%x", *msr);
351
	kfree(buf);
A
Alan Cox 已提交
352
	return rc;
L
Linus Torvalds 已提交
353 354
} /* mct_u232_get_modem_stat */

355 356 357 358 359 360 361 362 363 364 365 366 367 368
static void mct_u232_msr_to_icount(struct async_icount *icount,
						unsigned char msr)
{
	/* Translate Control Line states */
	if (msr & MCT_U232_MSR_DDSR)
		icount->dsr++;
	if (msr & MCT_U232_MSR_DCTS)
		icount->cts++;
	if (msr & MCT_U232_MSR_DRI)
		icount->rng++;
	if (msr & MCT_U232_MSR_DCD)
		icount->dcd++;
} /* mct_u232_msr_to_icount */

A
Alan Cox 已提交
369 370
static void mct_u232_msr_to_state(unsigned int *control_state,
						unsigned char msr)
L
Linus Torvalds 已提交
371
{
A
Alan Cox 已提交
372
	/* Translate Control Line states */
L
Linus Torvalds 已提交
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
	if (msr & MCT_U232_MSR_DSR)
		*control_state |=  TIOCM_DSR;
	else
		*control_state &= ~TIOCM_DSR;
	if (msr & MCT_U232_MSR_CTS)
		*control_state |=  TIOCM_CTS;
	else
		*control_state &= ~TIOCM_CTS;
	if (msr & MCT_U232_MSR_RI)
		*control_state |=  TIOCM_RI;
	else
		*control_state &= ~TIOCM_RI;
	if (msr & MCT_U232_MSR_CD)
		*control_state |=  TIOCM_CD;
	else
		*control_state &= ~TIOCM_CD;
A
Alan Cox 已提交
389
	dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
L
Linus Torvalds 已提交
390 391 392 393 394 395
} /* mct_u232_msr_to_state */

/*
 * Driver's tty interface functions
 */

A
Alan Cox 已提交
396
static int mct_u232_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
397 398 399 400
{
	struct mct_u232_private *priv;
	struct usb_serial_port *port, *rport;

401
	priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
L
Linus Torvalds 已提交
402 403 404
	if (!priv)
		return -ENOMEM;
	spin_lock_init(&priv->lock);
405
	init_waitqueue_head(&priv->msr_wait);
L
Linus Torvalds 已提交
406 407 408 409 410 411 412
	usb_set_serial_port_data(serial->port[0], priv);

	init_waitqueue_head(&serial->port[0]->write_wait);

	/* Puh, that's dirty */
	port = serial->port[0];
	rport = serial->port[1];
M
Mariusz Kozlowski 已提交
413 414
	/* No unlinking, it wasn't submitted yet. */
	usb_free_urb(port->read_urb);
L
Linus Torvalds 已提交
415 416 417 418
	port->read_urb = rport->interrupt_in_urb;
	rport->interrupt_in_urb = NULL;
	port->read_urb->context = port;

A
Alan Cox 已提交
419
	return 0;
L
Linus Torvalds 已提交
420 421 422
} /* mct_u232_startup */


423
static void mct_u232_release(struct usb_serial *serial)
L
Linus Torvalds 已提交
424 425 426
{
	struct mct_u232_private *priv;
	int i;
A
Alan Cox 已提交
427

428
	dbg("%s", __func__);
L
Linus Torvalds 已提交
429

A
Alan Cox 已提交
430
	for (i = 0; i < serial->num_ports; ++i) {
L
Linus Torvalds 已提交
431 432
		/* My special items, the standard routines free my urbs */
		priv = usb_get_serial_port_data(serial->port[i]);
433
		kfree(priv);
L
Linus Torvalds 已提交
434
	}
435
} /* mct_u232_release */
L
Linus Torvalds 已提交
436

437
static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
L
Linus Torvalds 已提交
438 439 440 441 442 443 444 445 446
{
	struct usb_serial *serial = port->serial;
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
	int retval = 0;
	unsigned int control_state;
	unsigned long flags;
	unsigned char last_lcr;
	unsigned char last_msr;

447
	dbg("%s port %d", __func__, port->number);
L
Linus Torvalds 已提交
448 449 450 451 452 453

	/* Compensate for a hardware bug: although the Sitecom U232-P25
	 * device reports a maximum output packet size of 32 bytes,
	 * it seems to be able to accept only 16 bytes (and that's what
	 * SniffUSB says too...)
	 */
A
Alan Cox 已提交
454 455
	if (le16_to_cpu(serial->dev->descriptor.idProduct)
						== MCT_U232_SITECOM_PID)
L
Linus Torvalds 已提交
456 457
		port->bulk_out_size = 16;

A
Alan Cox 已提交
458
	/* Do a defined restart: the normal serial device seems to
L
Linus Torvalds 已提交
459 460 461 462 463
	 * always turn on DTR and RTS here, so do the same. I'm not
	 * sure if this is really necessary. But it should not harm
	 * either.
	 */
	spin_lock_irqsave(&priv->lock, flags);
A
Alan Cox 已提交
464
	if (tty && (tty->termios->c_cflag & CBAUD))
L
Linus Torvalds 已提交
465 466 467
		priv->control_state = TIOCM_DTR | TIOCM_RTS;
	else
		priv->control_state = 0;
A
Alan Cox 已提交
468 469

	priv->last_lcr = (MCT_U232_DATA_BITS_8 |
L
Linus Torvalds 已提交
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
			  MCT_U232_PARITY_NONE |
			  MCT_U232_STOP_BITS_1);
	control_state = priv->control_state;
	last_lcr = priv->last_lcr;
	spin_unlock_irqrestore(&priv->lock, flags);
	mct_u232_set_modem_ctrl(serial, control_state);
	mct_u232_set_line_ctrl(serial, last_lcr);

	/* Read modem status and update control state */
	mct_u232_get_modem_stat(serial, &last_msr);
	spin_lock_irqsave(&priv->lock, flags);
	priv->last_msr = last_msr;
	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
	spin_unlock_irqrestore(&priv->lock, flags);

	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
	if (retval) {
487 488 489
		dev_err(&port->dev,
			"usb_submit_urb(read bulk) failed pipe 0x%x err %d\n",
			port->read_urb->pipe, retval);
490
		goto error;
L
Linus Torvalds 已提交
491 492 493
	}

	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
494 495
	if (retval) {
		usb_kill_urb(port->read_urb);
496 497 498
		dev_err(&port->dev,
			"usb_submit_urb(read int) failed pipe 0x%x err %d",
			port->interrupt_in_urb->pipe, retval);
499 500
		goto error;
	}
L
Linus Torvalds 已提交
501
	return 0;
502 503 504

error:
	return retval;
L
Linus Torvalds 已提交
505 506
} /* mct_u232_open */

507
static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
L
Linus Torvalds 已提交
508
{
509 510
	unsigned int control_state;
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
L
Linus Torvalds 已提交
511

512 513 514 515 516 517 518
	mutex_lock(&port->serial->disc_mutex);
	if (!port->serial->disconnected) {
		/* drop DTR and RTS */
		spin_lock_irq(&priv->lock);
		if (on)
			priv->control_state |= TIOCM_DTR | TIOCM_RTS;
		else
519
			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
520 521 522
		control_state = priv->control_state;
		spin_unlock_irq(&priv->lock);
		mct_u232_set_modem_ctrl(port->serial, control_state);
523
	}
524 525
	mutex_unlock(&port->serial->disc_mutex);
}
526

527 528 529
static void mct_u232_close(struct usb_serial_port *port)
{
	dbg("%s port %d", __func__, port->number);
530

J
Johan Hovold 已提交
531 532 533 534
	if (port->serial->dev) {
		/* shutdown our urbs */
		usb_kill_urb(port->write_urb);
		usb_kill_urb(port->read_urb);
L
Linus Torvalds 已提交
535
		usb_kill_urb(port->interrupt_in_urb);
J
Johan Hovold 已提交
536
	}
L
Linus Torvalds 已提交
537 538 539
} /* mct_u232_close */


A
Alan Cox 已提交
540
static void mct_u232_read_int_callback(struct urb *urb)
L
Linus Torvalds 已提交
541
{
542
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
543 544 545 546
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
	struct usb_serial *serial = port->serial;
	struct tty_struct *tty;
	unsigned char *data = urb->transfer_buffer;
547 548
	int retval;
	int status = urb->status;
L
Linus Torvalds 已提交
549 550
	unsigned long flags;

551
	switch (status) {
L
Linus Torvalds 已提交
552 553 554 555 556 557 558
	case 0:
		/* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* this urb is terminated, clean up */
559
		dbg("%s - urb shutting down with status: %d",
560
		    __func__, status);
L
Linus Torvalds 已提交
561 562
		return;
	default:
563
		dbg("%s - nonzero urb status received: %d",
564
		    __func__, status);
L
Linus Torvalds 已提交
565 566 567 568
		goto exit;
	}

	if (!serial) {
569
		dbg("%s - bad serial pointer, exiting", __func__);
L
Linus Torvalds 已提交
570 571 572
		return;
	}

A
Alan Cox 已提交
573 574 575
	dbg("%s - port %d", __func__, port->number);
	usb_serial_debug_data(debug, &port->dev, __func__,
					urb->actual_length, data);
L
Linus Torvalds 已提交
576 577 578 579 580 581

	/*
	 * Work-a-round: handle the 'usual' bulk-in pipe here
	 */
	if (urb->transfer_buffer_length > 2) {
		if (urb->actual_length) {
582 583 584 585 586 587
			tty = tty_port_tty_get(&port->port);
			if (tty) {
				tty_insert_flip_string(tty, data,
						urb->actual_length);
				tty_flip_buffer_push(tty);
			}
A
Alan Cox 已提交
588
			tty_kref_put(tty);
L
Linus Torvalds 已提交
589 590 591
		}
		goto exit;
	}
A
Alan Cox 已提交
592

L
Linus Torvalds 已提交
593 594 595 596 597 598
	/*
	 * The interrupt-in pipe signals exceptional conditions (modem line
	 * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
	 */
	spin_lock_irqsave(&priv->lock, flags);
	priv->last_msr = data[MCT_U232_MSR_INDEX];
A
Alan Cox 已提交
599

L
Linus Torvalds 已提交
600 601 602
	/* Record Control Line states */
	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);

603 604
	mct_u232_msr_to_icount(&priv->icount, priv->last_msr);

L
Linus Torvalds 已提交
605
#if 0
A
Alan Cox 已提交
606
	/* Not yet handled. See belkin_sa.c for further information */
L
Linus Torvalds 已提交
607 608 609 610 611 612 613 614
	/* Now to report any errors */
	priv->last_lsr = data[MCT_U232_LSR_INDEX];
	/*
	 * fill in the flip buffer here, but I do not know the relation
	 * to the current/next receive buffer or characters.  I need
	 * to look in to this before committing any code.
	 */
	if (priv->last_lsr & MCT_U232_LSR_ERR) {
A
Alan Cox 已提交
615
		tty = tty_port_tty_get(&port->port);
L
Linus Torvalds 已提交
616 617 618 619 620 621 622 623 624 625 626 627
		/* Overrun Error */
		if (priv->last_lsr & MCT_U232_LSR_OE) {
		}
		/* Parity Error */
		if (priv->last_lsr & MCT_U232_LSR_PE) {
		}
		/* Framing Error */
		if (priv->last_lsr & MCT_U232_LSR_FE) {
		}
		/* Break Indicator */
		if (priv->last_lsr & MCT_U232_LSR_BI) {
		}
A
Alan Cox 已提交
628
		tty_kref_put(tty);
L
Linus Torvalds 已提交
629 630
	}
#endif
631
	wake_up_interruptible(&priv->msr_wait);
L
Linus Torvalds 已提交
632 633
	spin_unlock_irqrestore(&priv->lock, flags);
exit:
A
Alan Cox 已提交
634
	retval = usb_submit_urb(urb, GFP_ATOMIC);
635
	if (retval)
636 637 638
		dev_err(&port->dev,
			"%s - usb_submit_urb failed with result %d\n",
			__func__, retval);
L
Linus Torvalds 已提交
639 640
} /* mct_u232_read_int_callback */

A
Alan Cox 已提交
641 642 643
static void mct_u232_set_termios(struct tty_struct *tty,
				 struct usb_serial_port *port,
				 struct ktermios *old_termios)
L
Linus Torvalds 已提交
644 645 646
{
	struct usb_serial *serial = port->serial;
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
A
Alan Cox 已提交
647
	struct ktermios *termios = tty->termios;
648
	unsigned int cflag = termios->c_cflag;
L
Linus Torvalds 已提交
649 650
	unsigned int old_cflag = old_termios->c_cflag;
	unsigned long flags;
651
	unsigned int control_state;
L
Linus Torvalds 已提交
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
	unsigned char last_lcr;

	/* get a local copy of the current port settings */
	spin_lock_irqsave(&priv->lock, flags);
	control_state = priv->control_state;
	spin_unlock_irqrestore(&priv->lock, flags);
	last_lcr = 0;

	/*
	 * Update baud rate.
	 * Do not attempt to cache old rates and skip settings,
	 * disconnects screw such tricks up completely.
	 * Premature optimization is the root of all evil.
	 */

A
Alan Cox 已提交
667
	/* reassert DTR and RTS on transition from B0 */
L
Linus Torvalds 已提交
668
	if ((old_cflag & CBAUD) == B0) {
669
		dbg("%s: baud was B0", __func__);
670
		control_state |= TIOCM_DTR | TIOCM_RTS;
L
Linus Torvalds 已提交
671 672 673
		mct_u232_set_modem_ctrl(serial, control_state);
	}

A
Alan Cox 已提交
674
	mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty));
L
Linus Torvalds 已提交
675

A
Alan Cox 已提交
676
	if ((cflag & CBAUD) == B0) {
677
		dbg("%s: baud is B0", __func__);
L
Linus Torvalds 已提交
678 679
		/* Drop RTS and DTR */
		control_state &= ~(TIOCM_DTR | TIOCM_RTS);
A
Alan Cox 已提交
680
		mct_u232_set_modem_ctrl(serial, control_state);
L
Linus Torvalds 已提交
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
	}

	/*
	 * Update line control register (LCR)
	 */

	/* set the parity */
	if (cflag & PARENB)
		last_lcr |= (cflag & PARODD) ?
			MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
	else
		last_lcr |= MCT_U232_PARITY_NONE;

	/* set the number of data bits */
	switch (cflag & CSIZE) {
	case CS5:
		last_lcr |= MCT_U232_DATA_BITS_5; break;
	case CS6:
		last_lcr |= MCT_U232_DATA_BITS_6; break;
	case CS7:
		last_lcr |= MCT_U232_DATA_BITS_7; break;
	case CS8:
		last_lcr |= MCT_U232_DATA_BITS_8; break;
	default:
705 706
		dev_err(&port->dev,
			"CSIZE was not CS5-CS8, using default of 8\n");
L
Linus Torvalds 已提交
707 708 709 710
		last_lcr |= MCT_U232_DATA_BITS_8;
		break;
	}

711 712
	termios->c_cflag &= ~CMSPAR;

L
Linus Torvalds 已提交
713 714 715 716 717 718 719 720 721 722 723 724 725
	/* set the number of stop bits */
	last_lcr |= (cflag & CSTOPB) ?
		MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;

	mct_u232_set_line_ctrl(serial, last_lcr);

	/* save off the modified port settings */
	spin_lock_irqsave(&priv->lock, flags);
	priv->control_state = control_state;
	priv->last_lcr = last_lcr;
	spin_unlock_irqrestore(&priv->lock, flags);
} /* mct_u232_set_termios */

A
Alan Cox 已提交
726
static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
727
{
A
Alan Cox 已提交
728
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
729 730 731 732 733
	struct usb_serial *serial = port->serial;
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
	unsigned char lcr;
	unsigned long flags;

734
	dbg("%sstate=%d", __func__, break_state);
L
Linus Torvalds 已提交
735 736 737 738 739 740

	spin_lock_irqsave(&priv->lock, flags);
	lcr = priv->last_lcr;

	if (break_state)
		lcr |= MCT_U232_SET_BREAK;
741
	spin_unlock_irqrestore(&priv->lock, flags);
L
Linus Torvalds 已提交
742 743 744 745 746

	mct_u232_set_line_ctrl(serial, lcr);
} /* mct_u232_break_ctl */


747
static int mct_u232_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
748
{
A
Alan Cox 已提交
749
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
750 751 752
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
	unsigned int control_state;
	unsigned long flags;
A
Alan Cox 已提交
753

754
	dbg("%s", __func__);
L
Linus Torvalds 已提交
755 756 757 758 759 760 761 762

	spin_lock_irqsave(&priv->lock, flags);
	control_state = priv->control_state;
	spin_unlock_irqrestore(&priv->lock, flags);

	return control_state;
}

763
static int mct_u232_tiocmset(struct tty_struct *tty,
L
Linus Torvalds 已提交
764 765
			      unsigned int set, unsigned int clear)
{
A
Alan Cox 已提交
766
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
767 768 769 770
	struct usb_serial *serial = port->serial;
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
	unsigned int control_state;
	unsigned long flags;
A
Alan Cox 已提交
771

772
	dbg("%s", __func__);
L
Linus Torvalds 已提交
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790

	spin_lock_irqsave(&priv->lock, flags);
	control_state = priv->control_state;

	if (set & TIOCM_RTS)
		control_state |= TIOCM_RTS;
	if (set & TIOCM_DTR)
		control_state |= TIOCM_DTR;
	if (clear & TIOCM_RTS)
		control_state &= ~TIOCM_RTS;
	if (clear & TIOCM_DTR)
		control_state &= ~TIOCM_DTR;

	priv->control_state = control_state;
	spin_unlock_irqrestore(&priv->lock, flags);
	return mct_u232_set_modem_ctrl(serial, control_state);
}

A
Alan Cox 已提交
791
static void mct_u232_throttle(struct tty_struct *tty)
792
{
A
Alan Cox 已提交
793
	struct usb_serial_port *port = tty->driver_data;
794 795 796
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
	unsigned int control_state;

797
	dbg("%s - port %d", __func__, port->number);
798

799
	spin_lock_irq(&priv->lock);
800 801
	priv->rx_flags |= THROTTLED;
	if (C_CRTSCTS(tty)) {
A
Alan Cox 已提交
802 803
		priv->control_state &= ~TIOCM_RTS;
		control_state = priv->control_state;
804
		spin_unlock_irq(&priv->lock);
A
Alan Cox 已提交
805
		(void) mct_u232_set_modem_ctrl(port->serial, control_state);
806
	} else {
807
		spin_unlock_irq(&priv->lock);
808 809 810
	}
}

A
Alan Cox 已提交
811
static void mct_u232_unthrottle(struct tty_struct *tty)
812
{
A
Alan Cox 已提交
813
	struct usb_serial_port *port = tty->driver_data;
814 815 816
	struct mct_u232_private *priv = usb_get_serial_port_data(port);
	unsigned int control_state;

817
	dbg("%s - port %d", __func__, port->number);
818

819
	spin_lock_irq(&priv->lock);
820
	if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
A
Alan Cox 已提交
821 822 823
		priv->rx_flags &= ~THROTTLED;
		priv->control_state |= TIOCM_RTS;
		control_state = priv->control_state;
824
		spin_unlock_irq(&priv->lock);
A
Alan Cox 已提交
825
		(void) mct_u232_set_modem_ctrl(port->serial, control_state);
826
	} else {
827
		spin_unlock_irq(&priv->lock);
828 829
	}
}
L
Linus Torvalds 已提交
830

831
static int  mct_u232_ioctl(struct tty_struct *tty,
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
			unsigned int cmd, unsigned long arg)
{
	DEFINE_WAIT(wait);
	struct usb_serial_port *port = tty->driver_data;
	struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
	struct async_icount cnow, cprev;
	unsigned long flags;

	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);

	switch (cmd) {

	case TIOCMIWAIT:

		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);

		spin_lock_irqsave(&mct_u232_port->lock, flags);
		cprev = mct_u232_port->icount;
		spin_unlock_irqrestore(&mct_u232_port->lock, flags);
		for ( ; ; ) {
			prepare_to_wait(&mct_u232_port->msr_wait,
					&wait, TASK_INTERRUPTIBLE);
			schedule();
			finish_wait(&mct_u232_port->msr_wait, &wait);
			/* see if a signal did it */
			if (signal_pending(current))
				return -ERESTARTSYS;
			spin_lock_irqsave(&mct_u232_port->lock, flags);
			cnow = mct_u232_port->icount;
			spin_unlock_irqrestore(&mct_u232_port->lock, flags);
			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
				return -EIO; /* no change => error */
			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
				return 0;
			}
			cprev = cnow;
		}

	}
	return -ENOIOCTLCMD;
}

static int  mct_u232_get_icount(struct tty_struct *tty,
			struct serial_icounter_struct *icount)
{
	struct usb_serial_port *port = tty->driver_data;
	struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
	struct async_icount *ic = &mct_u232_port->icount;
	unsigned long flags;

	spin_lock_irqsave(&mct_u232_port->lock, flags);

	icount->cts = ic->cts;
	icount->dsr = ic->dsr;
	icount->rng = ic->rng;
	icount->dcd = ic->dcd;
	icount->rx = ic->rx;
	icount->tx = ic->tx;
	icount->frame = ic->frame;
	icount->overrun = ic->overrun;
	icount->parity = ic->parity;
	icount->brk = ic->brk;
	icount->buf_overrun = ic->buf_overrun;

	spin_unlock_irqrestore(&mct_u232_port->lock, flags);

	dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d",
		__func__,  port->number, icount->rx, icount->tx);
	return 0;
}

A
Alan Cox 已提交
907
static int __init mct_u232_init(void)
L
Linus Torvalds 已提交
908 909 910 911 912 913 914 915
{
	int retval;
	retval = usb_serial_register(&mct_u232_device);
	if (retval)
		goto failed_usb_serial_register;
	retval = usb_register(&mct_u232_driver);
	if (retval)
		goto failed_usb_register;
916 917
	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
	       DRIVER_DESC "\n");
L
Linus Torvalds 已提交
918 919 920 921 922 923 924 925
	return 0;
failed_usb_register:
	usb_serial_deregister(&mct_u232_device);
failed_usb_serial_register:
	return retval;
}


A
Alan Cox 已提交
926
static void __exit mct_u232_exit(void)
L
Linus Torvalds 已提交
927
{
A
Alan Cox 已提交
928 929
	usb_deregister(&mct_u232_driver);
	usb_serial_deregister(&mct_u232_device);
L
Linus Torvalds 已提交
930 931
}

A
Alan Cox 已提交
932
module_init(mct_u232_init);
L
Linus Torvalds 已提交
933 934
module_exit(mct_u232_exit);

A
Alan Cox 已提交
935 936
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
L
Linus Torvalds 已提交
937 938 939 940
MODULE_LICENSE("GPL");

module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");