kl5kusb105.c 17.8 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
 */
63 64
static int klsi_105_port_probe(struct usb_serial_port *port);
static int klsi_105_port_remove(struct usb_serial_port *port);
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
	.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,
102 103
	.port_probe =		klsi_105_port_probe,
	.port_remove =		klsi_105_port_remove,
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
 */

226
static int klsi_105_port_probe(struct usb_serial_port *port)
L
Linus Torvalds 已提交
227 228 229
{
	struct klsi_105_private *priv;

230 231 232
	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;
L
Linus Torvalds 已提交
233

234 235 236 237 238 239
	/* 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;
L
Linus Torvalds 已提交
240

241
	priv->line_state    = 0;
L
Linus Torvalds 已提交
242

243
	spin_lock_init(&priv->lock);
L
Linus Torvalds 已提交
244

245
	/* priv->termios is left uninitialized until port opening */
L
Linus Torvalds 已提交
246

247
	usb_set_serial_port_data(port, priv);
A
Alan Cox 已提交
248

249
	return 0;
J
Johan Hovold 已提交
250
}
L
Linus Torvalds 已提交
251

252
static int klsi_105_port_remove(struct usb_serial_port *port)
253
{
254
	struct klsi_105_private *priv;
255

256 257 258 259
	priv = usb_get_serial_port_data(port);
	kfree(priv);

	return 0;
J
Johan Hovold 已提交
260
}
L
Linus Torvalds 已提交
261

262
static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
L
Linus Torvalds 已提交
263 264 265 266 267 268
{
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
	int retval = 0;
	int rc;
	int i;
	unsigned long line_state;
269
	struct klsi_105_port_settings *cfg;
L
Linus Torvalds 已提交
270 271 272 273
	unsigned long flags;

	/* Do a defined restart:
	 * Set up sane default baud rate and send the 'READ_ON'
A
Alan Cox 已提交
274
	 * vendor command.
L
Linus Torvalds 已提交
275 276 277 278
	 * FIXME: set modem line control (how?)
	 * Then read the modem line control and store values in
	 * priv->line_state.
	 */
279 280 281 282 283 284 285 286 287 288 289 290
	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 已提交
291

L
Linus Torvalds 已提交
292
	/* set up termios structure */
A
Alan Cox 已提交
293
	spin_lock_irqsave(&priv->lock, flags);
294 295 296 297
	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 已提交
298
	for (i = 0; i < NCCS; i++)
299
		priv->termios.c_cc[i] = tty->termios.c_cc[i];
300 301 302 303 304
	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 已提交
305
	spin_unlock_irqrestore(&priv->lock, flags);
L
Linus Torvalds 已提交
306 307

	/* READ_ON and urb submission */
308
	rc = usb_serial_generic_open(tty, port);
L
Linus Torvalds 已提交
309 310 311 312 313 314
	if (rc) {
		retval = rc;
		goto exit;
	}

	rc = usb_control_msg(port->serial->dev,
A
Alan Cox 已提交
315
			     usb_sndctrlpipe(port->serial->dev, 0),
L
Linus Torvalds 已提交
316 317 318 319 320 321 322 323
			     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) {
324
		dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
L
Linus Torvalds 已提交
325
		retval = rc;
A
Alan Cox 已提交
326
	} else
327
		dev_dbg(&port->dev, "%s - enabled reading\n", __func__);
L
Linus Torvalds 已提交
328 329 330

	rc = klsi_105_get_line_state(port, &line_state);
	if (rc >= 0) {
A
Alan Cox 已提交
331
		spin_lock_irqsave(&priv->lock, flags);
L
Linus Torvalds 已提交
332
		priv->line_state = line_state;
A
Alan Cox 已提交
333
		spin_unlock_irqrestore(&priv->lock, flags);
334
		dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
L
Linus Torvalds 已提交
335 336 337 338 339
		retval = 0;
	} else
		retval = rc;

exit:
340
	kfree(cfg);
L
Linus Torvalds 已提交
341
	return retval;
J
Johan Hovold 已提交
342
}
L
Linus Torvalds 已提交
343

344
static void klsi_105_close(struct usb_serial_port *port)
L
Linus Torvalds 已提交
345 346 347
{
	int rc;

348 349 350
	mutex_lock(&port->serial->disc_mutex);
	if (!port->serial->disconnected) {
		/* send READ_OFF */
A
Alan Cox 已提交
351 352 353 354 355 356 357 358
		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);
359
		if (rc < 0)
360 361
			dev_err(&port->dev,
				"Disabling read failed (error = %d)\n", rc);
362 363
	}
	mutex_unlock(&port->serial->disc_mutex);
