xref: /openbmc/linux/drivers/usb/serial/kl5kusb105.c (revision 33a03aad)
1 /*
2  * KLSI KL5KUSB105 chip RS232 converter driver
3  *
4  *   Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
5  *   Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  * All information about the device was acquired using SniffUSB ans snoopUSB
13  * on Windows98.
14  * It was written out of frustration with the PalmConnect USB Serial adapter
15  * sold by Palm Inc.
16  * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided
17  * information that was not already available.
18  *
19  * It seems that KLSI bought some silicon-design information from ScanLogic,
20  * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI.
21  * KLSI has firmware available for their devices; it is probable that the
22  * firmware differs from that used by KLSI in their products. If you have an
23  * original KLSI device and can provide some information on it, I would be
24  * most interested in adding support for it here. If you have any information
25  * on the protocol used (or find errors in my reverse-engineered stuff), please
26  * let me know.
27  *
28  * The code was only tested with a PalmConnect USB adapter; if you
29  * are adventurous, try it with any KLSI-based device and let me know how it
30  * breaks so that I can fix it!
31  */
32 
33 /* TODO:
34  *	check modem line signals
35  *	implement handshaking or decide that we do not support it
36  */
37 
38 #include <linux/kernel.h>
39 #include <linux/errno.h>
40 #include <linux/init.h>
41 #include <linux/slab.h>
42 #include <linux/tty.h>
43 #include <linux/tty_driver.h>
44 #include <linux/tty_flip.h>
45 #include <linux/module.h>
46 #include <linux/uaccess.h>
47 #include <asm/unaligned.h>
48 #include <linux/usb.h>
49 #include <linux/usb/serial.h>
50 #include "kl5kusb105.h"
51 
52 static bool debug;
53 
54 /*
55  * Version Information
56  */
57 #define DRIVER_VERSION "v0.4"
58 #define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>"
59 #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
60 
61 
62 /*
63  * Function prototypes
64  */
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);
69 static void klsi_105_set_termios(struct tty_struct *tty,
70 			struct usb_serial_port *port, struct ktermios *old);
71 static int  klsi_105_tiocmget(struct tty_struct *tty);
72 static int  klsi_105_tiocmset(struct tty_struct *tty,
73 			unsigned int set, unsigned int clear);
74 static void klsi_105_process_read_urb(struct urb *urb);
75 static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
76 						void *dest, size_t size);
77 
78 /*
79  * All of the device info needed for the KLSI converters.
80  */
81 static const struct usb_device_id id_table[] = {
82 	{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
83 	{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
84 	{ }		/* Terminating entry */
85 };
86 
87 MODULE_DEVICE_TABLE(usb, id_table);
88 
89 static struct usb_serial_driver kl5kusb105d_device = {
90 	.driver = {
91 		.owner =	THIS_MODULE,
92 		.name =		"kl5kusb105d",
93 	},
94 	.description =		"KL5KUSB105D / PalmConnect",
95 	.id_table =		id_table,
96 	.num_ports =		1,
97 	.bulk_out_size =	64,
98 	.open =			klsi_105_open,
99 	.close =		klsi_105_close,
100 	.set_termios =		klsi_105_set_termios,
101 	/*.break_ctl =		klsi_105_break_ctl,*/
102 	.tiocmget =		klsi_105_tiocmget,
103 	.tiocmset =		klsi_105_tiocmset,
104 	.attach =		klsi_105_startup,
105 	.release =		klsi_105_release,
106 	.throttle =		usb_serial_generic_throttle,
107 	.unthrottle =		usb_serial_generic_unthrottle,
108 	.process_read_urb =	klsi_105_process_read_urb,
109 	.prepare_write_buffer =	klsi_105_prepare_write_buffer,
110 };
111 
112 static struct usb_serial_driver * const serial_drivers[] = {
113 	&kl5kusb105d_device, NULL
114 };
115 
116 struct klsi_105_port_settings {
117 	__u8	pktlen;		/* always 5, it seems */
118 	__u8	baudrate;
119 	__u8	databits;
120 	__u8	unknown1;
121 	__u8	unknown2;
122 } __attribute__ ((packed));
123 
124 struct klsi_105_private {
125 	struct klsi_105_port_settings	cfg;
126 	struct ktermios			termios;
127 	unsigned long			line_state; /* modem line settings */
128 	spinlock_t			lock;
129 };
130 
131 
132 /*
133  * Handle vendor specific USB requests
134  */
135 
136 
137 #define KLSI_TIMEOUT	 5000 /* default urb timeout */
138 
139 static int klsi_105_chg_port_settings(struct usb_serial_port *port,
140 				      struct klsi_105_port_settings *settings)
141 {
142 	int rc;
143 
144 	rc = usb_control_msg(port->serial->dev,
145 			usb_sndctrlpipe(port->serial->dev, 0),
146 			KL5KUSB105A_SIO_SET_DATA,
147 			USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE,
148 			0, /* value */
149 			0, /* index */
150 			settings,
151 			sizeof(struct klsi_105_port_settings),
152 			KLSI_TIMEOUT);
153 	if (rc < 0)
154 		dev_err(&port->dev,
155 			"Change port settings failed (error = %d)\n", rc);
156 	dev_info(&port->serial->dev->dev,
157 		 "%d byte block, baudrate %x, databits %d, u1 %d, u2 %d\n",
158 		 settings->pktlen, settings->baudrate, settings->databits,
159 		 settings->unknown1, settings->unknown2);
160 	return rc;
161 }
162 
163 /* translate a 16-bit status value from the device to linux's TIO bits */
164 static unsigned long klsi_105_status2linestate(const __u16 status)
165 {
166 	unsigned long res = 0;
167 
168 	res =   ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0)
169 	      | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0)
170 	      ;
171 
172 	return res;
173 }
174 
175 /*
176  * Read line control via vendor command and return result through
177  * *line_state_p
178  */
179 /* It seems that the status buffer has always only 2 bytes length */
180 #define KLSI_STATUSBUF_LEN	2
181 static int klsi_105_get_line_state(struct usb_serial_port *port,
182 				   unsigned long *line_state_p)
183 {
184 	int rc;
185 	u8 *status_buf;
186 	__u16 status;
187 
188 	dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
189 
190 	status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL);
191 	if (!status_buf) {
192 		dev_err(&port->dev, "%s - out of memory for status buffer.\n",
193 				__func__);
194 		return -ENOMEM;
195 	}
196 	status_buf[0] = 0xff;
197 	status_buf[1] = 0xff;
198 	rc = usb_control_msg(port->serial->dev,
199 			     usb_rcvctrlpipe(port->serial->dev, 0),
200 			     KL5KUSB105A_SIO_POLL,
201 			     USB_TYPE_VENDOR | USB_DIR_IN,
202 			     0, /* value */
203 			     0, /* index */
204 			     status_buf, KLSI_STATUSBUF_LEN,
205 			     10000
206 			     );
207 	if (rc < 0)
208 		dev_err(&port->dev, "Reading line status failed (error = %d)\n",
209 			rc);
210 	else {
211 		status = get_unaligned_le16(status_buf);
212 
213 		dev_info(&port->serial->dev->dev, "read status %x %x",
214 			 status_buf[0], status_buf[1]);
215 
216 		*line_state_p = klsi_105_status2linestate(status);
217 	}
218 
219 	kfree(status_buf);
220 	return rc;
221 }
222 
223 
224 /*
225  * Driver's tty interface functions
226  */
227 
228 static int klsi_105_startup(struct usb_serial *serial)
229 {
230 	struct klsi_105_private *priv;
231 	int i;
232 
233 	/* check if we support the product id (see keyspan.c)
234 	 * FIXME
235 	 */
236 
237 	/* allocate the private data structure */
238 	for (i = 0; i < serial->num_ports; i++) {
239 		priv = kmalloc(sizeof(struct klsi_105_private),
240 						   GFP_KERNEL);
241 		if (!priv) {
242 			dbg("%skmalloc for klsi_105_private failed.", __func__);
243 			i--;
244 			goto err_cleanup;
245 		}
246 		/* set initial values for control structures */
247 		priv->cfg.pktlen    = 5;
248 		priv->cfg.baudrate  = kl5kusb105a_sio_b9600;
249 		priv->cfg.databits  = kl5kusb105a_dtb_8;
250 		priv->cfg.unknown1  = 0;
251 		priv->cfg.unknown2  = 1;
252 
253 		priv->line_state    = 0;
254 
255 		usb_set_serial_port_data(serial->port[i], priv);
256 
257 		spin_lock_init(&priv->lock);
258 
259 		/* priv->termios is left uninitialized until port opening */
260 		init_waitqueue_head(&serial->port[i]->write_wait);
261 	}
262 
263 	return 0;
264 
265 err_cleanup:
266 	for (; i >= 0; i--) {
267 		priv = usb_get_serial_port_data(serial->port[i]);
268 		kfree(priv);
269 		usb_set_serial_port_data(serial->port[i], NULL);
270 	}
271 	return -ENOMEM;
272 }
273 
274 static void klsi_105_release(struct usb_serial *serial)
275 {
276 	int i;
277 
278 	for (i = 0; i < serial->num_ports; ++i)
279 		kfree(usb_get_serial_port_data(serial->port[i]));
280 }
281 
282 static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
283 {
284 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
285 	int retval = 0;
286 	int rc;
287 	int i;
288 	unsigned long line_state;
289 	struct klsi_105_port_settings *cfg;
290 	unsigned long flags;
291 
292 	/* Do a defined restart:
293 	 * Set up sane default baud rate and send the 'READ_ON'
294 	 * vendor command.
295 	 * FIXME: set modem line control (how?)
296 	 * Then read the modem line control and store values in
297 	 * priv->line_state.
298 	 */
299 	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
300 	if (!cfg) {
301 		dev_err(&port->dev, "%s - out of memory for config buffer.\n",
302 				__func__);
303 		return -ENOMEM;
304 	}
305 	cfg->pktlen   = 5;
306 	cfg->baudrate = kl5kusb105a_sio_b9600;
307 	cfg->databits = kl5kusb105a_dtb_8;
308 	cfg->unknown1 = 0;
309 	cfg->unknown2 = 1;
310 	klsi_105_chg_port_settings(port, cfg);
311 
312 	/* set up termios structure */
313 	spin_lock_irqsave(&priv->lock, flags);
314 	priv->termios.c_iflag = tty->termios->c_iflag;
315 	priv->termios.c_oflag = tty->termios->c_oflag;
316 	priv->termios.c_cflag = tty->termios->c_cflag;
317 	priv->termios.c_lflag = tty->termios->c_lflag;
318 	for (i = 0; i < NCCS; i++)
319 		priv->termios.c_cc[i] = tty->termios->c_cc[i];
320 	priv->cfg.pktlen   = cfg->pktlen;
321 	priv->cfg.baudrate = cfg->baudrate;
322 	priv->cfg.databits = cfg->databits;
323 	priv->cfg.unknown1 = cfg->unknown1;
324 	priv->cfg.unknown2 = cfg->unknown2;
325 	spin_unlock_irqrestore(&priv->lock, flags);
326 
327 	/* READ_ON and urb submission */
328 	rc = usb_serial_generic_open(tty, port);
329 	if (rc) {
330 		retval = rc;
331 		goto exit;
332 	}
333 
334 	rc = usb_control_msg(port->serial->dev,
335 			     usb_sndctrlpipe(port->serial->dev, 0),
336 			     KL5KUSB105A_SIO_CONFIGURE,
337 			     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
338 			     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
339 			     0, /* index */
340 			     NULL,
341 			     0,
342 			     KLSI_TIMEOUT);
343 	if (rc < 0) {
344 		dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
345 		retval = rc;
346 	} else
347 		dbg("%s - enabled reading", __func__);
348 
349 	rc = klsi_105_get_line_state(port, &line_state);
350 	if (rc >= 0) {
351 		spin_lock_irqsave(&priv->lock, flags);
352 		priv->line_state = line_state;
353 		spin_unlock_irqrestore(&priv->lock, flags);
354 		dbg("%s - read line state 0x%lx", __func__, line_state);
355 		retval = 0;
356 	} else
357 		retval = rc;
358 
359 exit:
360 	kfree(cfg);
361 	return retval;
362 }
363 
364 static void klsi_105_close(struct usb_serial_port *port)
365 {
366 	int rc;
367 
368 	mutex_lock(&port->serial->disc_mutex);
369 	if (!port->serial->disconnected) {
370 		/* send READ_OFF */
371 		rc = usb_control_msg(port->serial->dev,
372 				     usb_sndctrlpipe(port->serial->dev, 0),
373 				     KL5KUSB105A_SIO_CONFIGURE,
374 				     USB_TYPE_VENDOR | USB_DIR_OUT,
375 				     KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
376 				     0, /* index */
377 				     NULL, 0,
378 				     KLSI_TIMEOUT);
379 		if (rc < 0)
380 			dev_err(&port->dev,
381 				"Disabling read failed (error = %d)\n", rc);
382 	}
383 	mutex_unlock(&port->serial->disc_mutex);
384 
385 	/* shutdown our bulk reads and writes */
386 	usb_serial_generic_close(port);
387 
388 	/* wgg - do I need this? I think so. */
389 	usb_kill_urb(port->interrupt_in_urb);
390 }
391 
392 /* We need to write a complete 64-byte data block and encode the
393  * number actually sent in the first double-byte, LSB-order. That
394  * leaves at most 62 bytes of payload.
395  */
396 #define KLSI_HDR_LEN		2
397 static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
398 						void *dest, size_t size)
399 {
400 	unsigned char *buf = dest;
401 	int count;
402 
403 	count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
404 								&port->lock);
405 	put_unaligned_le16(count, buf);
406 
407 	return count + KLSI_HDR_LEN;
408 }
409 
410 /* The data received is preceded by a length double-byte in LSB-first order.
411  */
412 static void klsi_105_process_read_urb(struct urb *urb)
413 {
414 	struct usb_serial_port *port = urb->context;
415 	unsigned char *data = urb->transfer_buffer;
416 	struct tty_struct *tty;
417 	unsigned len;
418 
419 	/* empty urbs seem to happen, we ignore them */
420 	if (!urb->actual_length)
421 		return;
422 
423 	if (urb->actual_length <= KLSI_HDR_LEN) {
424 		dbg("%s - malformed packet", __func__);
425 		return;
426 	}
427 
428 	tty = tty_port_tty_get(&port->port);
429 	if (!tty)
430 		return;
431 
432 	len = get_unaligned_le16(data);
433 	if (len > urb->actual_length - KLSI_HDR_LEN) {
434 		dbg("%s - packet length mismatch", __func__);
435 		len = urb->actual_length - KLSI_HDR_LEN;
436 	}
437 
438 	tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len);
439 	tty_flip_buffer_push(tty);
440 	tty_kref_put(tty);
441 }
442 
443 static void klsi_105_set_termios(struct tty_struct *tty,
444 				 struct usb_serial_port *port,
445 				 struct ktermios *old_termios)
446 {
447 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
448 	unsigned int iflag = tty->termios->c_iflag;
449 	unsigned int old_iflag = old_termios->c_iflag;
450 	unsigned int cflag = tty->termios->c_cflag;
451 	unsigned int old_cflag = old_termios->c_cflag;
452 	struct klsi_105_port_settings *cfg;
453 	unsigned long flags;
454 	speed_t baud;
455 
456 	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
457 	if (!cfg) {
458 		dev_err(&port->dev, "%s - out of memory for config buffer.\n",
459 				__func__);
460 		return;
461 	}
462 
463 	/* lock while we are modifying the settings */
464 	spin_lock_irqsave(&priv->lock, flags);
465 
466 	/*
467 	 * Update baud rate
468 	 */
469 	baud = tty_get_baud_rate(tty);
470 
471 	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
472 		/* reassert DTR and (maybe) RTS on transition from B0 */
473 		if ((old_cflag & CBAUD) == B0) {
474 			dbg("%s: baud was B0", __func__);
475 #if 0
476 			priv->control_state |= TIOCM_DTR;
477 			/* don't set RTS if using hardware flow control */
478 			if (!(old_cflag & CRTSCTS))
479 				priv->control_state |= TIOCM_RTS;
480 			mct_u232_set_modem_ctrl(serial, priv->control_state);
481 #endif
482 		}
483 	}
484 	switch (baud) {
485 	case 0: /* handled below */
486 		break;
487 	case 1200:
488 		priv->cfg.baudrate = kl5kusb105a_sio_b1200;
489 		break;
490 	case 2400:
491 		priv->cfg.baudrate = kl5kusb105a_sio_b2400;
492 		break;
493 	case 4800:
494 		priv->cfg.baudrate = kl5kusb105a_sio_b4800;
495 		break;
496 	case 9600:
497 		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
498 		break;
499 	case 19200:
500 		priv->cfg.baudrate = kl5kusb105a_sio_b19200;
501 		break;
502 	case 38400:
503 		priv->cfg.baudrate = kl5kusb105a_sio_b38400;
504 		break;
505 	case 57600:
506 		priv->cfg.baudrate = kl5kusb105a_sio_b57600;
507 		break;
508 	case 115200:
509 		priv->cfg.baudrate = kl5kusb105a_sio_b115200;
510 		break;
511 	default:
512 		dbg("KLSI USB->Serial converter:"
513 		    " unsupported baudrate request, using default of 9600");
514 			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
515 		baud = 9600;
516 		break;
517 	}
518 	if ((cflag & CBAUD) == B0) {
519 		dbg("%s: baud is B0", __func__);
520 		/* Drop RTS and DTR */
521 		/* maybe this should be simulated by sending read
522 		 * disable and read enable messages?
523 		 */
524 		;
525 #if 0
526 		priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
527 		mct_u232_set_modem_ctrl(serial, priv->control_state);
528 #endif
529 	}
530 	tty_encode_baud_rate(tty, baud, baud);
531 
532 	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
533 		/* set the number of data bits */
534 		switch (cflag & CSIZE) {
535 		case CS5:
536 			dbg("%s - 5 bits/byte not supported", __func__);
537 			spin_unlock_irqrestore(&priv->lock, flags);
538 			goto err;
539 		case CS6:
540 			dbg("%s - 6 bits/byte not supported", __func__);
541 			spin_unlock_irqrestore(&priv->lock, flags);
542 			goto err;
543 		case CS7:
544 			priv->cfg.databits = kl5kusb105a_dtb_7;
545 			break;
546 		case CS8:
547 			priv->cfg.databits = kl5kusb105a_dtb_8;
548 			break;
549 		default:
550 			dev_err(&port->dev,
551 				"CSIZE was not CS5-CS8, using default of 8\n");
552 			priv->cfg.databits = kl5kusb105a_dtb_8;
553 			break;
554 		}
555 	}
556 
557 	/*
558 	 * Update line control register (LCR)
559 	 */
560 	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
561 	    || (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
562 		/* Not currently supported */
563 		tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB);
564 #if 0
565 		priv->last_lcr = 0;
566 
567 		/* set the parity */
568 		if (cflag & PARENB)
569 			priv->last_lcr |= (cflag & PARODD) ?
570 				MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
571 		else
572 			priv->last_lcr |= MCT_U232_PARITY_NONE;
573 
574 		/* set the number of stop bits */
575 		priv->last_lcr |= (cflag & CSTOPB) ?
576 			MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
577 
578 		mct_u232_set_line_ctrl(serial, priv->last_lcr);
579 #endif
580 		;
581 	}
582 	/*
583 	 * Set flow control: well, I do not really now how to handle DTR/RTS.
584 	 * Just do what we have seen with SniffUSB on Win98.
585 	 */
586 	if ((iflag & IXOFF) != (old_iflag & IXOFF)
587 	    || (iflag & IXON) != (old_iflag & IXON)
588 	    ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
589 		/* Not currently supported */
590 		tty->termios->c_cflag &= ~CRTSCTS;
591 		/* Drop DTR/RTS if no flow control otherwise assert */
592 #if 0
593 		if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
594 			priv->control_state |= TIOCM_DTR | TIOCM_RTS;
595 		else
596 			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
597 		mct_u232_set_modem_ctrl(serial, priv->control_state);
598 #endif
599 		;
600 	}
601 	memcpy(cfg, &priv->cfg, sizeof(*cfg));
602 	spin_unlock_irqrestore(&priv->lock, flags);
603 
604 	/* now commit changes to device */
605 	klsi_105_chg_port_settings(port, cfg);
606 err:
607 	kfree(cfg);
608 }
609 
610 #if 0
611 static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
612 {
613 	struct usb_serial_port *port = tty->driver_data;
614 	struct usb_serial *serial = port->serial;
615 	struct mct_u232_private *priv =
616 				(struct mct_u232_private *)port->private;
617 	unsigned char lcr = priv->last_lcr;
618 
619 	dbg("%sstate=%d", __func__, break_state);
620 
621 	/* LOCKING */
622 	if (break_state)
623 		lcr |= MCT_U232_SET_BREAK;
624 
625 	mct_u232_set_line_ctrl(serial, lcr);
626 }
627 #endif
628 
629 static int klsi_105_tiocmget(struct tty_struct *tty)
630 {
631 	struct usb_serial_port *port = tty->driver_data;
632 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
633 	unsigned long flags;
634 	int rc;
635 	unsigned long line_state;
636 
637 	rc = klsi_105_get_line_state(port, &line_state);
638 	if (rc < 0) {
639 		dev_err(&port->dev,
640 			"Reading line control failed (error = %d)\n", rc);
641 		/* better return value? EAGAIN? */
642 		return rc;
643 	}
644 
645 	spin_lock_irqsave(&priv->lock, flags);
646 	priv->line_state = line_state;
647 	spin_unlock_irqrestore(&priv->lock, flags);
648 	dbg("%s - read line state 0x%lx", __func__, line_state);
649 	return (int)line_state;
650 }
651 
652 static int klsi_105_tiocmset(struct tty_struct *tty,
653 			     unsigned int set, unsigned int clear)
654 {
655 	int retval = -EINVAL;
656 
657 /* if this ever gets implemented, it should be done something like this:
658 	struct usb_serial *serial = port->serial;
659 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
660 	unsigned long flags;
661 	int control;
662 
663 	spin_lock_irqsave (&priv->lock, flags);
664 	if (set & TIOCM_RTS)
665 		priv->control_state |= TIOCM_RTS;
666 	if (set & TIOCM_DTR)
667 		priv->control_state |= TIOCM_DTR;
668 	if (clear & TIOCM_RTS)
669 		priv->control_state &= ~TIOCM_RTS;
670 	if (clear & TIOCM_DTR)
671 		priv->control_state &= ~TIOCM_DTR;
672 	control = priv->control_state;
673 	spin_unlock_irqrestore (&priv->lock, flags);
674 	retval = mct_u232_set_modem_ctrl(serial, control);
675 */
676 	return retval;
677 }
678 
679 module_usb_serial_driver(serial_drivers, id_table);
680 
681 MODULE_AUTHOR(DRIVER_AUTHOR);
682 MODULE_DESCRIPTION(DRIVER_DESC);
683 MODULE_LICENSE("GPL");
684 
685 module_param(debug, bool, S_IRUGO | S_IWUSR);
686 MODULE_PARM_DESC(debug, "enable extensive debugging messages");
687