kl5kusb105.c 19.2 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 55 56
#include "kl5kusb105.h"

static int debug;

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


/*
 * Function prototypes
 */
A
Alan Cox 已提交
65
static int  klsi_105_startup(struct usb_serial *serial);
66
static void klsi_105_release(struct usb_serial *serial);
67
static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
68
static void klsi_105_close(struct usb_serial_port *port);
A
Alan Cox 已提交
69 70 71 72 73
static void klsi_105_set_termios(struct tty_struct *tty,
			struct usb_serial_port *port, struct ktermios *old);
static int  klsi_105_tiocmget(struct tty_struct *tty, struct file *file);
static int  klsi_105_tiocmset(struct tty_struct *tty, struct file *file,
			unsigned int set, unsigned int clear);
74 75 76
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 已提交
77 78 79 80

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

A
Alan Cox 已提交
87
MODULE_DEVICE_TABLE(usb, id_table);
L
Linus Torvalds 已提交
88 89 90 91 92 93

static struct usb_driver kl5kusb105d_driver = {
	.name =		"kl5kusb105d",
	.probe =	usb_serial_probe,
	.disconnect =	usb_serial_disconnect,
	.id_table =	id_table,
J
Johan Hovold 已提交
94
	.no_dynamic_id =	1,
L
Linus Torvalds 已提交
95 96
};

97
static struct usb_serial_driver kl5kusb105d_device = {
98 99
	.driver = {
		.owner =	THIS_MODULE,
100
		.name =		"kl5kusb105d",
101
	},
J
Johan Hovold 已提交
102 103 104 105
	.description =		"KL5KUSB105D / PalmConnect",
	.usb_driver =		&kl5kusb105d_driver,
	.id_table =		id_table,
	.num_ports =		1,
106
	.bulk_out_size =	64,
J
Johan Hovold 已提交
107 108 109 110 111 112 113 114
	.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,
115 116 117 118
	.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 已提交
119 120 121 122 123 124 125 126 127 128 129 130
};

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 已提交
131
	struct ktermios			termios;
L
Linus Torvalds 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
	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 已提交
149 150 151 152 153 154 155 156 157
	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 已提交
158
	if (rc < 0)
159 160
		dev_err(&port->dev,
			"Change port settings failed (error = %d)\n", rc);
161 162 163 164
	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 已提交
165
	return rc;
J
Johan Hovold 已提交
166
}
L
Linus Torvalds 已提交
167 168 169 170 171 172 173 174 175 176 177 178

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

A
Alan Cox 已提交
180
/*
L
Linus Torvalds 已提交
181
 * Read line control via vendor command and return result through
A
Alan Cox 已提交
182
 * *line_state_p
L
Linus Torvalds 已提交
183 184 185 186 187 188 189
 */
/* 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;
190
	u8 *status_buf;
L
Linus Torvalds 已提交
191 192
	__u16 status;

193
	dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
194 195 196 197 198 199 200 201 202

	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 已提交
203
	rc = usb_control_msg(port->serial->dev,
L
Linus Torvalds 已提交
204 205
			     usb_rcvctrlpipe(port->serial->dev, 0),
			     KL5KUSB105A_SIO_POLL,
A
Alan Cox 已提交
206
			     USB_TYPE_VENDOR | USB_DIR_IN,
L
Linus Torvalds 已提交
207 208 209 210 211 212
			     0, /* value */
			     0, /* index */
			     status_buf, KLSI_STATUSBUF_LEN,
			     10000
			     );
	if (rc < 0)
213 214
		dev_err(&port->dev, "Reading line status failed (error = %d)\n",
			rc);
L
Linus Torvalds 已提交
215
	else {
216
		status = get_unaligned_le16(status_buf);
L
Linus Torvalds 已提交
217

218 219
		dev_info(&port->serial->dev->dev, "read status %x %x",
			 status_buf[0], status_buf[1]);
L
Linus Torvalds 已提交
220 221 222

		*line_state_p = klsi_105_status2linestate(status);
	}