L
Linus Torvalds 已提交
364 365

	/* shutdown our bulk reads and writes */
366 367
	usb_serial_generic_close(port);

L
Linus Torvalds 已提交
368 369
	/* wgg - do I need this? I think so. */
	usb_kill_urb(port->interrupt_in_urb);
J
Johan Hovold 已提交
370
}
L
Linus Torvalds 已提交
371 372

/* We need to write a complete 64-byte data block and encode the
A
Alan Cox 已提交
373
 * number actually sent in the first double-byte, LSB-order. That
L
Linus Torvalds 已提交
374 375
 * leaves at most 62 bytes of payload.
 */
376 377 378
#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 已提交
379
{
380 381
	unsigned char *buf = dest;
	int count;
382

383 384 385
	count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
								&port->lock);
	put_unaligned_le16(count, buf);
L
Linus Torvalds 已提交
386

387
	return count + KLSI_HDR_LEN;
J
Johan Hovold 已提交
388
}
L
Linus Torvalds 已提交
389

390 391 392
/* 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 已提交
393
{
394
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
395
	unsigned char *data = urb->transfer_buffer;
396 397
	struct tty_struct *tty;
	unsigned len;
L
Linus Torvalds 已提交
398

399 400 401
	/* empty urbs seem to happen, we ignore them */
	if (!urb->actual_length)
		return;
L
Linus Torvalds 已提交
402

403
	if (urb->actual_length <= KLSI_HDR_LEN) {
404
		dev_dbg(&port->dev, "%s - malformed packet\n", __func__);
405 406 407
		return;
	}

408 409 410
	tty = tty_port_tty_get(&port->port);
	if (!tty)
		return;
L
Linus Torvalds 已提交
411

412 413
	len = get_unaligned_le16(data);
	if (len > urb->actual_length - KLSI_HDR_LEN) {
414
		dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__);
415
		len = urb->actual_length - KLSI_HDR_LEN;
L
Linus Torvalds 已提交
416
	}
417 418 419 420

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

A
Alan Cox 已提交
423 424 425
static void klsi_105_set_termios(struct tty_struct *tty,
				 struct usb_serial_port *port,
				 struct ktermios *old_termios)
L
Linus Torvalds 已提交
426 427
{
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
428
	struct device *dev = &port->dev;
429
	unsigned int iflag = tty->termios.c_iflag;
L
Linus Torvalds 已提交
430
	unsigned int old_iflag = old_termios->c_iflag;
431
	unsigned int cflag = tty->termios.c_cflag;
L
Linus Torvalds 已提交
432
	unsigned int old_cflag = old_termios->c_cflag;
433
	struct klsi_105_port_settings *cfg;
L
Linus Torvalds 已提交
434
	unsigned long flags;
435
	speed_t baud;
A
Alan Cox 已提交
436

437 438
	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
	if (!cfg) {
439
		dev_err(dev, "%s - out of memory for config buffer.\n", __func__);
440 441 442
		return;
	}

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

L
Linus Torvalds 已提交
446 447 448
	/*
	 * Update baud rate
	 */
449 450
	baud = tty_get_baud_rate(tty);

A
Alan Cox 已提交
451 452 453
	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
		/* reassert DTR and (maybe) RTS on transition from B0 */
		if ((old_cflag & CBAUD) == B0) {
454
			dev_dbg(dev, "%s: baud was B0\n", __func__);
L
Linus Torvalds 已提交
455 456 457
#if 0
			priv->control_state |= TIOCM_DTR;
			/* don't set RTS if using hardware flow control */
A
Alan Cox 已提交
458
			if (!(old_cflag & CRTSCTS))
L
Linus Torvalds 已提交
459 460 461 462
				priv->control_state |= TIOCM_RTS;
			mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
		}
463
	}
A
Alan Cox 已提交
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
	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:
492 493
		dev_dbg(dev, "KLSI USB->Serial converter: unsupported baudrate request, using default of 9600");
		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
A
Alan Cox 已提交
494 495
		baud = 9600;
		break;
496
	}
A
Alan Cox 已提交
497
	if ((cflag & CBAUD) == B0) {
498
		dev_dbg(dev, "%s: baud is B0\n", __func__);
499 500 501 502 503
		/* Drop RTS and DTR */
		/* maybe this should be simulated by sending read
		 * disable and read enable messages?
		 */
		;
L
Linus Torvalds 已提交
504
#if 0
505
		priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
A
Alan Cox 已提交
506
		mct_u232_set_modem_ctrl(serial, priv->control_state);
L
Linus Torvalds 已提交
507 508
#endif
	}
