kl5kusb105.c 18.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * KLSI KL5KUSB105 chip RS232 converter driver
 *
4
 *   Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *   Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
 *
 *   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.
 *
 * All information about the device was acquired using SniffUSB ans snoopUSB
 * on Windows98.
 * It was written out of frustration with the PalmConnect USB Serial adapter
 * sold by Palm Inc.
 * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided
 * information that was not already available.
 *
A
Alan Cox 已提交
19
 * It seems that KLSI bought some silicon-design information from ScanLogic,
L
Linus Torvalds 已提交
20 21 22
 * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI.
 * KLSI has firmware available for their devices; it is probable that the
 * firmware differs from that used by KLSI in their products. If you have an
A
Alan Cox 已提交
23 24
 * original KLSI device and can provide some information on it, I would be
 * most interested in adding support for it here. If you have any information
L
Linus Torvalds 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 * on the protocol used (or find errors in my reverse-engineered stuff), please
 * let me know.
 *
 * The code was only tested with a PalmConnect USB adapter; if you
 * are adventurous, try it with any KLSI-based device and let me know how it
 * breaks so that I can fix it!
 */

/* TODO:
 *	check modem line signals
 *	implement handshaking or decide that we do not support it
 */

#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>
A
Alan Cox 已提交
46
#include <linux/uaccess.h>
A
Al Viro 已提交
47
#include <asm/unaligned.h>
L
Linus Torvalds 已提交
48
#include <linux/usb.h>
49
#include <linux/usb/serial.h>
L
Linus Torvalds 已提交
50 51 52 53 54
#include "kl5kusb105.h"

/*
 * Version Information
 */
55 56
#define DRIVER_VERSION "v0.4"
#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>"
L
Linus Torvalds 已提交
57 58 59 60 61 62
#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"


/*
 * Function prototypes
 */
A
Alan Cox 已提交
63
static int  klsi_105_startup(struct usb_serial *serial);
64
static void klsi_105_release(struct usb_serial *serial);
65
static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
66
static void klsi_105_close(struct usb_serial_port *port);
A
Alan Cox 已提交
67 68
static void klsi_105_set_termios(struct tty_struct *tty,
			struct usb_serial_port *port, struct ktermios *old);
69
static int  klsi_105_tiocmget(struct tty_struct *tty);
70
static int  klsi_105_tiocmset(struct tty_struct *tty,
A
Alan Cox 已提交
71
			unsigned int set, unsigned int clear);
72 73 74
static void klsi_105_process_read_urb(struct urb *urb);
static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
						void *dest, size_t size);
L
Linus Torvalds 已提交
75 76 77 78

/*
 * All of the device info needed for the KLSI converters.
 */
