kl5kusb105.c (13700B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * KLSI KL5KUSB105 chip RS232 converter driver 4 * 5 * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> 6 * Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de> 7 * 8 * All information about the device was acquired using SniffUSB ans snoopUSB 9 * on Windows98. 10 * It was written out of frustration with the PalmConnect USB Serial adapter 11 * sold by Palm Inc. 12 * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided 13 * information that was not already available. 14 * 15 * It seems that KLSI bought some silicon-design information from ScanLogic, 16 * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI. 17 * KLSI has firmware available for their devices; it is probable that the 18 * firmware differs from that used by KLSI in their products. If you have an 19 * original KLSI device and can provide some information on it, I would be 20 * most interested in adding support for it here. If you have any information 21 * on the protocol used (or find errors in my reverse-engineered stuff), please 22 * let me know. 23 * 24 * The code was only tested with a PalmConnect USB adapter; if you 25 * are adventurous, try it with any KLSI-based device and let me know how it 26 * breaks so that I can fix it! 27 */ 28 29/* TODO: 30 * check modem line signals 31 * implement handshaking or decide that we do not support it 32 */ 33 34#include <linux/kernel.h> 35#include <linux/errno.h> 36#include <linux/slab.h> 37#include <linux/tty.h> 38#include <linux/tty_driver.h> 39#include <linux/tty_flip.h> 40#include <linux/module.h> 41#include <linux/uaccess.h> 42#include <asm/unaligned.h> 43#include <linux/usb.h> 44#include <linux/usb/serial.h> 45#include "kl5kusb105.h" 46 47#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>" 48#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" 49 50 51/* 52 * Function prototypes 53 */ 54static int klsi_105_port_probe(struct usb_serial_port *port); 55static void klsi_105_port_remove(struct usb_serial_port *port); 56static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); 57static void klsi_105_close(struct usb_serial_port *port); 58static void klsi_105_set_termios(struct tty_struct *tty, 59 struct usb_serial_port *port, struct ktermios *old); 60static int klsi_105_tiocmget(struct tty_struct *tty); 61static void klsi_105_process_read_urb(struct urb *urb); 62static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, 63 void *dest, size_t size); 64 65/* 66 * All of the device info needed for the KLSI converters. 67 */ 68static const struct usb_device_id id_table[] = { 69 { USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) }, 70 { } /* Terminating entry */ 71}; 72 73MODULE_DEVICE_TABLE(usb, id_table); 74 75static struct usb_serial_driver kl5kusb105d_device = { 76 .driver = { 77 .owner = THIS_MODULE, 78 .name = "kl5kusb105d", 79 }, 80 .description = "KL5KUSB105D / PalmConnect", 81 .id_table = id_table, 82 .num_ports = 1, 83 .bulk_out_size = 64, 84 .open = klsi_105_open, 85 .close = klsi_105_close, 86 .set_termios = klsi_105_set_termios, 87 .tiocmget = klsi_105_tiocmget, 88 .port_probe = klsi_105_port_probe, 89 .port_remove = klsi_105_port_remove, 90 .throttle = usb_serial_generic_throttle, 91 .unthrottle = usb_serial_generic_unthrottle, 92 .process_read_urb = klsi_105_process_read_urb, 93 .prepare_write_buffer = klsi_105_prepare_write_buffer, 94}; 95 96static struct usb_serial_driver * const serial_drivers[] = { 97 &kl5kusb105d_device, NULL 98}; 99 100struct klsi_105_port_settings { 101 u8 pktlen; /* always 5, it seems */ 102 u8 baudrate; 103 u8 databits; 104 u8 unknown1; 105 u8 unknown2; 106}; 107 108struct klsi_105_private { 109 struct klsi_105_port_settings cfg; 110 unsigned long line_state; /* modem line settings */ 111 spinlock_t lock; 112}; 113 114 115/* 116 * Handle vendor specific USB requests 117 */ 118 119 120#define KLSI_TIMEOUT 5000 /* default urb timeout */ 121 122static int klsi_105_chg_port_settings(struct usb_serial_port *port, 123 struct klsi_105_port_settings *settings) 124{ 125 int rc; 126 127 rc = usb_control_msg_send(port->serial->dev, 128 0, 129 KL5KUSB105A_SIO_SET_DATA, 130 USB_TYPE_VENDOR | USB_DIR_OUT | 131 USB_RECIP_INTERFACE, 132 0, /* value */ 133 0, /* index */ 134 settings, 135 sizeof(struct klsi_105_port_settings), 136 KLSI_TIMEOUT, 137 GFP_KERNEL); 138 if (rc) 139 dev_err(&port->dev, 140 "Change port settings failed (error = %d)\n", rc); 141 142 dev_dbg(&port->dev, 143 "pktlen %u, baudrate 0x%02x, databits %u, u1 %u, u2 %u\n", 144 settings->pktlen, settings->baudrate, settings->databits, 145 settings->unknown1, settings->unknown2); 146 147 return rc; 148} 149 150/* 151 * Read line control via vendor command and return result through 152 * the state pointer. 153 */ 154static int klsi_105_get_line_state(struct usb_serial_port *port, 155 unsigned long *state) 156{ 157 u16 status; 158 int rc; 159 160 rc = usb_control_msg_recv(port->serial->dev, 0, 161 KL5KUSB105A_SIO_POLL, 162 USB_TYPE_VENDOR | USB_DIR_IN, 163 0, /* value */ 164 0, /* index */ 165 &status, sizeof(status), 166 10000, 167 GFP_KERNEL); 168 if (rc) { 169 dev_err(&port->dev, "reading line status failed: %d\n", rc); 170 return rc; 171 } 172 173 le16_to_cpus(&status); 174 175 dev_dbg(&port->dev, "read status %04x\n", status); 176 177 *state = ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0) | 178 ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0); 179 180 return 0; 181} 182 183 184/* 185 * Driver's tty interface functions 186 */ 187 188static int klsi_105_port_probe(struct usb_serial_port *port) 189{ 190 struct klsi_105_private *priv; 191 192 priv = kmalloc(sizeof(*priv), GFP_KERNEL); 193 if (!priv) 194 return -ENOMEM; 195 196 /* set initial values for control structures */ 197 priv->cfg.pktlen = 5; 198 priv->cfg.baudrate = kl5kusb105a_sio_b9600; 199 priv->cfg.databits = kl5kusb105a_dtb_8; 200 priv->cfg.unknown1 = 0; 201 priv->cfg.unknown2 = 1; 202 203 priv->line_state = 0; 204 205 spin_lock_init(&priv->lock); 206 207 usb_set_serial_port_data(port, priv); 208 209 return 0; 210} 211 212static void klsi_105_port_remove(struct usb_serial_port *port) 213{ 214 struct klsi_105_private *priv; 215 216 priv = usb_get_serial_port_data(port); 217 kfree(priv); 218} 219 220static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) 221{ 222 struct klsi_105_private *priv = usb_get_serial_port_data(port); 223 int retval = 0; 224 int rc; 225 unsigned long line_state; 226 struct klsi_105_port_settings cfg; 227 unsigned long flags; 228 229 /* Do a defined restart: 230 * Set up sane default baud rate and send the 'READ_ON' 231 * vendor command. 232 * FIXME: set modem line control (how?) 233 * Then read the modem line control and store values in 234 * priv->line_state. 235 */ 236 237 cfg.pktlen = 5; 238 cfg.baudrate = kl5kusb105a_sio_b9600; 239 cfg.databits = kl5kusb105a_dtb_8; 240 cfg.unknown1 = 0; 241 cfg.unknown2 = 1; 242 klsi_105_chg_port_settings(port, &cfg); 243 244 spin_lock_irqsave(&priv->lock, flags); 245 priv->cfg.pktlen = cfg.pktlen; 246 priv->cfg.baudrate = cfg.baudrate; 247 priv->cfg.databits = cfg.databits; 248 priv->cfg.unknown1 = cfg.unknown1; 249 priv->cfg.unknown2 = cfg.unknown2; 250 spin_unlock_irqrestore(&priv->lock, flags); 251 252 /* READ_ON and urb submission */ 253 rc = usb_serial_generic_open(tty, port); 254 if (rc) 255 return rc; 256 257 rc = usb_control_msg(port->serial->dev, 258 usb_sndctrlpipe(port->serial->dev, 0), 259 KL5KUSB105A_SIO_CONFIGURE, 260 USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE, 261 KL5KUSB105A_SIO_CONFIGURE_READ_ON, 262 0, /* index */ 263 NULL, 264 0, 265 KLSI_TIMEOUT); 266 if (rc < 0) { 267 dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc); 268 retval = rc; 269 goto err_generic_close; 270 } else 271 dev_dbg(&port->dev, "%s - enabled reading\n", __func__); 272 273 rc = klsi_105_get_line_state(port, &line_state); 274 if (rc < 0) { 275 retval = rc; 276 goto err_disable_read; 277 } 278 279 spin_lock_irqsave(&priv->lock, flags); 280 priv->line_state = line_state; 281 spin_unlock_irqrestore(&priv->lock, flags); 282 dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, 283 line_state); 284 285 return 0; 286 287err_disable_read: 288 usb_control_msg(port->serial->dev, 289 usb_sndctrlpipe(port->serial->dev, 0), 290 KL5KUSB105A_SIO_CONFIGURE, 291 USB_TYPE_VENDOR | USB_DIR_OUT, 292 KL5KUSB105A_SIO_CONFIGURE_READ_OFF, 293 0, /* index */ 294 NULL, 0, 295 KLSI_TIMEOUT); 296err_generic_close: 297 usb_serial_generic_close(port); 298 299 return retval; 300} 301 302static void klsi_105_close(struct usb_serial_port *port) 303{ 304 int rc; 305 306 /* send READ_OFF */ 307 rc = usb_control_msg(port->serial->dev, 308 usb_sndctrlpipe(port->serial->dev, 0), 309 KL5KUSB105A_SIO_CONFIGURE, 310 USB_TYPE_VENDOR | USB_DIR_OUT, 311 KL5KUSB105A_SIO_CONFIGURE_READ_OFF, 312 0, /* index */ 313 NULL, 0, 314 KLSI_TIMEOUT); 315 if (rc < 0) 316 dev_err(&port->dev, "failed to disable read: %d\n", rc); 317 318 /* shutdown our bulk reads and writes */ 319 usb_serial_generic_close(port); 320} 321 322/* We need to write a complete 64-byte data block and encode the 323 * number actually sent in the first double-byte, LSB-order. That 324 * leaves at most 62 bytes of payload. 325 */ 326#define KLSI_HDR_LEN 2 327static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, 328 void *dest, size_t size) 329{ 330 unsigned char *buf = dest; 331 int count; 332 333 count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size, 334 &port->lock); 335 put_unaligned_le16(count, buf); 336 337 return count + KLSI_HDR_LEN; 338} 339 340/* The data received is preceded by a length double-byte in LSB-first order. 341 */ 342static void klsi_105_process_read_urb(struct urb *urb) 343{ 344 struct usb_serial_port *port = urb->context; 345 unsigned char *data = urb->transfer_buffer; 346 unsigned len; 347 348 /* empty urbs seem to happen, we ignore them */ 349 if (!urb->actual_length) 350 return; 351 352 if (urb->actual_length <= KLSI_HDR_LEN) { 353 dev_dbg(&port->dev, "%s - malformed packet\n", __func__); 354 return; 355 } 356 357 len = get_unaligned_le16(data); 358 if (len > urb->actual_length - KLSI_HDR_LEN) { 359 dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__); 360 len = urb->actual_length - KLSI_HDR_LEN; 361 } 362 363 tty_insert_flip_string(&port->port, data + KLSI_HDR_LEN, len); 364 tty_flip_buffer_push(&port->port); 365} 366 367static void klsi_105_set_termios(struct tty_struct *tty, 368 struct usb_serial_port *port, 369 struct ktermios *old_termios) 370{ 371 struct klsi_105_private *priv = usb_get_serial_port_data(port); 372 struct device *dev = &port->dev; 373 unsigned int iflag = tty->termios.c_iflag; 374 unsigned int old_iflag = old_termios->c_iflag; 375 unsigned int cflag = tty->termios.c_cflag; 376 unsigned int old_cflag = old_termios->c_cflag; 377 struct klsi_105_port_settings *cfg; 378 unsigned long flags; 379 speed_t baud; 380 381 cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); 382 if (!cfg) 383 return; 384 385 /* lock while we are modifying the settings */ 386 spin_lock_irqsave(&priv->lock, flags); 387 388 /* 389 * Update baud rate 390 */ 391 baud = tty_get_baud_rate(tty); 392 393 switch (baud) { 394 case 0: /* handled below */ 395 break; 396 case 1200: 397 priv->cfg.baudrate = kl5kusb105a_sio_b1200; 398 break; 399 case 2400: 400 priv->cfg.baudrate = kl5kusb105a_sio_b2400; 401 break; 402 case 4800: 403 priv->cfg.baudrate = kl5kusb105a_sio_b4800; 404 break; 405 case 9600: 406 priv->cfg.baudrate = kl5kusb105a_sio_b9600; 407 break; 408 case 19200: 409 priv->cfg.baudrate = kl5kusb105a_sio_b19200; 410 break; 411 case 38400: 412 priv->cfg.baudrate = kl5kusb105a_sio_b38400; 413 break; 414 case 57600: 415 priv->cfg.baudrate = kl5kusb105a_sio_b57600; 416 break; 417 case 115200: 418 priv->cfg.baudrate = kl5kusb105a_sio_b115200; 419 break; 420 default: 421 dev_dbg(dev, "unsupported baudrate, using 9600\n"); 422 priv->cfg.baudrate = kl5kusb105a_sio_b9600; 423 baud = 9600; 424 break; 425 } 426 427 /* 428 * FIXME: implement B0 handling 429 * 430 * Maybe this should be simulated by sending read disable and read 431 * enable messages? 432 */ 433 434 tty_encode_baud_rate(tty, baud, baud); 435 436 if ((cflag & CSIZE) != (old_cflag & CSIZE)) { 437 /* set the number of data bits */ 438 switch (cflag & CSIZE) { 439 case CS5: 440 dev_dbg(dev, "%s - 5 bits/byte not supported\n", __func__); 441 spin_unlock_irqrestore(&priv->lock, flags); 442 goto err; 443 case CS6: 444 dev_dbg(dev, "%s - 6 bits/byte not supported\n", __func__); 445 spin_unlock_irqrestore(&priv->lock, flags); 446 goto err; 447 case CS7: 448 priv->cfg.databits = kl5kusb105a_dtb_7; 449 break; 450 case CS8: 451 priv->cfg.databits = kl5kusb105a_dtb_8; 452 break; 453 default: 454 dev_err(dev, "CSIZE was not CS5-CS8, using default of 8\n"); 455 priv->cfg.databits = kl5kusb105a_dtb_8; 456 break; 457 } 458 } 459 460 /* 461 * Update line control register (LCR) 462 */ 463 if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD)) 464 || (cflag & CSTOPB) != (old_cflag & CSTOPB)) { 465 /* Not currently supported */ 466 tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB); 467 } 468 /* 469 * Set flow control: well, I do not really now how to handle DTR/RTS. 470 * Just do what we have seen with SniffUSB on Win98. 471 */ 472 if ((iflag & IXOFF) != (old_iflag & IXOFF) 473 || (iflag & IXON) != (old_iflag & IXON) 474 || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { 475 /* Not currently supported */ 476 tty->termios.c_cflag &= ~CRTSCTS; 477 } 478 memcpy(cfg, &priv->cfg, sizeof(*cfg)); 479 spin_unlock_irqrestore(&priv->lock, flags); 480 481 /* now commit changes to device */ 482 klsi_105_chg_port_settings(port, cfg); 483err: 484 kfree(cfg); 485} 486 487static int klsi_105_tiocmget(struct tty_struct *tty) 488{ 489 struct usb_serial_port *port = tty->driver_data; 490 struct klsi_105_private *priv = usb_get_serial_port_data(port); 491 unsigned long flags; 492 int rc; 493 unsigned long line_state; 494 495 rc = klsi_105_get_line_state(port, &line_state); 496 if (rc < 0) { 497 dev_err(&port->dev, 498 "Reading line control failed (error = %d)\n", rc); 499 /* better return value? EAGAIN? */ 500 return rc; 501 } 502 503 spin_lock_irqsave(&priv->lock, flags); 504 priv->line_state = line_state; 505 spin_unlock_irqrestore(&priv->lock, flags); 506 dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state); 507 return (int)line_state; 508} 509 510module_usb_serial_driver(serial_drivers, id_table); 511 512MODULE_AUTHOR(DRIVER_AUTHOR); 513MODULE_DESCRIPTION(DRIVER_DESC); 514MODULE_LICENSE("GPL");