223 224

	kfree(status_buf);
A
Alan Cox 已提交
225
	return rc;
L
Linus Torvalds 已提交
226 227 228 229 230 231 232
}


/*
 * Driver's tty interface functions
 */

A
Alan Cox 已提交
233
static int klsi_105_startup(struct usb_serial *serial)
L
Linus Torvalds 已提交
234 235
{
	struct klsi_105_private *priv;
236
	int i;
L
Linus Torvalds 已提交
237 238 239 240 241 242

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

	/* allocate the private data structure */
A
Alan Cox 已提交
243
	for (i = 0; i < serial->num_ports; i++) {
L
Linus Torvalds 已提交
244 245 246
		priv = kmalloc(sizeof(struct klsi_105_private),
						   GFP_KERNEL);
		if (!priv) {
247
			dbg("%skmalloc for klsi_105_private failed.", __func__);
248 249
			i--;
			goto err_cleanup;
L
Linus Torvalds 已提交
250 251 252 253 254 255 256 257 258 259 260 261
		}
		/* 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 已提交
262
		spin_lock_init(&priv->lock);
L
Linus Torvalds 已提交
263

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

268 269 270 271 272
	return 0;

err_cleanup:
	for (; i >= 0; i--) {
		priv = usb_get_serial_port_data(serial->port[i]);
J
Johan Hovold 已提交
273
		kfree(priv);
274 275 276
		usb_set_serial_port_data(serial->port[i], NULL);
	}
	return -ENOMEM;
J
Johan Hovold 已提交
277
}
L
Linus Torvalds 已提交
278

279 280 281 282 283 284
static void klsi_105_release(struct usb_serial *serial)
{
	int i;

	dbg("%s", __func__);

285 286
	for (i = 0; i < serial->num_ports; ++i)
		kfree(usb_get_serial_port_data(serial->port[i]));
J
Johan Hovold 已提交
287
}
L
Linus Torvalds 已提交
288

289
static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
L
Linus Torvalds 已提交
290 291 292 293 294 295
{
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
	int retval = 0;
	int rc;
	int i;
	unsigned long line_state;
296
	struct klsi_105_port_settings *cfg;
L
Linus Torvalds 已提交
297 298
	unsigned long flags;

299
	dbg("%s port %d", __func__, port->number);
L
Linus Torvalds 已提交
300 301 302

	/* Do a defined restart:
	 * Set up sane default baud rate and send the 'READ_ON'
A
Alan Cox 已提交
303
	 * vendor command.
L
Linus Torvalds 已提交
304 305 306 307
	 * FIXME: set modem line control (how?)
	 * Then read the modem line control and store values in
	 * priv->line_state.
	 */
308 309 310 311 312 313 314 315 316 317 318 319
	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 已提交
320

L
Linus Torvalds 已提交
321
	/* set up termios structure */
A
Alan Cox 已提交
322
	spin_lock_irqsave(&priv->lock, flags);
A
Alan Cox 已提交
323 324 325 326
	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 已提交
327
	for (i = 0; i < NCCS; i++)
A
Alan Cox 已提交
328
		priv->termios.c_cc[i] = tty->termios->c_cc[i];
329 330 331 332 333
	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 已提交
334
	spin_unlock_irqrestore(&priv->lock, flags);
L
Linus Torvalds 已提交
335 336

	/* READ_ON and urb submission */
337
	rc = usb_serial_generic_open(tty, port);
L
Linus Torvalds 已提交
338 339 340 341 342 343
	if (rc) {
		retval = rc;
		goto exit;
	}

	rc = usb_control_msg(port->serial->dev,
A
Alan Cox 已提交
344
			     usb_sndctrlpipe(port->serial->dev, 0),
L
Linus Torvalds 已提交
345 346 347 348 349 350 351 352
			     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) {
353
		dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
L
Linus Torvalds 已提交
354
		retval = rc;
A
Alan Cox 已提交
355
	} else
356
		dbg("%s - enabled reading", __func__);
L
Linus Torvalds 已提交
357 358 359

	rc = klsi_105_get_line_state(port, &line_state);
	if (rc >= 0) {
A
Alan Cox 已提交
360
		spin_lock_irqsave(&priv->lock, flags);
L
Linus Torvalds 已提交
361
		priv->line_state = line_state;
A
Alan Cox 已提交
362
		spin_unlock_irqrestore(&priv->lock, flags);
363
		dbg("%s - read line state 0x%lx", __func__, line_state);
L
Linus Torvalds 已提交
364 365 366 367 368
		retval = 0;
	} else
		retval = rc;

exit:
369
	kfree(cfg);
L
Linus Torvalds 已提交
370
	return retval;
J
Johan Hovold 已提交
371
}
L
Linus Torvalds 已提交
372

373
static void klsi_105_close(struct usb_serial_port *port)
L
Linus Torvalds 已提交
374 375 376
{
	int rc;

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

379 380 381
	mutex_lock(&port->serial->disc_mutex);
	if (!port->serial->disconnected) {
		/* send READ_OFF */
A
Alan Cox 已提交
382 383 384 385 386 387 388 389
		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);
390
		if (rc < 0)
391 392
			dev_err(&port->dev,
				"Disabling read failed (error = %d)\n", rc);
393 394
	}
	mutex_unlock(&port->serial->disc_mutex);
L
Linus Torvalds 已提交
395 396

	/* shutdown our bulk reads and writes */
397 398
	usb_serial_generic_close(port);

L
Linus Torvalds 已提交
399 400
	/* wgg - do I need this? I think so. */
	usb_kill_urb(port->interrupt_in_urb);
J
Johan Hovold 已提交
401
}
L
Linus Torvalds 已提交
402 403