79
static const struct usb_device_id id_table[] = {
L
Linus Torvalds 已提交
80 81 82 83 84
	{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
	{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
	{ }		/* Terminating entry */
};

A
Alan Cox 已提交
85
MODULE_DEVICE_TABLE(usb, id_table);
L
Linus Torvalds 已提交
86

87
static struct usb_serial_driver kl5kusb105d_device = {
88 89
	.driver = {
		.owner =	THIS_MODULE,
90
		.name =		"kl5kusb105d",
91
	},
J
Johan Hovold 已提交
92 93 94
	.description =		"KL5KUSB105D / PalmConnect",
	.id_table =		id_table,
	.num_ports =		1,
95
	.bulk_out_size =	64,
J
Johan Hovold 已提交
96 97 98 99 100 101 102 103
	.open =			klsi_105_open,
	.close =		klsi_105_close,
	.set_termios =		klsi_105_set_termios,
	/*.break_ctl =		klsi_105_break_ctl,*/
	.tiocmget =		klsi_105_tiocmget,
	.tiocmset =		klsi_105_tiocmset,
	.attach =		klsi_105_startup,
	.release =		klsi_105_release,
104 105 106 107
	.throttle =		usb_serial_generic_throttle,
	.unthrottle =		usb_serial_generic_unthrottle,
	.process_read_urb =	klsi_105_process_read_urb,
	.prepare_write_buffer =	klsi_105_prepare_write_buffer,
L
Linus Torvalds 已提交
108 109
};

110 111 112 113
static struct usb_serial_driver * const serial_drivers[] = {
	&kl5kusb105d_device, NULL
};

L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122 123
struct klsi_105_port_settings {
	__u8	pktlen;		/* always 5, it seems */
	__u8	baudrate;
	__u8	databits;
	__u8	unknown1;
	__u8	unknown2;
} __attribute__ ((packed));

struct klsi_105_private {
	struct klsi_105_port_settings	cfg;
A
Alan Cox 已提交
124
	struct ktermios			termios;
L
Linus Torvalds 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	unsigned long			line_state; /* modem line settings */
	spinlock_t			lock;
};


/*
 * Handle vendor specific USB requests
 */


#define KLSI_TIMEOUT	 5000 /* default urb timeout */

static int klsi_105_chg_port_settings(struct usb_serial_port *port,
				      struct klsi_105_port_settings *settings)
{
	int rc;

A
Alan Cox 已提交
142 143 144 145 146 147 148 149 150
	rc = usb_control_msg(port->serial->dev,
			usb_sndctrlpipe(port->serial->dev, 0),
			KL5KUSB105A_SIO_SET_DATA,
			USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE,
			0, /* value */
			0, /* index */
			settings,
			sizeof(struct klsi_105_port_settings),
			KLSI_TIMEOUT);
L
Linus Torvalds 已提交
151
	if (rc < 0)
152 153
		dev_err(&port->dev,
			"Change port settings failed (error = %d)\n", rc);
154 155 156 157
	dev_info(&port->serial->dev->dev,
		 "%d byte block, baudrate %x, databits %d, u1 %d, u2 %d\n",
		 settings->pktlen, settings->baudrate, settings->databits,
		 settings->unknown1, settings->unknown2);
A
Alan Cox 已提交
158
	return rc;
J
Johan Hovold 已提交
159
}
L
Linus Torvalds 已提交
160 161 162 163 164 165 166 167 168 169 170 171

/* translate a 16-bit status value from the device to linux's TIO bits */
static unsigned long klsi_105_status2linestate(const __u16 status)
{
	unsigned long res = 0;

	res =   ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0)
	      | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0)
	      ;

	return res;
}
J
Johan Hovold 已提交
172

A
Alan Cox 已提交
173
/*
L
Linus Torvalds 已提交
174
 * Read line control via vendor command and return result through
A
Alan Cox 已提交
175
 * *line_state_p
L
Linus Torvalds 已提交
176 177 178 179 180 181 182
 */
/* It seems that the status buffer has always only 2 bytes length */
#define KLSI_STATUSBUF_LEN	2
static int klsi_105_get_line_state(struct usb_serial_port *port,
				   unsigned long *line_state_p)
{
	int rc;
183
	u8 *status_buf;
L
Linus Torvalds 已提交
184 185
	__u16 status;

186
	dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
187 188 189 190 191 192 193 194 195

	status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL);
	if (!status_buf) {
		dev_err(&port->dev, "%s - out of memory for status buffer.\n",
				__func__);
		return -ENOMEM;
	}
	status_buf[0] = 0xff;
	status_buf[1] = 0xff;
A
Alan Cox 已提交
196
	rc = usb_control_msg(port->serial->dev,
L
Linus Torvalds 已提交
197 198
			     usb_rcvctrlpipe(port->serial->dev, 0),
			     KL5KUSB105A_SIO_POLL,
A
Alan Cox 已提交
199
			     USB_TYPE_VENDOR | USB_DIR_IN,
L
Linus Torvalds 已提交
200 201 202 203 204 205
			     0, /* value */
			     0, /* index */
			     status_buf, KLSI_STATUSBUF_LEN,
			     10000
			     );
	if (rc < 0)
