kl5kusb105.c 17.6 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
#include "kl5kusb105.h"

52
#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>"
L
Linus Torvalds 已提交
53 54 55 56 57 58
#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"


/*
 * Function prototypes
 */
59 60
static int klsi_105_port_probe(struct usb_serial_port *port);
static int klsi_105_port_remove(struct usb_serial_port *port);
61
static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
62
static void klsi_105_close(struct usb_serial_port *port);
A
Alan Cox 已提交
63 64
static void klsi_105_set_termios(struct tty_struct *tty,
			struct usb_serial_port *port, struct ktermios *old);
65
static int  klsi_105_tiocmget(struct tty_struct *tty);
66
static int  klsi_105_tiocmset(struct tty_struct *tty,
A
Alan Cox 已提交
67
			unsigned int set, unsigned int clear);
68 69 70
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 已提交
71 72 73 74

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

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

83
static struct usb_serial_driver kl5kusb105d_device = {
84 85
	.driver = {
		.owner =	THIS_MODULE,
86
		.name =		"kl5kusb105d",
87
	},
J
Johan Hovold 已提交
88 89 90
	.description =		"KL5KUSB105D / PalmConnect",
	.id_table =		id_table,
	.num_ports =		1,
91
	.bulk_out_size =	64,
J
Johan Hovold 已提交
92 93 94 95 96 97
	.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,
98 99
	.port_probe =		klsi_105_port_probe,
	.port_remove =		klsi_105_port_remove,
100 101 102 103
	.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 已提交
104 105
};

106 107 108 109
static struct usb_serial_driver * const serial_drivers[] = {
	&kl5kusb105d_device, NULL
};

L
Linus Torvalds 已提交
110 111 112 113 114 115 116 117 118 119
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 已提交
120
	struct ktermios			termios;
L
Linus Torvalds 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
	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 已提交
138 139 140 141 142 143 144 145 146
	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 已提交
147
	if (rc < 0)
148 149
		dev_err(&port->dev,
			"Change port settings failed (error = %d)\n", rc);
150 151 152 153
	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 已提交
154
	return rc;
J
Johan Hovold 已提交
155
}
L
Linus Torvalds 已提交
156 157 158 159 160 161 162 163 164 165 166 167

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

A
Alan Cox 已提交
169
/*
L
Linus Torvalds 已提交
170
 * Read line control via vendor command and return result through
A
Alan Cox 已提交
171
 * *line_state_p
L
Linus Torvalds 已提交
172 173 174 175 176 177 178
 */
/* 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;
179
	u8 *status_buf;
L
Linus Torvalds 已提交
180 181
	__u16 status;

182
	dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
183 184 185 186 187 188 189 190 191

	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 已提交
192
	rc = usb_control_msg(port->serial->dev,
L
Linus Torvalds 已提交
193 194
			     usb_rcvctrlpipe(port->serial->dev, 0),
			     KL5KUSB105A_SIO_POLL,
A
Alan Cox 已提交
195
			     USB_TYPE_VENDOR | USB_DIR_IN,
L
Linus Torvalds 已提交
196 197 198 199 200 201
			     0, /* value */
			     0, /* index */
			     status_buf, KLSI_STATUSBUF_LEN,
			     10000
			     );
	if (rc < 0)
202 203
		dev_err(&port->dev, "Reading line status failed (error = %d)\n",
			rc);
L
Linus Torvalds 已提交
204
	else {
205
		status = get_unaligned_le16(status_buf);
L
Linus Torvalds 已提交
206

207 208
		dev_info(&port->serial->dev->dev, "read status %x %x",
			 status_buf[0], status_buf[1]);
L
Linus Torvalds 已提交
209 210 211

		*line_state_p = klsi_105_status2linestate(status);
	}
212 213

	kfree(status_buf);
A
Alan Cox 已提交
214
	return rc;
L
Linus Torvalds 已提交
215 216 217 218 219 220 221
}


/*
 * Driver's tty interface functions
 */