/* We need to write a complete 64-byte data block and encode the
A
Alan Cox 已提交
404
 * number actually sent in the first double-byte, LSB-order. That
L
Linus Torvalds 已提交
405 406
 * leaves at most 62 bytes of payload.
 */
407 408 409
#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 已提交
410
{
411 412
	unsigned char *buf = dest;
	int count;
413

414 415 416
	count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
								&port->lock);
	put_unaligned_le16(count, buf);
L
Linus Torvalds 已提交
417

418
	return count + KLSI_HDR_LEN;
J
Johan Hovold 已提交
419
}
L
Linus Torvalds 已提交
420

421 422 423
/* 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 已提交
424
{
425
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
426
	unsigned char *data = urb->transfer_buffer;
427 428
	struct tty_struct *tty;
	unsigned len;
L
Linus Torvalds 已提交
429

430 431 432
	/* empty urbs seem to happen, we ignore them */
	if (!urb->actual_length)
		return;
L
Linus Torvalds 已提交
433

434 435
	if (urb->actual_length <= KLSI_HDR_LEN) {
		dbg("%s - malformed packet", __func__);
436 437 438
		return;
	}

439 440 441
	tty = tty_port_tty_get(&port->port);
	if (!tty)
		return;
L
Linus Torvalds 已提交
442

443 444 445 446
	len = get_unaligned_le16(data);
	if (len > urb->actual_length - KLSI_HDR_LEN) {
		dbg("%s - packet length mismatch", __func__);
		len = urb->actual_length - KLSI_HDR_LEN;
L
Linus Torvalds 已提交
447
	}
448 449 450 451

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

A
Alan Cox 已提交
454 455 456
static void klsi_105_set_termios(struct tty_struct *tty,
				 struct usb_serial_port *port,
				 struct ktermios *old_termios)