206 207
		dev_err(&port->dev, "Reading line status failed (error = %d)\n",
			rc);
L
Linus Torvalds 已提交
208
	else {
209
		status = get_unaligned_le16(status_buf);
L
Linus Torvalds 已提交
210

211 212
		dev_info(&port->serial->dev->dev, "read status %x %x",
			 status_buf[0], status_buf[1]);
L
Linus Torvalds 已提交
213 214 215

		*line_state_p = klsi_105_status2linestate(status);
	}
216 217

	kfree(status_buf);
A
Alan Cox 已提交
218
	return rc;
L
Linus Torvalds 已提交
219 220 221 222 223 224 225
}


/*
 * Driver's tty interface functions
 */

A
Alan Cox 已提交
226
static int klsi_105_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
227 228
{
	struct klsi_105_private *priv;
229
	int i;
L
Linus Torvalds 已提交
230 231 232 233 234 235

	/* check if we support the product id (see keyspan.c)
	 * FIXME
	 */

	/* allocate the private data structure */
A
Alan Cox 已提交
236
	for (i = 0; i < serial->num_ports; i++) {
L
Linus Torvalds 已提交
237 238 239
		priv = kmalloc(sizeof(struct klsi_105_private),
						   GFP_KERNEL);
		if (!priv) {
240 241 242
			dev_dbg(&serial->interface->dev,
				"%s - kmalloc for klsi_105_private failed.\n",
				__func__);
243 244
			i--;
			goto err_cleanup;
L
Linus Torvalds 已提交
245 246 247 248 249 250 251 252 253 254 255 256
		}
		/* set initial values for control structures */
		priv->cfg.pktlen    = 5;
		priv->cfg.baudrate  = kl5kusb105a_sio_b9600;
		priv->cfg.databits  = kl5kusb105a_dtb_8;
		priv->cfg.unknown1  = 0;
		priv->cfg.unknown2  = 1;

		priv->line_state    = 0;

		usb_set_serial_port_data(serial->port[i], priv);

A
Alan Cox 已提交
257
		spin_lock_init(&priv->lock);
L
Linus Torvalds 已提交
258

259
		/* priv->termios is left uninitialized until port opening */
L
Linus Torvalds 已提交
260 261
		init_waitqueue_head(&serial->port[i]->write_wait);
	}
A
Alan Cox 已提交
262

263 264 265 266 267
	return 0;

err_cleanup:
	for (; i >= 0; i--) {
		priv = usb_get_serial_port_data(serial->port[i]);
J
Johan Hovold 已提交
268
		kfree(priv);
269 270 271
		usb_set_serial_port_data(serial->port[i], NULL);
	}
	return -ENOMEM;
J
Johan Hovold 已提交
272
}
L
Linus Torvalds 已提交
273

274 275 276 277
static void klsi_105_release(struct usb_serial *serial)
{
	int i;

278 279
	for (i = 0; i < serial->num_ports; ++i)
		kfree(usb_get_serial_port_data(serial->port[i]));
J
Johan Hovold 已提交
280
}
L
Linus Torvalds 已提交
281