222
static int klsi_105_port_probe(struct usb_serial_port *port)
L
Linus Torvalds 已提交
223 224 225
{
	struct klsi_105_private *priv;

226 227 228
	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;
L
Linus Torvalds 已提交
229

230 231 232 233 234 235
	/* 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 已提交
236

237
	priv->line_state    = 0;
L
Linus Torvalds 已提交
238

239
	spin_lock_init(&priv->lock);
L
Linus Torvalds 已提交
240

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

243
	usb_set_serial_port_data(port, priv);
A
Alan Cox 已提交
244

245
	return 0;
J
Johan Hovold 已提交
246
}
L
Linus Torvalds 已提交
247

248
static int klsi_105_port_remove(struct usb_serial_port *port)
249
{
250
	struct klsi_105_private *priv;
251

252 253 254 255
	priv = usb_get_serial_port_data(port);
	kfree(priv);

	return 0;
J
Johan Hovold 已提交
256
}
L
Linus Torvalds 已提交
257

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

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

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

	/* READ_ON and urb submission */
304
	rc = usb_serial_generic_open(tty, port);
L
Linus Torvalds 已提交
305 306 307 308 309 310
	if (rc) {
		retval = rc;
		goto exit;
	}

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

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

exit:
336
	kfree(cfg);
L
Linus Torvalds 已提交
337
	return retval;
J
Johan Hovold 已提交
338
}
L
Linus Torvalds 已提交
339

340
static void klsi_105_close(struct usb_serial_port *port)
L
Linus Torvalds 已提交
341 342 343
{
	int rc;

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

	/* shutdown our bulk reads and writes */
362
	usb_serial_generic_close(port);
J
Johan Hovold 已提交
363
}
L
Linus Torvalds 已提交
364 365

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

376 377 378
	count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
								&port->lock);
	put_unaligned_le16(count, buf);
L
Linus Torvalds 已提交
379

380
	return count + KLSI_HDR_LEN;
J
Johan Hovold 已提交
381
}
L
Linus Torvalds 已提交
382

383 384 385
/* 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 已提交
386
{
387
	struct usb_serial_port *port = urb->context;
L
Linus Torvalds 已提交
388
	unsigned char *data = urb->transfer_buffer;
389
	unsigned len;
L
Linus Torvalds 已提交
390

391 392 393
	/* empty urbs seem to happen, we ignore them */
	if (!urb->actual_length)
		return;
L
Linus Torvalds 已提交
394

395
	if (urb->actual_length <= KLSI_HDR_LEN) {
396
		dev_dbg(&port->dev, "%s - malformed packet\n", __func__);
397 398 399
		return;
	}

400 401
	len = get_unaligned_le16(data);
	if (len > urb->actual_length - KLSI_HDR_LEN) {
402
		dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__);
403
		len = urb->actual_length - KLSI_HDR_LEN;
L
Linus Torvalds 已提交
404
	}
405

J
Jiri Slaby 已提交
406
	tty_insert_flip_string(&port->port, data + KLSI_HDR_LEN, len);
J
Jiri Slaby 已提交
407
	tty_flip_buffer_push(&port->port);
J
Johan Hovold 已提交
408
}
L
Linus Torvalds 已提交
409

A
Alan Cox 已提交
410 411 412
static void klsi_105_set_termios(struct tty_struct *tty,
				 struct usb_serial_port *port,
				 struct ktermios *old_termios)
L
Linus Torvalds 已提交
413 414
{
	struct klsi_105_private *priv = usb_get_serial_port_data(port);
415
	struct device *dev = &port->dev;
416
	unsigned int iflag = tty->termios.c_iflag;
L
Linus Torvalds 已提交
417
	unsigned int old_iflag = old_termios->c_iflag;
418
	unsigned int cflag = tty->termios.c_cflag;
L
Linus Torvalds 已提交
419
	unsigned int old_cflag = old_termios->c_cflag;
420
	struct klsi_105_port_settings *cfg;
L
Linus Torvalds 已提交
421
	unsigned long flags;
422
	speed_t baud;
A
Alan Cox 已提交
423

424 425
	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
	if (!cfg) {
426
		dev_err(dev, "%s - out of memory for config buffer.\n", __func__);
427 428 429
		return;
	}

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

L
Linus Torvalds 已提交
433 434 435
	/*
	 * Update baud rate
	 */
436 437
	baud = tty_get_baud_rate(tty);

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

	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
		/* set the number of data bits */
		switch (cflag & CSIZE) {
		case CS5:
502
			dev_dbg(dev, "%s - 5 bits/byte not supported\n", __func__);
A
Alan Cox 已提交
503
			spin_unlock_irqrestore(&priv->lock, flags);
504
			goto err;
L
Linus Torvalds 已提交
505
		case CS6:
506
			dev_dbg(dev, "%s - 6 bits/byte not supported\n", __func__);
A
Alan Cox 已提交
507
			spin_unlock_irqrestore(&priv->lock, flags);
508
			goto err;
L
Linus Torvalds 已提交
509 510 511 512 513 514 515
		case CS7:
			priv->cfg.databits = kl5kusb105a_dtb_7;
			break;
		case CS8:
			priv->cfg.databits = kl5kusb105a_dtb_8;
			break;
		default:
516
			dev_err(dev, "CSIZE was not CS5-CS8, using default of 8\n");
L
Linus Torvalds 已提交
517 518 519 520 521 522 523 524 525
			priv->cfg.databits = kl5kusb105a_dtb_8;
			break;
		}
	}

	/*
	 * Update line control register (LCR)
	 */
	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