L
Linus Torvalds 已提交
457 458
{
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
459
	unsigned int iflag = tty->termios->c_iflag;
L
Linus Torvalds 已提交
460
	unsigned int old_iflag = old_termios->c_iflag;
461
	unsigned int cflag = tty->termios->c_cflag;
L
Linus Torvalds 已提交
462
	unsigned int old_cflag = old_termios->c_cflag;
463
	struct klsi_105_port_settings *cfg;
L
Linus Torvalds 已提交
464
	unsigned long flags;
465
	speed_t baud;
A
Alan Cox 已提交
466

467 468 469 470 471 472 473
	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
	if (!cfg) {
		dev_err(&port->dev, "%s - out of memory for config buffer.\n",
				__func__);
		return;
	}

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

L
Linus Torvalds 已提交
477 478 479
	/*
	 * Update baud rate
	 */
480 481
	baud = tty_get_baud_rate(tty);

A
Alan Cox 已提交
482 483 484
	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
		/* reassert DTR and (maybe) RTS on transition from B0 */
		if ((old_cflag & CBAUD) == B0) {
485
			dbg("%s: baud was B0", __func__);
L
Linus Torvalds 已提交
486 487 488
#if 0
			priv->control_state |= TIOCM_DTR;
			/* don't set RTS if using hardware flow control */
A
Alan Cox 已提交
489
			if (!(old_cflag & CRTSCTS))
L
Linus Torvalds 已提交
490 491 492 493
				priv->control_state |= TIOCM_RTS;
			mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
		}
494
	}
A
Alan Cox 已提交
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
	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:
		dbg("KLSI USB->Serial converter:"
		    " unsupported baudrate request, using default of 9600");
A
Alan Cox 已提交
525
			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
A
Alan Cox 已提交
526 527
		baud = 9600;
		break;
528
	}
A
Alan Cox 已提交
529
	if ((cflag & CBAUD) == B0) {
530 531 532 533 534 535
		dbg("%s: baud is B0", __func__);
		/* Drop RTS and DTR */
		/* maybe this should be simulated by sending read
		 * disable and read enable messages?
		 */
		;
L
Linus Torvalds 已提交
536
#if 0
537
		priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
A
Alan Cox 已提交
538
		mct_u232_set_modem_ctrl(serial, priv->control_state);
L
Linus Torvalds 已提交
539 540
#endif
	}
541
	tty_encode_baud_rate(tty, baud, baud);
L
Linus Torvalds 已提交
542 543 544 545 546

	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
		/* set the number of data bits */
		switch (cflag & CSIZE) {
		case CS5:
547
			dbg("%s - 5 bits/byte not supported", __func__);
A
Alan Cox 已提交
548
			spin_unlock_irqrestore(&priv->lock, flags);
549
			goto err;
L
Linus Torvalds 已提交
550
		case CS6:
551
			dbg("%s - 6 bits/byte not supported", __func__);
A
Alan Cox 已提交
552
			spin_unlock_irqrestore(&priv->lock, flags);
553
			goto err;
L
Linus Torvalds 已提交
554 555 556 557 558 559 560
		case CS7:
			priv->cfg.databits = kl5kusb105a_dtb_7;
			break;
		case CS8:
			priv->cfg.databits = kl5kusb105a_dtb_8;
			break;
		default:
561 562
			dev_err(&port->dev,
				"CSIZE was not CS5-CS8, using default of 8\n");
L
Linus Torvalds 已提交
563 564 565 566 567 568 569 570 571
			priv->cfg.databits = kl5kusb105a_dtb_8;
			break;
		}
	}

	/*
	 * Update line control register (LCR)
	 */
	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
A
Alan Cox 已提交
572
	    || (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
573 574
		/* Not currently supported */
		tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB);
L
Linus Torvalds 已提交
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
#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 已提交
597
	if ((iflag & IXOFF) != (old_iflag & IXOFF)
L
Linus Torvalds 已提交
598
	    || (iflag & IXON) != (old_iflag & IXON)
A
Alan Cox 已提交
599
	    ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
600 601
		/* Not currently supported */
		tty->termios->c_cflag &= ~CRTSCTS;
L
Linus Torvalds 已提交
602 603
		/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
A
Alan Cox 已提交
604
		if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
L
Linus Torvalds 已提交
605 606 607 608 609 610 611
			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
		;
	}
