1/* 2 * Fintek F81232 USB to serial adaptor driver 3 * 4 * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org) 5 * Copyright (C) 2012 Linux Foundation 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 * 11 */ 12 13#include <linux/kernel.h> 14#include <linux/errno.h> 15#include <linux/slab.h> 16#include <linux/tty.h> 17#include <linux/tty_driver.h> 18#include <linux/tty_flip.h> 19#include <linux/serial.h> 20#include <linux/module.h> 21#include <linux/moduleparam.h> 22#include <linux/mutex.h> 23#include <linux/uaccess.h> 24#include <linux/usb.h> 25#include <linux/usb/serial.h> 26#include <linux/serial_reg.h> 27 28static const struct usb_device_id id_table[] = { 29 { USB_DEVICE(0x1934, 0x0706) }, 30 { } /* Terminating entry */ 31}; 32MODULE_DEVICE_TABLE(usb, id_table); 33 34/* Maximum baudrate for F81232 */ 35#define F81232_MAX_BAUDRATE 115200 36 37/* USB Control EP parameter */ 38#define F81232_REGISTER_REQUEST 0xa0 39#define F81232_GET_REGISTER 0xc0 40#define F81232_SET_REGISTER 0x40 41 42#define SERIAL_BASE_ADDRESS 0x0120 43#define RECEIVE_BUFFER_REGISTER (0x00 + SERIAL_BASE_ADDRESS) 44#define INTERRUPT_ENABLE_REGISTER (0x01 + SERIAL_BASE_ADDRESS) 45#define FIFO_CONTROL_REGISTER (0x02 + SERIAL_BASE_ADDRESS) 46#define LINE_CONTROL_REGISTER (0x03 + SERIAL_BASE_ADDRESS) 47#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS) 48#define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS) 49 50struct f81232_private { 51 struct mutex lock; 52 u8 modem_control; 53 u8 modem_status; 54 struct work_struct interrupt_work; 55 struct usb_serial_port *port; 56}; 57 58static int calc_baud_divisor(speed_t baudrate) 59{ 60 return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate); 61} 62 63static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val) 64{ 65 int status; 66 u8 *tmp; 67 struct usb_device *dev = port->serial->dev; 68 69 tmp = kmalloc(sizeof(*val), GFP_KERNEL); 70 if (!tmp) 71 return -ENOMEM; 72 73 status = usb_control_msg(dev, 74 usb_rcvctrlpipe(dev, 0), 75 F81232_REGISTER_REQUEST, 76 F81232_GET_REGISTER, 77 reg, 78 0, 79 tmp, 80 sizeof(*val), 81 USB_CTRL_GET_TIMEOUT); 82 if (status != sizeof(*val)) { 83 dev_err(&port->dev, "%s failed status: %d\n", __func__, status); 84 85 if (status < 0) 86 status = usb_translate_errors(status); 87 else 88 status = -EIO; 89 } else { 90 status = 0; 91 *val = *tmp; 92 } 93 94 kfree(tmp); 95 return status; 96} 97 98static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val) 99{ 100 int status; 101 u8 *tmp; 102 struct usb_device *dev = port->serial->dev; 103 104 tmp = kmalloc(sizeof(val), GFP_KERNEL); 105 if (!tmp) 106 return -ENOMEM; 107 108 *tmp = val; 109 110 status = usb_control_msg(dev, 111 usb_sndctrlpipe(dev, 0), 112 F81232_REGISTER_REQUEST, 113 F81232_SET_REGISTER, 114 reg, 115 0, 116 tmp, 117 sizeof(val), 118 USB_CTRL_SET_TIMEOUT); 119 if (status != sizeof(val)) { 120 dev_err(&port->dev, "%s failed status: %d\n", __func__, status); 121 122 if (status < 0) 123 status = usb_translate_errors(status); 124 else 125 status = -EIO; 126 } else { 127 status = 0; 128 } 129 130 kfree(tmp); 131 return status; 132} 133 134static void f81232_read_msr(struct usb_serial_port *port) 135{ 136 int status; 137 u8 current_msr; 138 struct tty_struct *tty; 139 struct f81232_private *priv = usb_get_serial_port_data(port); 140 141 mutex_lock(&priv->lock); 142 status = f81232_get_register(port, MODEM_STATUS_REGISTER, 143 ¤t_msr); 144 if (status) { 145 dev_err(&port->dev, "%s fail, status: %d\n", __func__, status); 146 mutex_unlock(&priv->lock); 147 return; 148 } 149 150 if (!(current_msr & UART_MSR_ANY_DELTA)) { 151 mutex_unlock(&priv->lock); 152 return; 153 } 154 155 priv->modem_status = current_msr; 156 157 if (current_msr & UART_MSR_DCTS) 158 port->icount.cts++; 159 if (current_msr & UART_MSR_DDSR) 160 port->icount.dsr++; 161 if (current_msr & UART_MSR_TERI) 162 port->icount.rng++; 163 if (current_msr & UART_MSR_DDCD) { 164 port->icount.dcd++; 165 tty = tty_port_tty_get(&port->port); 166 if (tty) { 167 usb_serial_handle_dcd_change(port, tty, 168 current_msr & UART_MSR_DCD); 169 170 tty_kref_put(tty); 171 } 172 } 173 174 wake_up_interruptible(&port->port.delta_msr_wait); 175 mutex_unlock(&priv->lock); 176} 177 178static int f81232_set_mctrl(struct usb_serial_port *port, 179 unsigned int set, unsigned int clear) 180{ 181 u8 val; 182 int status; 183 struct f81232_private *priv = usb_get_serial_port_data(port); 184 185 if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) 186 return 0; /* no change */ 187 188 /* 'set' takes precedence over 'clear' */ 189 clear &= ~set; 190 191 /* force enable interrupt with OUT2 */ 192 mutex_lock(&priv->lock); 193 val = UART_MCR_OUT2 | priv->modem_control; 194 195 if (clear & TIOCM_DTR) 196 val &= ~UART_MCR_DTR; 197 198 if (clear & TIOCM_RTS) 199 val &= ~UART_MCR_RTS; 200 201 if (set & TIOCM_DTR) 202 val |= UART_MCR_DTR; 203 204 if (set & TIOCM_RTS) 205 val |= UART_MCR_RTS; 206 207 dev_dbg(&port->dev, "%s new:%02x old:%02x\n", __func__, 208 val, priv->modem_control); 209 210 status = f81232_set_register(port, MODEM_CONTROL_REGISTER, val); 211 if (status) { 212 dev_err(&port->dev, "%s set MCR status < 0\n", __func__); 213 mutex_unlock(&priv->lock); 214 return status; 215 } 216 217 priv->modem_control = val; 218 mutex_unlock(&priv->lock); 219 220 return 0; 221} 222 223static void f81232_update_line_status(struct usb_serial_port *port, 224 unsigned char *data, 225 size_t actual_length) 226{ 227 struct f81232_private *priv = usb_get_serial_port_data(port); 228 229 if (!actual_length) 230 return; 231 232 switch (data[0] & 0x07) { 233 case 0x00: /* msr change */ 234 dev_dbg(&port->dev, "IIR: MSR Change: %02x\n", data[0]); 235 schedule_work(&priv->interrupt_work); 236 break; 237 case 0x02: /* tx-empty */ 238 break; 239 case 0x04: /* rx data available */ 240 break; 241 case 0x06: /* lsr change */ 242 /* we can forget it. the LSR will read from bulk-in */ 243 dev_dbg(&port->dev, "IIR: LSR Change: %02x\n", data[0]); 244 break; 245 } 246} 247 248static void f81232_read_int_callback(struct urb *urb) 249{ 250 struct usb_serial_port *port = urb->context; 251 unsigned char *data = urb->transfer_buffer; 252 unsigned int actual_length = urb->actual_length; 253 int status = urb->status; 254 int retval; 255 256 switch (status) { 257 case 0: 258 /* success */ 259 break; 260 case -ECONNRESET: 261 case -ENOENT: 262 case -ESHUTDOWN: 263 /* this urb is terminated, clean up */ 264 dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", 265 __func__, status); 266 return; 267 default: 268 dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", 269 __func__, status); 270 goto exit; 271 } 272 273 usb_serial_debug_data(&port->dev, __func__, 274 urb->actual_length, urb->transfer_buffer); 275 276 f81232_update_line_status(port, data, actual_length); 277 278exit: 279 retval = usb_submit_urb(urb, GFP_ATOMIC); 280 if (retval) 281 dev_err(&urb->dev->dev, 282 "%s - usb_submit_urb failed with result %d\n", 283 __func__, retval); 284} 285 286static void f81232_process_read_urb(struct urb *urb) 287{ 288 struct usb_serial_port *port = urb->context; 289 unsigned char *data = urb->transfer_buffer; 290 char tty_flag; 291 unsigned int i; 292 u8 lsr; 293 294 /* 295 * When opening the port we get a 1-byte packet with the current LSR, 296 * which we discard. 297 */ 298 if ((urb->actual_length < 2) || (urb->actual_length % 2)) 299 return; 300 301 /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */ 302 303 for (i = 0; i < urb->actual_length; i += 2) { 304 tty_flag = TTY_NORMAL; 305 lsr = data[i]; 306 307 if (lsr & UART_LSR_BRK_ERROR_BITS) { 308 if (lsr & UART_LSR_BI) { 309 tty_flag = TTY_BREAK; 310 port->icount.brk++; 311 usb_serial_handle_break(port); 312 } else if (lsr & UART_LSR_PE) { 313 tty_flag = TTY_PARITY; 314 port->icount.parity++; 315 } else if (lsr & UART_LSR_FE) { 316 tty_flag = TTY_FRAME; 317 port->icount.frame++; 318 } 319 320 if (lsr & UART_LSR_OE) { 321 port->icount.overrun++; 322 tty_insert_flip_char(&port->port, 0, 323 TTY_OVERRUN); 324 } 325 } 326 327 if (port->port.console && port->sysrq) { 328 if (usb_serial_handle_sysrq_char(port, data[i + 1])) 329 continue; 330 } 331 332 tty_insert_flip_char(&port->port, data[i + 1], tty_flag); 333 } 334 335 tty_flip_buffer_push(&port->port); 336} 337 338static void f81232_break_ctl(struct tty_struct *tty, int break_state) 339{ 340 /* FIXME - Stubbed out for now */ 341 342 /* 343 * break_state = -1 to turn on break, and 0 to turn off break 344 * see drivers/char/tty_io.c to see it used. 345 * last_set_data_urb_value NEVER has the break bit set in it. 346 */ 347} 348 349static void f81232_set_baudrate(struct usb_serial_port *port, speed_t baudrate) 350{ 351 u8 lcr; 352 int divisor; 353 int status = 0; 354 355 divisor = calc_baud_divisor(baudrate); 356 357 status = f81232_get_register(port, LINE_CONTROL_REGISTER, 358 &lcr); /* get LCR */ 359 if (status) { 360 dev_err(&port->dev, "%s failed to get LCR: %d\n", 361 __func__, status); 362 return; 363 } 364 365 status = f81232_set_register(port, LINE_CONTROL_REGISTER, 366 lcr | UART_LCR_DLAB); /* Enable DLAB */ 367 if (status) { 368 dev_err(&port->dev, "%s failed to set DLAB: %d\n", 369 __func__, status); 370 return; 371 } 372 373 status = f81232_set_register(port, RECEIVE_BUFFER_REGISTER, 374 divisor & 0x00ff); /* low */ 375 if (status) { 376 dev_err(&port->dev, "%s failed to set baudrate MSB: %d\n", 377 __func__, status); 378 goto reapply_lcr; 379 } 380 381 status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, 382 (divisor & 0xff00) >> 8); /* high */ 383 if (status) { 384 dev_err(&port->dev, "%s failed to set baudrate LSB: %d\n", 385 __func__, status); 386 } 387 388reapply_lcr: 389 status = f81232_set_register(port, LINE_CONTROL_REGISTER, 390 lcr & ~UART_LCR_DLAB); 391 if (status) { 392 dev_err(&port->dev, "%s failed to set DLAB: %d\n", 393 __func__, status); 394 } 395} 396 397static int f81232_port_enable(struct usb_serial_port *port) 398{ 399 u8 val; 400 int status; 401 402 /* fifo on, trigger8, clear TX/RX*/ 403 val = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | 404 UART_FCR_CLEAR_XMIT; 405 406 status = f81232_set_register(port, FIFO_CONTROL_REGISTER, val); 407 if (status) { 408 dev_err(&port->dev, "%s failed to set FCR: %d\n", 409 __func__, status); 410 return status; 411 } 412 413 /* MSR Interrupt only, LSR will read from Bulk-in odd byte */ 414 status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, 415 UART_IER_MSI); 416 if (status) { 417 dev_err(&port->dev, "%s failed to set IER: %d\n", 418 __func__, status); 419 return status; 420 } 421 422 return 0; 423} 424 425static int f81232_port_disable(struct usb_serial_port *port) 426{ 427 int status; 428 429 status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, 0); 430 if (status) { 431 dev_err(&port->dev, "%s failed to set IER: %d\n", 432 __func__, status); 433 return status; 434 } 435 436 return 0; 437} 438 439static void f81232_set_termios(struct tty_struct *tty, 440 struct usb_serial_port *port, struct ktermios *old_termios) 441{ 442 u8 new_lcr = 0; 443 int status = 0; 444 speed_t baudrate; 445 446 /* Don't change anything if nothing has changed */ 447 if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) 448 return; 449 450 if (C_BAUD(tty) == B0) 451 f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS); 452 else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) 453 f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0); 454 455 baudrate = tty_get_baud_rate(tty); 456 if (baudrate > 0) { 457 if (baudrate > F81232_MAX_BAUDRATE) { 458 baudrate = F81232_MAX_BAUDRATE; 459 tty_encode_baud_rate(tty, baudrate, baudrate); 460 } 461 f81232_set_baudrate(port, baudrate); 462 } 463 464 if (C_PARENB(tty)) { 465 new_lcr |= UART_LCR_PARITY; 466 467 if (!C_PARODD(tty)) 468 new_lcr |= UART_LCR_EPAR; 469 470 if (C_CMSPAR(tty)) 471 new_lcr |= UART_LCR_SPAR; 472 } 473 474 if (C_CSTOPB(tty)) 475 new_lcr |= UART_LCR_STOP; 476 477 switch (C_CSIZE(tty)) { 478 case CS5: 479 new_lcr |= UART_LCR_WLEN5; 480 break; 481 case CS6: 482 new_lcr |= UART_LCR_WLEN6; 483 break; 484 case CS7: 485 new_lcr |= UART_LCR_WLEN7; 486 break; 487 default: 488 case CS8: 489 new_lcr |= UART_LCR_WLEN8; 490 break; 491 } 492 493 status = f81232_set_register(port, LINE_CONTROL_REGISTER, new_lcr); 494 if (status) { 495 dev_err(&port->dev, "%s failed to set LCR: %d\n", 496 __func__, status); 497 } 498} 499 500static int f81232_tiocmget(struct tty_struct *tty) 501{ 502 int r; 503 struct usb_serial_port *port = tty->driver_data; 504 struct f81232_private *port_priv = usb_get_serial_port_data(port); 505 u8 mcr, msr; 506 507 /* force get current MSR changed state */ 508 f81232_read_msr(port); 509 510 mutex_lock(&port_priv->lock); 511 mcr = port_priv->modem_control; 512 msr = port_priv->modem_status; 513 mutex_unlock(&port_priv->lock); 514 515 r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) | 516 (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) | 517 (msr & UART_MSR_CTS ? TIOCM_CTS : 0) | 518 (msr & UART_MSR_DCD ? TIOCM_CAR : 0) | 519 (msr & UART_MSR_RI ? TIOCM_RI : 0) | 520 (msr & UART_MSR_DSR ? TIOCM_DSR : 0); 521 522 return r; 523} 524 525static int f81232_tiocmset(struct tty_struct *tty, 526 unsigned int set, unsigned int clear) 527{ 528 struct usb_serial_port *port = tty->driver_data; 529 530 return f81232_set_mctrl(port, set, clear); 531} 532 533static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) 534{ 535 int result; 536 537 result = f81232_port_enable(port); 538 if (result) 539 return result; 540 541 /* Setup termios */ 542 if (tty) 543 f81232_set_termios(tty, port, NULL); 544 545 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 546 if (result) { 547 dev_err(&port->dev, "%s - failed submitting interrupt urb," 548 " error %d\n", __func__, result); 549 return result; 550 } 551 552 result = usb_serial_generic_open(tty, port); 553 if (result) { 554 usb_kill_urb(port->interrupt_in_urb); 555 return result; 556 } 557 558 return 0; 559} 560 561static void f81232_close(struct usb_serial_port *port) 562{ 563 f81232_port_disable(port); 564 usb_serial_generic_close(port); 565 usb_kill_urb(port->interrupt_in_urb); 566} 567 568static void f81232_dtr_rts(struct usb_serial_port *port, int on) 569{ 570 if (on) 571 f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0); 572 else 573 f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS); 574} 575 576static int f81232_carrier_raised(struct usb_serial_port *port) 577{ 578 u8 msr; 579 struct f81232_private *priv = usb_get_serial_port_data(port); 580 581 mutex_lock(&priv->lock); 582 msr = priv->modem_status; 583 mutex_unlock(&priv->lock); 584 585 if (msr & UART_MSR_DCD) 586 return 1; 587 return 0; 588} 589 590static int f81232_get_serial_info(struct usb_serial_port *port, 591 unsigned long arg) 592{ 593 struct serial_struct ser; 594 595 memset(&ser, 0, sizeof(ser)); 596 597 ser.type = PORT_16550A; 598 ser.line = port->minor; 599 ser.port = port->port_number; 600 ser.baud_base = F81232_MAX_BAUDRATE; 601 602 if (copy_to_user((void __user *)arg, &ser, sizeof(ser))) 603 return -EFAULT; 604 605 return 0; 606} 607 608static int f81232_ioctl(struct tty_struct *tty, 609 unsigned int cmd, unsigned long arg) 610{ 611 struct usb_serial_port *port = tty->driver_data; 612 613 switch (cmd) { 614 case TIOCGSERIAL: 615 return f81232_get_serial_info(port, arg); 616 default: 617 break; 618 } 619 return -ENOIOCTLCMD; 620} 621 622static void f81232_interrupt_work(struct work_struct *work) 623{ 624 struct f81232_private *priv = 625 container_of(work, struct f81232_private, interrupt_work); 626 627 f81232_read_msr(priv->port); 628} 629 630static int f81232_port_probe(struct usb_serial_port *port) 631{ 632 struct f81232_private *priv; 633 634 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 635 if (!priv) 636 return -ENOMEM; 637 638 mutex_init(&priv->lock); 639 INIT_WORK(&priv->interrupt_work, f81232_interrupt_work); 640 641 usb_set_serial_port_data(port, priv); 642 643 port->port.drain_delay = 256; 644 priv->port = port; 645 646 return 0; 647} 648 649static int f81232_port_remove(struct usb_serial_port *port) 650{ 651 struct f81232_private *priv; 652 653 priv = usb_get_serial_port_data(port); 654 kfree(priv); 655 656 return 0; 657} 658 659static struct usb_serial_driver f81232_device = { 660 .driver = { 661 .owner = THIS_MODULE, 662 .name = "f81232", 663 }, 664 .id_table = id_table, 665 .num_ports = 1, 666 .bulk_in_size = 256, 667 .bulk_out_size = 256, 668 .open = f81232_open, 669 .close = f81232_close, 670 .dtr_rts = f81232_dtr_rts, 671 .carrier_raised = f81232_carrier_raised, 672 .ioctl = f81232_ioctl, 673 .break_ctl = f81232_break_ctl, 674 .set_termios = f81232_set_termios, 675 .tiocmget = f81232_tiocmget, 676 .tiocmset = f81232_tiocmset, 677 .tiocmiwait = usb_serial_generic_tiocmiwait, 678 .process_read_urb = f81232_process_read_urb, 679 .read_int_callback = f81232_read_int_callback, 680 .port_probe = f81232_port_probe, 681 .port_remove = f81232_port_remove, 682}; 683 684static struct usb_serial_driver * const serial_drivers[] = { 685 &f81232_device, 686 NULL, 687}; 688 689module_usb_serial_driver(serial_drivers, id_table); 690 691MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver"); 692MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>"); 693MODULE_AUTHOR("Peter Hong <peter_hong@fintek.com.tw>"); 694MODULE_LICENSE("GPL v2"); 695