509
	tty_encode_baud_rate(tty, baud, baud);
L
Linus Torvalds 已提交
510 511 512 513 514

	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
		/* set the number of data bits */
		switch (cflag & CSIZE) {
		case CS5:
515
			dev_dbg(dev, "%s - 5 bits/byte not supported\n", __func__);
A
Alan Cox 已提交
516
			spin_unlock_irqrestore(&priv->lock, flags);
517
			goto err;
L
Linus Torvalds 已提交
518
		case CS6:
519
			dev_dbg(dev, "%s - 6 bits/byte not supported\n", __func__);
A
Alan Cox 已提交
520
			spin_unlock_irqrestore(&priv->lock, flags);
521
			goto err;
L
Linus Torvalds 已提交
522 523 524 525 526 527 528
		case CS7:
			priv->cfg.databits = kl5kusb105a_dtb_7;
			break;
		case CS8:
			priv->cfg.databits = kl5kusb105a_dtb_8;
			break;
		default:
529
			dev_err(dev, "CSIZE was not CS5-CS8, using default of 8\n");
L
Linus Torvalds 已提交
530 531 532 533 534 535 536 537 538
			priv->cfg.databits = kl5kusb105a_dtb_8;
			break;
		}
	}

	/*
	 * Update line control register (LCR)
	 */
	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
A
Alan Cox 已提交
539
	    || (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
540
		/* Not currently supported */
541
		tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB);
L
Linus Torvalds 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
#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 已提交
564
	if ((iflag & IXOFF) != (old_iflag & IXOFF)
L
Linus Torvalds 已提交
565
	    || (iflag & IXON) != (old_iflag & IXON)
A
Alan Cox 已提交
566
	    ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
567
		/* Not currently supported */
568
		tty->termios.c_cflag &= ~CRTSCTS;
L
Linus Torvalds 已提交
569 570
		/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
A
Alan Cox 已提交
571
		if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
L
Linus Torvalds 已提交
572 573 574 575 576 577 578
			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
		;
	}
579
	memcpy(cfg, &priv->cfg, sizeof(*cfg));
A
Alan Cox 已提交
580 581
	spin_unlock_irqrestore(&priv->lock, flags);

L
Linus Torvalds 已提交
582
	/* now commit changes to device */
583 584 585
	klsi_105_chg_port_settings(port, cfg);
err:
	kfree(cfg);
J
Johan Hovold 已提交
586
}
L
Linus Torvalds 已提交
587 588

#if 0
A
Alan Cox 已提交
589
static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
590
{
A
Alan Cox 已提交
591
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
592
	struct usb_serial *serial = port->serial;
A
Alan Cox 已提交
593 594
	struct mct_u232_private *priv =
				(struct mct_u232_private *)port->private;
L
Linus Torvalds 已提交
595 596
	unsigned char lcr = priv->last_lcr;

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

599
	/* LOCKING */
L
Linus Torvalds 已提交
600 601 602 603
	if (break_state)
		lcr |= MCT_U232_SET_BREAK;

	mct_u232_set_line_ctrl(serial, lcr);
J
Johan Hovold 已提交
604
}
L
Linus Torvalds 已提交
605 606
#endif

607
static int klsi_105_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
608
{
A
Alan Cox 已提交
609
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
610 611 612 613 614 615 616
	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) {
617 618
		dev_err(&port->dev,
			"Reading line control failed (error = %d)\n", rc);
L
Linus Torvalds 已提交
619 620 621 622
		/* better return value? EAGAIN? */
		return rc;
	}

A
Alan Cox 已提交
623
	spin_lock_irqsave(&priv->lock, flags);
L
Linus Torvalds 已提交
624
	priv->line_state = line_state;
A
Alan Cox 已提交
625
	spin_unlock_irqrestore(&priv->lock, flags);
626
	dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
L
Linus Torvalds 已提交
627 628 629
	return (int)line_state;
}

630
static int klsi_105_tiocmset(struct tty_struct *tty,
A
Alan Cox 已提交
631
			     unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
632 633
{
	int retval = -EINVAL;
A
Alan Cox 已提交
634

L
Linus Torvalds 已提交
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
/* 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;
}

657
module_usb_serial_driver(serial_drivers, id_table);
L
Linus Torvalds 已提交
658

A
Alan Cox 已提交
659 660 661
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");