612
	memcpy(cfg, &priv->cfg, sizeof(*cfg));
A
Alan Cox 已提交
613 614
	spin_unlock_irqrestore(&priv->lock, flags);

L
Linus Torvalds 已提交
615
	/* now commit changes to device */
616 617 618
	klsi_105_chg_port_settings(port, cfg);
err:
	kfree(cfg);
J
Johan Hovold 已提交
619
}
L
Linus Torvalds 已提交
620 621

#if 0
A
Alan Cox 已提交
622
static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
623
{
A
Alan Cox 已提交
624
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
625
	struct usb_serial *serial = port->serial;
A
Alan Cox 已提交
626 627
	struct mct_u232_private *priv =
				(struct mct_u232_private *)port->private;
L
Linus Torvalds 已提交
628 629
	unsigned char lcr = priv->last_lcr;

630
	dbg("%sstate=%d", __func__, break_state);
L
Linus Torvalds 已提交
631

632
	/* LOCKING */
L
Linus Torvalds 已提交
633 634 635 636
	if (break_state)
		lcr |= MCT_U232_SET_BREAK;

	mct_u232_set_line_ctrl(serial, lcr);
J
Johan Hovold 已提交
637
}
L
Linus Torvalds 已提交
638 639
#endif

A
Alan Cox 已提交
640
static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file)
L
Linus Torvalds 已提交
641
{
A
Alan Cox 已提交
642
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
643 644 645 646
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	int rc;
	unsigned long line_state;
647
	dbg("%s - request, just guessing", __func__);
L
Linus Torvalds 已提交
648 649 650

	rc = klsi_105_get_line_state(port, &line_state);
	if (rc < 0) {
651 652
		dev_err(&port->dev,
			"Reading line control failed (error = %d)\n", rc);
L
Linus Torvalds 已提交
653 654 655 656
		/* better return value? EAGAIN? */
		return rc;
	}

A
Alan Cox 已提交
657
	spin_lock_irqsave(&priv->lock, flags);
L
Linus Torvalds 已提交
658
	priv->line_state = line_state;
A
Alan Cox 已提交
659
	spin_unlock_irqrestore(&priv->lock, flags);
660
	dbg("%s - read line state 0x%lx", __func__, line_state);
L
Linus Torvalds 已提交
661 662 663
	return (int)line_state;
}

A
Alan Cox 已提交
664 665
static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file,
			     unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
666 667
{
	int retval = -EINVAL;
A
Alan Cox 已提交
668

669
	dbg("%s", __func__);
L
Linus Torvalds 已提交
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693

/* 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;
}


A
Alan Cox 已提交
694
static int __init klsi_105_init(void)
L
Linus Torvalds 已提交
695 696 697 698 699 700 701 702 703
{
	int retval;
	retval = usb_serial_register(&kl5kusb105d_device);
	if (retval)
		goto failed_usb_serial_register;
	retval = usb_register(&kl5kusb105d_driver);
	if (retval)
		goto failed_usb_register;

704 705
	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
	       DRIVER_DESC "\n");
L
Linus Torvalds 已提交
706 707 708 709 710 711 712
	return 0;
failed_usb_register:
	usb_serial_deregister(&kl5kusb105d_device);
failed_usb_serial_register:
	return retval;
}

A
Alan Cox 已提交
713
static void __exit klsi_105_exit(void)
L
Linus Torvalds 已提交
714
{
A
Alan Cox 已提交
715 716
	usb_deregister(&kl5kusb105d_driver);
	usb_serial_deregister(&kl5kusb105d_device);
L
Linus Torvalds 已提交
717 718 719
}


A
Alan Cox 已提交
720 721
module_init(klsi_105_init);
module_exit(klsi_105_exit);
L
Linus Torvalds 已提交
722

A
Alan Cox 已提交
723 724 725
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
L
Linus Torvalds 已提交
726 727 728 729


module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "enable extensive debugging messages");