linux/drivers/usb/serial/f81232.c
<<
>>
Prefs
   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                        &current_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