282
static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
L
Linus Torvalds 已提交
283 284 285 286 287 288
{
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
	int retval = 0;
	int rc;
	int i;
	unsigned long line_state;
289
	struct klsi_105_port_settings *cfg;
L
Linus Torvalds 已提交
290 291 292 293
	unsigned long flags;

	/* Do a defined restart:
	 * Set up sane default baud rate and send the 'READ_ON'
A
Alan Cox 已提交
294
	 * vendor command.
L
Linus Torvalds 已提交
295 296 297 298
	 * FIXME: set modem line control (how?)
	 * Then read the modem line control and store values in
	 * priv->line_state.
	 */
299 300 301 302 303 304 305 306 307 308 309 310
	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
	if (!cfg) {
		dev_err(&port->dev, "%s - out of memory for config buffer.\n",
				__func__);
		return -ENOMEM;
	}
	cfg->pktlen   = 5;
	cfg->baudrate = kl5kusb105a_sio_b9600;
	cfg->databits = kl5kusb105a_dtb_8;
	cfg->unknown1 = 0;
	cfg->unknown2 = 1;
	klsi_105_chg_port_settings(port, cfg);
A
Alan Cox 已提交
311

L
Linus Torvalds 已提交
312
	/* set up termios structure */
A
Alan Cox 已提交
313
	spin_lock_irqsave(&priv->lock, flags);
314 315 316 317
	priv->termios.c_iflag = tty->termios.c_iflag;
	priv->termios.c_oflag = tty->termios.c_oflag;
	priv->termios.c_cflag = tty->termios.c_cflag;
	priv->termios.c_lflag = tty->termios.c_lflag;
A
Alan Cox 已提交
318
	for (i = 0; i < NCCS; i++)
319
		priv->termios.c_cc[i] = tty->termios.c_cc[i];
320 321 322 323 324
	priv->cfg.pktlen   = cfg->pktlen;
	priv->cfg.baudrate = cfg->baudrate;
	priv->cfg.databits = cfg->databits;
	priv->cfg.unknown1 = cfg->unknown1;
	priv->cfg.unknown2 = cfg->unknown2;
A
Alan Cox 已提交
325
	spin_unlock_irqrestore(&priv->lock, flags);
L
Linus Torvalds 已提交
326 327

	/* READ_ON and urb submission */
328
	rc = usb_serial_generic_open(tty, port);
L
Linus Torvalds 已提交
329 330 331 332 333 334
	if (rc) {
		retval = rc;
		goto exit;
	}

	rc = usb_control_msg(port->serial->dev,
A
Alan Cox 已提交
335
			     usb_sndctrlpipe(port->serial->dev, 0),
L
Linus Torvalds 已提交
336 337 338 339 340 341 342 343
			     KL5KUSB105A_SIO_CONFIGURE,
			     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
			     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
			     0, /* index */
			     NULL,
			     0,
			     KLSI_TIMEOUT);
	if (rc < 0) {
344
		dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
L
Linus Torvalds 已提交
345
		retval = rc;
A
Alan Cox 已提交
346
	} else
347
		dev_dbg(&port->dev, "%s - enabled reading\n", __func__);
L
Linus Torvalds 已提交
348 349 350

	rc = klsi_105_get_line_state(port, &line_state);
	if (rc >= 0) {
A
Alan Cox 已提交
351
		spin_lock_irqsave(&priv->lock, flags);
L
Linus Torvalds 已提交
352
		priv->line_state = line_state;
A
Alan Cox 已提交
353
		spin_unlock_irqrestore(&priv->lock, flags);
354
		dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
L
Linus Torvalds 已提交
355 356 357 358 359
		retval = 0;
	} else
		retval = rc;

exit:
360
	kfree(cfg);
L
Linus Torvalds 已提交
361
	return retval;
J
Johan Hovold 已提交
362
}
L
Linus Torvalds 已提交
363

364
static void klsi_105_close(struct usb_serial_port *port)
L
Linus Torvalds 已提交
365 366 367
{
	int rc;

368 369 370
	mutex_lock(&port->serial->disc_mutex);
	if (!port->serial->disconnected) {
		/* send READ_OFF */
A
Alan Cox 已提交
371 372 373 374 375 376 377 378
		rc = usb_control_msg(port->serial->dev,
				     usb_sndctrlpipe(port->serial->dev, 0),
				     KL5KUSB105A_SIO_CONFIGURE,
				     USB_TYPE_VENDOR | USB_DIR_OUT,
				     KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
				     0, /* index */
				     NULL, 0,
				     KLSI_TIMEOUT);
379
		if (rc < 0)
380 381
			dev_err(&port->dev,
				"Disabling read failed (error = %d)\n", rc);
382 383
	}
	mutex_unlock(&port->serial->disc_mutex);
L
Linus Torvalds 已提交
384 385

	/* shutdown our bulk reads and writes */
386 387
	usb_serial_generic_close(port);

L
Linus Torvalds 已提交
388 389
	/* wgg - do I need this? I think so. */
	usb_kill_urb(port->interrupt_in_urb);
J
Johan Hovold 已提交
390
}
L
Linus Torvalds 已提交
391 392