A
Alan Cox 已提交
526
	    || (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
527
		/* Not currently supported */
528
		tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB);
L
Linus Torvalds 已提交
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
#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 已提交
551
	if ((iflag & IXOFF) != (old_iflag & IXOFF)
L
Linus Torvalds 已提交
552
	    || (iflag & IXON) != (old_iflag & IXON)
A
Alan Cox 已提交
553
	    ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
554
		/* Not currently supported */
555
		tty->termios.c_cflag &= ~CRTSCTS;
L
Linus Torvalds 已提交
556 557
		/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
A
Alan Cox 已提交
558
		if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
L
Linus Torvalds 已提交
559 560 561 562 563 564 565
			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
		;
	}
566
	memcpy(cfg, &priv->cfg, sizeof(*cfg));
A
Alan Cox 已提交
567 568
	spin_unlock_irqrestore(&priv->lock, flags);

L
Linus Torvalds 已提交
569
	/* now commit changes to device */
570 571 572
	klsi_105_chg_port_settings(port, cfg);
err:
	kfree(cfg);
J
Johan Hovold 已提交
573
}
L
Linus Torvalds 已提交
574 575

#if 0
A
Alan Cox 已提交
576
static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
L
Linus Torvalds 已提交
577
{
A
Alan Cox 已提交
578
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
579
	struct usb_serial *serial = port->serial;
A
Alan Cox 已提交
580 581
	struct mct_u232_private *priv =
				(struct mct_u232_private *)port->private;
L
Linus Torvalds 已提交
582 583
	unsigned char lcr = priv->last_lcr;

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

586
	/* LOCKING */
L
Linus Torvalds 已提交
587 588 589 590
	if (break_state)
		lcr |= MCT_U232_SET_BREAK;

	mct_u232_set_line_ctrl(serial, lcr);
J
Johan Hovold 已提交
591
}
L
Linus Torvalds 已提交
592 593
#endif

594
static int klsi_105_tiocmget(struct tty_struct *tty)
L
Linus Torvalds 已提交
595
{
A
Alan Cox 已提交
596
	struct usb_serial_port *port = tty->driver_data;
L
Linus Torvalds 已提交
597 598 599 600 601 602 603
	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) {
604 605
		dev_err(&port->dev,
			"Reading line control failed (error = %d)\n", rc);
L
Linus Torvalds 已提交
606 607 608 609
		/* better return value? EAGAIN? */
		return rc;
	}

A
Alan Cox 已提交
610
	spin_lock_irqsave(&priv->lock, flags);
L
Linus Torvalds 已提交
611
	priv->line_state = line_state;
A
Alan Cox 已提交
612
	spin_unlock_irqrestore(&priv->lock, flags);
613
	dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
L
Linus Torvalds 已提交
614 615 616
	return (int)line_state;
}

617
static int klsi_105_tiocmset(struct tty_struct *tty,
A
Alan Cox 已提交
618
			     unsigned int set, unsigned int clear)
L
Linus Torvalds 已提交
619 620
{
	int retval = -EINVAL;
A
Alan Cox 已提交
621

L
Linus Torvalds 已提交
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
/* 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;
}

644
module_usb_serial_driver(serial_drivers, id_table);
L
Linus Torvalds 已提交
645

A
Alan Cox 已提交
646 647 648
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");