/* We need to write a complete 64-byte data block and encode the
A
Alan Cox 已提交
393
 * number actually sent in the first double-byte, LSB-order. That
L
Linus Torvalds 已提交
394 395
 * leaves at most 62 bytes of payload.
 */
396 397 398
#define KLSI_HDR_LEN		2
static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
						void *dest, size_t size)
L
Linus Torvalds 已提交
399
{
400 401
	unsigned char *buf = dest;
	int count;
402

403 404 405
	count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
								&port->lock);
	put_unaligned_le16(count, buf);
L
Linus Torvalds 已提交
406

407
	return count + KLSI_HDR_LEN;
J
Johan Hovold 已提交
408
}
L
Linus Torvalds 已提交
409

410 411 412
/* The data received is preceded by a length double-byte in LSB-first order.
 */
static void klsi_105_process_read_urb(struct urb *urb)
L
Linus Torvalds 已提交
413
{
414
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
415
	unsigned char *data = urb->transfer_buffer;
416 417
	struct tty_struct *tty;
	unsigned len;
L
Linus Torvalds 已提交
418

419 420 421
	/* empty urbs seem to happen, we ignore them */
	if (!urb->actual_length)
		return;
L
Linus Torvalds 已提交
422

423
	if (urb->actual_length <= KLSI_HDR_LEN) {
424
		dev_dbg(&port->dev, "%s - malformed packet\n", __func__);
425 426 427
		return;
	}

428 429 430
	tty = tty_port_tty_get(&port->port);
	if (!tty)
		return;
L
Linus Torvalds 已提交
431

432 433
	len = get_unaligned_le16(data);
	if (len > urb->actual_length - KLSI_HDR_LEN) {
434
		dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__);
435
		len = urb->actual_length - KLSI_HDR_LEN;
L
Linus Torvalds 已提交
436
	}
437 438 439 440

	tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len);
	tty_flip_buffer_push(tty);
	tty_kref_put(tty);
J
Johan Hovold 已提交
441
}
L
Linus Torvalds 已提交
442

A
Alan Cox 已提交
443 444 445
static void klsi_105_set_termios(struct tty_struct *tty,
				 struct usb_serial_port *port,
				 struct ktermios *old_termios)
L
Linus Torvalds 已提交
446 447
{
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
448
	struct device *dev = &port->dev;
449
	unsigned int iflag = tty->termios.c_iflag;
L
Linus Torvalds 已提交
450
	unsigned int old_iflag = old_termios->c_iflag;
451
	unsigned int cflag = tty->termios.c_cflag;
L
Linus Torvalds 已提交
452
	unsigned int old_cflag = old_termios->c_cflag;
453
	struct klsi_105_port_settings *cfg;
L
Linus Torvalds 已提交
454
	unsigned long flags;
455
	speed_t baud;
A
Alan Cox 已提交
456

457 458
	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
	if (!cfg) {
459
		dev_err(dev, "%s - out of memory for config buffer.\n", __func__);
460 461 462
		return;
	}

L
Linus Torvalds 已提交
463
	/* lock while we are modifying the settings */
A
Alan Cox 已提交
464 465
	spin_lock_irqsave(&priv->lock, flags);

L
Linus Torvalds 已提交
466 467 468
	/*
	 * Update baud rate
	 */
469 470
	baud = tty_get_baud_rate(tty);

A
Alan Cox 已提交
471 472 473
	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
		/* reassert DTR and (maybe) RTS on transition from B0 */
		if ((old_cflag & CBAUD) == B0) {
474
			dev_dbg(dev, "%s: baud was B0\n", __func__);
L
Linus Torvalds 已提交
475 476 477
#if 0
			priv->control_state |= TIOCM_DTR;
			/* don't set RTS if using hardware flow control */
A
Alan Cox 已提交
478
			if (!(old_cflag & CRTSCTS))
L
Linus Torvalds 已提交
479 480 481 482
				priv->control_state |= TIOCM_RTS;
			mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
		}
483
	}
A
Alan Cox 已提交
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
	switch (baud) {
	case 0: /* handled below */
		break;
	case 1200:
		priv->cfg.baudrate = kl5kusb105a_sio_b1200;
		break;
	case 2400:
		priv->cfg.baudrate = kl5kusb105a_sio_b2400;
		break;
	case 4800:
		priv->cfg.baudrate = kl5kusb105a_sio_b4800;
		break;
	case 9600:
		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
		break;
	case 19200:
		priv->cfg.baudrate = kl5kusb105a_sio_b19200;
		break;
	case 38400:
		priv->cfg.baudrate = kl5kusb105a_sio_b38400;
		break;
	case 57600:
		priv->cfg.baudrate = kl5kusb105a_sio_b57600;
		break;
	case 115200:
		priv->cfg.baudrate = kl5kusb105a_sio_b115200;
		break;
	default:
512 513
		dev_dbg(dev, "KLSI USB->Serial converter: unsupported baudrate request, using default of 9600");
		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
A
Alan Cox 已提交
514 515
		baud = 9600;
		break;
516
	}
A
Alan Cox 已提交
517
	if ((cflag & CBAUD) == B0) {
518
		dev_dbg(dev, "%s: baud is B0\n", __func__);
519 520 521 522 523
		/* Drop RTS and DTR */
		/* maybe this should be simulated by sending read
		 * disable and read enable messages?
		 */
		;
L
Linus Torvalds 已提交
524
#if 0
525
		priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
A
Alan Cox 已提交
526
		mct_u232_set_modem_ctrl(serial, priv->control_state);
L
Linus Torvalds 已提交
527 528
#endif
	}
529
	tty_encode_baud_rate(tty, baud, baud);
L
Linus Torvalds 已提交
530 531 532 533 534

	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
		/* set the number of data bits */
		switch (cflag & CSIZE) {
		case CS5:
535
			dev_dbg(dev, "%s - 5 bits/byte not supported\n", __func__);
A
Alan Cox 已提交
536
			spin_unlock_irqrestore(&priv->lock, flags);
537
			goto err;
L
Linus Torvalds 已提交
538
		case CS6:
539
			dev_dbg(dev, "%s - 6 bits/byte not supported\n", __func__);
A
Alan Cox 已提交
540
			spin_unlock_irqrestore(&priv->lock, flags);
541
			goto err;
L
Linus Torvalds 已提交
542 543 544 545 546 547 548
		case CS7:
			priv->cfg.databits = kl5kusb105a_dtb_7;
			break;
		case CS8:
			priv->cfg.databits = kl5kusb105a_dtb_8;
			break;
		default:
549
			dev_err(dev, "CSIZE was not CS5-CS8, using default of 8\n");
L
Linus Torvalds 已提交
550 551 552 553 554 555 556 557 558
			priv->cfg.databits = kl5kusb105a_dtb_8;
			break;
		}
	}

	/*
	 * Update line control register (LCR)
	 */
	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
A
Alan Cox 已提交
559
	    || (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
560
		/* Not currently supported */
561
		tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB);
L
Linus Torvalds 已提交
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
#if 0
		priv->last_lcr = 0;

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

		/* set the number of stop bits */
		priv->last_lcr |= (cflag & CSTOPB) ?
			MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;

		mct_u232_set_line_ctrl(serial, priv->last_lcr);
#endif
		;
	}
	/*
	 * Set flow control: well, I do not really now how to handle DTR/RTS.
	 * Just do what we have seen with SniffUSB on Win98.
	 */
A
Alan Cox 已提交
584
	if ((iflag & IXOFF) != (old_iflag & IXOFF)
L
Linus Torvalds 已提交
585
	    || (iflag & IXON) != (old_iflag & IXON)
A
Alan Cox 已提交
586
	    ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
587
		/* Not currently supported */
588
		tty->termios.c_cflag &= ~CRTSCTS;
L
Linus Torvalds 已提交
589 590
		/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
A
Alan Cox 已提交
591
		if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
L
Linus Torvalds 已提交
592 593 594 595 596 597 598
			priv->control_state |= TIOCM_DTR | TIOCM_RTS;
		else
			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
		mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
		;
	}
599
	memcpy(cfg, &priv->cfg, sizeof(*cfg));
A
Alan Cox 已提交
600 601
	spin_unlock_irqrestore(&priv->lock, flags);

L
Linus Torvalds 已提交
602
	/* now commit changes to device */
603 604 605
	klsi_105_chg_port_settings(port, cfg);
err:
	kfree(cfg);
J
Johan Hovold 已提交
606
}
L
Linus Torvalds 已提交
607 608

#if 0
A
Alan Cox 已提交
609
static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
610
{
A
Alan Cox 已提交
611
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
612
	struct usb_serial *serial = port->serial;
A
Alan Cox 已提交
613 614
	struct mct_u232_private *priv =
				(struct mct_u232_private *)port->private;
L
Linus Torvalds 已提交
615 616
	unsigned char lcr = priv->last_lcr;

617
	dev_dbg(&port->dev, "%s - state=%d\n", __func__, break_state);
L
Linus Torvalds 已提交
618

619
	/* LOCKING */
L
Linus Torvalds 已提交
620 621 622 623
	if (break_state)
		lcr |= MCT_U232_SET_BREAK;

	mct_u232_set_line_ctrl(serial, lcr);
J
Johan Hovold 已提交
624
}
L
Linus Torvalds 已提交
625 626
#endif

627
static int klsi_105_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
628
{
A
Alan Cox 已提交
629
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
630 631 632 633 634 635 636
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	int rc;
	unsigned long line_state;

	rc = klsi_105_get_line_state(port, &line_state);
	if (rc < 0) {
637 638
		dev_err(&port->dev,
			"Reading line control failed (error = %d)\n", rc);
L
Linus Torvalds 已提交
639 640 641 642
		/* better return value? EAGAIN? */
		return rc;
	}

A
Alan Cox 已提交
643
	spin_lock_irqsave(&priv->lock, flags);
L
Linus Torvalds 已提交
644
	priv->line_state = line_state;
A
Alan Cox 已提交
645
	spin_unlock_irqrestore(&priv->lock, flags);
646
	dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
L
Linus Torvalds 已提交
647 648 649
	return (int)line_state;
}

650
static int klsi_105_tiocmset(struct tty_struct *tty,
A
Alan Cox 已提交
651
			     unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
652 653
{
	int retval = -EINVAL;
A
Alan Cox 已提交
654

L
Linus Torvalds 已提交
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
/* if this ever gets implemented, it should be done something like this:
	struct usb_serial *serial = port->serial;
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	int control;

	spin_lock_irqsave (&priv->lock, flags);
	if (set & TIOCM_RTS)
		priv->control_state |= TIOCM_RTS;
	if (set & TIOCM_DTR)
		priv->control_state |= TIOCM_DTR;
	if (clear & TIOCM_RTS)
		priv->control_state &= ~TIOCM_RTS;
	if (clear & TIOCM_DTR)
		priv->control_state &= ~TIOCM_DTR;
	control = priv->control_state;
	spin_unlock_irqrestore (&priv->lock, flags);
	retval = mct_u232_set_modem_ctrl(serial, control);
*/
	return retval;
}

677
module_usb_serial_driver(serial_drivers, id_table);
L
Linus Torvalds 已提交
678

A
Alan Cox 已提交
679 680 681
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");