linux-old/drivers/usb/serial/mct_u232.c
<<
>>
Prefs
   1/*
   2 * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver
   3 *
   4 *   Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
   5 *
   6 *   This program is free software; you can redistribute it and/or modify
   7 *   it under the terms of the GNU General Public License as published by
   8 *   the Free Software Foundation; either version 2 of the License, or
   9 *   (at your option) any later version.
  10 *
  11 * This program is largely derived from the Belkin USB Serial Adapter Driver
  12 * (see belkin_sa.[ch]). All of the information about the device was acquired
  13 * by using SniffUSB on Windows98. For technical details see mct_u232.h.
  14 *
  15 * William G. Greathouse and Greg Kroah-Hartman provided great help on how to
  16 * do the reverse engineering and how to write a USB serial device driver.
  17 *
  18 * TO BE DONE, TO BE CHECKED:
  19 *   DTR/RTS signal handling may be incomplete or incorrect. I have mainly
  20 *   implemented what I have seen with SniffUSB or found in belkin_sa.c.
  21 *   For further TODOs check also belkin_sa.c.
  22 *
  23 * TEST STATUS:
  24 *   Basic tests have been performed with minicom/zmodem transfers and
  25 *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
  26 *
  27 * 04-Nov-2003 Bill Marr <marr at flex dot com>
  28 *   - Mimic Windows driver by sending 2 USB 'device request' messages
  29 *     following normal 'baud rate change' message.  This allows data to be
  30 *     transmitted to RS-232 devices which don't assert the 'CTS' signal.
  31 *
  32 * 10-Nov-2001 Wolfgang Grandegger
  33 *   - Fixed an endianess problem with the baudrate selection for PowerPC.
  34 *
  35 * 06-Dec-2001 Martin Hamilton <martinh@gnu.org>
  36 *      Added support for the Belkin F5U109 DB9 adaptor
  37 *
  38 * 30-May-2001 Greg Kroah-Hartman
  39 *      switched from using spinlock to a semaphore, which fixes lots of problems.
  40 *
  41 * 04-May-2001 Stelian Pop
  42 *   - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes
  43 *     instead of the device reported 32 (using 32 bytes causes many data
  44 *     loss, Windows driver uses 16 too).
  45 *
  46 * 02-May-2001 Stelian Pop
  47 *   - Fixed the baud calculation for Sitecom U232-P25 model
  48 *
  49 * 08-Apr-2001 gb
  50 *   - Identify version on module load.
  51 *
  52 * 06-Jan-2001 Cornel Ciocirlan 
  53 *   - Added support for Sitecom U232-P25 model (Product Id 0x0230)
  54 *   - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200)
  55 *
  56 * 29-Nov-2000 Greg Kroah-Hartman
  57 *   - Added device id table to fit with 2.4.0-test11 structure.
  58 *   - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed
  59 *     (lots of things will change if/when the usb-serial core changes to
  60 *     handle these issues.
  61 *
  62 * 27-Nov-2000 Wolfgang Grandegger
  63 *   A version for kernel 2.4.0-test10 released to the Linux community 
  64 *   (via linux-usb-devel).
  65 */
  66
  67#include <linux/config.h>
  68#include <linux/kernel.h>
  69#include <linux/errno.h>
  70#include <linux/init.h>
  71#include <linux/slab.h>
  72#include <linux/tty.h>
  73#include <linux/tty_driver.h>
  74#include <linux/tty_flip.h>
  75#include <linux/module.h>
  76#include <linux/spinlock.h>
  77#include <asm/uaccess.h>
  78#include <linux/usb.h>
  79
  80#ifdef CONFIG_USB_SERIAL_DEBUG
  81        static int debug = 1;
  82#else
  83        static int debug;
  84#endif
  85
  86#include "usb-serial.h"
  87#include "mct_u232.h"
  88
  89/*
  90 * Version Information
  91 */
  92#define DRIVER_VERSION "z2.0"           /* Linux in-kernel version */
  93#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
  94#define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
  95
  96/*
  97 * Function prototypes
  98 */
  99static int  mct_u232_startup             (struct usb_serial *serial);
 100static void mct_u232_shutdown            (struct usb_serial *serial);
 101static int  mct_u232_open                (struct usb_serial_port *port,
 102                                          struct file *filp);
 103static void mct_u232_close               (struct usb_serial_port *port,
 104                                          struct file *filp);
 105static void mct_u232_read_int_callback   (struct urb *urb);
 106static void mct_u232_set_termios         (struct usb_serial_port *port,
 107                                          struct termios * old);
 108static int  mct_u232_ioctl               (struct usb_serial_port *port,
 109                                          struct file * file,
 110                                          unsigned int cmd,
 111                                          unsigned long arg);
 112static void mct_u232_break_ctl           (struct usb_serial_port *port,
 113                                          int break_state );
 114
 115/*
 116 * All of the device info needed for the MCT USB-RS232 converter.
 117 */
 118static struct usb_device_id id_table_combined [] = {
 119        { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
 120        { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
 121        { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
 122        { USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
 123        { }             /* Terminating entry */
 124};
 125
 126MODULE_DEVICE_TABLE (usb, id_table_combined);
 127
 128
 129static struct usb_serial_device_type mct_u232_device = {
 130        .owner =             THIS_MODULE,
 131        .name =              "MCT U232",
 132        .id_table =          id_table_combined,
 133        .num_interrupt_in =  2,
 134        .num_bulk_in =       0,
 135        .num_bulk_out =      1,
 136        .num_ports =         1,
 137        .open =              mct_u232_open,
 138        .close =             mct_u232_close,
 139        .read_int_callback = mct_u232_read_int_callback,
 140        .ioctl =             mct_u232_ioctl,
 141        .set_termios =       mct_u232_set_termios,
 142        .break_ctl =         mct_u232_break_ctl,
 143        .startup =           mct_u232_startup,
 144        .shutdown =          mct_u232_shutdown,
 145};
 146
 147struct mct_u232_interval_kludge {
 148        int ecnt;                       /* Error counter */
 149        int ibase;                      /* Initial interval value */
 150};
 151
 152struct mct_u232_private {
 153        spinlock_t lock;
 154        struct mct_u232_interval_kludge ik[2];
 155        unsigned int         control_state; /* Modem Line Setting (TIOCM) */
 156        unsigned char        last_lcr;      /* Line Control Register */
 157        unsigned char        last_lsr;      /* Line Status Register */
 158        unsigned char        last_msr;      /* Modem Status Register */
 159};
 160
 161/*
 162 * Handle vendor specific USB requests
 163 */
 164
 165#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 166
 167/*
 168 * Later day 2.6.0-test kernels have new baud rates like B230400 which
 169 * we do not know how to support. We ignore them for the moment.
 170 * XXX Rate-limit the error message, it's user triggerable.
 171 */
 172static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value) {
 173        if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID
 174          || serial->dev->descriptor.idProduct == MCT_U232_BELKIN_F5U109_PID) {
 175                switch (value) {
 176                case    B300: return 0x01;
 177                case    B600: return 0x02; /* this one not tested */
 178                case   B1200: return 0x03;
 179                case   B2400: return 0x04;
 180                case   B4800: return 0x06;
 181                case   B9600: return 0x08;
 182                case  B19200: return 0x09;
 183                case  B38400: return 0x0a;
 184                case  B57600: return 0x0b;
 185                case B115200: return 0x0c;
 186                default:
 187                        err("MCT USB-RS232: unsupported baudrate request 0x%x,"
 188                            " using default of B9600", value);
 189                        return 0x08;
 190                }
 191        } else {
 192                switch (value) {
 193                case    B300: value =     300; break;
 194                case    B600: value =     600; break;
 195                case   B1200: value =    1200; break;
 196                case   B2400: value =    2400; break;
 197                case   B4800: value =    4800; break;
 198                case   B9600: value =    9600; break;
 199                case  B19200: value =   19200; break;
 200                case  B38400: value =   38400; break;
 201                case  B57600: value =   57600; break;
 202                case B115200: value =  115200; break;
 203                default:
 204                        err("MCT USB-RS232: unsupported baudrate request 0x%x,"
 205                            " using default of B9600", value);
 206                        value = 9600;
 207                }
 208                return 115200/value;
 209        }
 210}
 211
 212static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
 213{
 214        unsigned int divisor;
 215        int rc;
 216        unsigned char zero_byte = 0;
 217
 218        divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
 219
 220        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 221                             MCT_U232_SET_BAUD_RATE_REQUEST,
 222                             MCT_U232_SET_REQUEST_TYPE,
 223                             0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
 224                             WDR_TIMEOUT);
 225        if (rc < 0)
 226                err("Set BAUD RATE %d failed (error = %d)", value, rc);
 227        dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
 228
 229        /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
 230           always sends two extra USB 'device request' messages after the
 231           'baud rate change' message.  The actual functionality of the
 232           request codes in these messages is not fully understood but these
 233           particular codes are never seen in any operation besides a baud
 234           rate change.  Both of these messages send a single byte of data
 235           whose value is always zero.  The second of these two extra messages
 236           is required in order for data to be properly written to an RS-232
 237           device which does not assert the 'CTS' signal. */
 238
 239        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 240                             MCT_U232_SET_UNKNOWN1_REQUEST, 
 241                             MCT_U232_SET_REQUEST_TYPE,
 242                             0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE, 
 243                             WDR_TIMEOUT);
 244        if (rc < 0)
 245                err("Sending USB device request code %d failed (error = %d)", 
 246                    MCT_U232_SET_UNKNOWN1_REQUEST, rc);
 247
 248        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 249                             MCT_U232_SET_UNKNOWN2_REQUEST, 
 250                             MCT_U232_SET_REQUEST_TYPE,
 251                             0, 0, &zero_byte, MCT_U232_SET_UNKNOWN2_SIZE, 
 252                             WDR_TIMEOUT);
 253        if (rc < 0)
 254                err("Sending USB device request code %d failed (error = %d)", 
 255                    MCT_U232_SET_UNKNOWN2_REQUEST, rc);
 256
 257        return rc;
 258} /* mct_u232_set_baud_rate */
 259
 260static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
 261{
 262        int rc;
 263        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 264                             MCT_U232_SET_LINE_CTRL_REQUEST,
 265                             MCT_U232_SET_REQUEST_TYPE,
 266                             0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
 267                             WDR_TIMEOUT);
 268        if (rc < 0)
 269                err("Set LINE CTRL 0x%x failed (error = %d)", lcr, rc);
 270        dbg("set_line_ctrl: 0x%x", lcr);
 271        return rc;
 272} /* mct_u232_set_line_ctrl */
 273
 274static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
 275                                   unsigned int control_state)
 276{
 277        int rc;
 278        unsigned char mcr = MCT_U232_MCR_NONE;
 279
 280        if (control_state & TIOCM_DTR)
 281                mcr |= MCT_U232_MCR_DTR;
 282        if (control_state & TIOCM_RTS)
 283                mcr |= MCT_U232_MCR_RTS;
 284
 285        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 286                             MCT_U232_SET_MODEM_CTRL_REQUEST,
 287                             MCT_U232_SET_REQUEST_TYPE,
 288                             0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
 289                             WDR_TIMEOUT);
 290        if (rc < 0)
 291                err("Set MODEM CTRL 0x%x failed (error = %d)", mcr, rc);
 292        dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
 293
 294        return rc;
 295} /* mct_u232_set_modem_ctrl */
 296
 297static int mct_u232_get_modem_stat(struct usb_serial *serial, unsigned char *msr)
 298{
 299        int rc;
 300        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 301                             MCT_U232_GET_MODEM_STAT_REQUEST,
 302                             MCT_U232_GET_REQUEST_TYPE,
 303                             0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
 304                             WDR_TIMEOUT);
 305        if (rc < 0) {
 306                err("Get MODEM STATus failed (error = %d)", rc);
 307                *msr = 0;
 308        }
 309        dbg("get_modem_stat: 0x%x", *msr);
 310        return rc;
 311} /* mct_u232_get_modem_stat */
 312
 313static void mct_u232_msr_to_state(unsigned int *control_state, unsigned char msr)
 314{
 315        /* Translate Control Line states */
 316        if (msr & MCT_U232_MSR_DSR)
 317                *control_state |=  TIOCM_DSR;
 318        else
 319                *control_state &= ~TIOCM_DSR;
 320        if (msr & MCT_U232_MSR_CTS)
 321                *control_state |=  TIOCM_CTS;
 322        else
 323                *control_state &= ~TIOCM_CTS;
 324        if (msr & MCT_U232_MSR_RI)
 325                *control_state |=  TIOCM_RI;
 326        else
 327                *control_state &= ~TIOCM_RI;
 328        if (msr & MCT_U232_MSR_CD)
 329                *control_state |=  TIOCM_CD;
 330        else
 331                *control_state &= ~TIOCM_CD;
 332        dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
 333} /* mct_u232_msr_to_state */
 334
 335/*
 336 * Driver's tty interface functions
 337 */
 338
 339static int mct_u232_startup (struct usb_serial *serial)
 340{
 341        struct mct_u232_private *priv;
 342        struct usb_serial_port *port, *rport;
 343
 344        priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
 345        if (!priv)
 346                return -ENOMEM;
 347        memset(priv, 0, sizeof(struct mct_u232_private));
 348        spin_lock_init(&priv->lock);
 349        serial->port->private = priv;
 350
 351        init_waitqueue_head(&serial->port->write_wait);
 352
 353        /* Puh, that's dirty */
 354        port = &serial->port[0];
 355        rport = &serial->port[1];
 356        if (port->read_urb) {
 357                /* No unlinking, it wasn't submitted yet. */
 358                usb_free_urb(port->read_urb);
 359        }
 360        port->read_urb = rport->interrupt_in_urb;
 361        rport->interrupt_in_urb = NULL;
 362        port->read_urb->context = port;
 363
 364        priv->ik[0].ibase = port->read_urb->interval;
 365        priv->ik[1].ibase = port->interrupt_in_urb->interval;
 366
 367        return (0);
 368} /* mct_u232_startup */
 369
 370
 371static void mct_u232_shutdown (struct usb_serial *serial)
 372{
 373        struct mct_u232_private *priv;
 374        int i;
 375        
 376        dbg("%s", __FUNCTION__);
 377
 378        for (i=0; i < serial->num_ports; ++i) {
 379                /* My special items, the standard routines free my urbs */
 380                priv = serial->port[i].private;
 381                if (priv) {
 382                        serial->port[i].private = NULL;
 383                        kfree(priv);
 384                }
 385        }
 386} /* mct_u232_shutdown */
 387
 388static int  mct_u232_open (struct usb_serial_port *port, struct file *filp)
 389{
 390        struct usb_serial *serial = port->serial;
 391        struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 392        int retval = 0;
 393        unsigned int control_state;
 394        unsigned long flags;
 395        unsigned char last_lcr;
 396        unsigned char last_msr;
 397
 398        dbg("%s port %d", __FUNCTION__, port->number);
 399
 400        /* Compensate for a hardware bug: although the Sitecom U232-P25
 401         * device reports a maximum output packet size of 32 bytes,
 402         * it seems to be able to accept only 16 bytes (and that's what
 403         * SniffUSB says too...)
 404         */
 405        if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
 406                port->bulk_out_size = 16;
 407
 408        /* Do a defined restart: the normal serial device seems to 
 409         * always turn on DTR and RTS here, so do the same. I'm not
 410         * sure if this is really necessary. But it should not harm
 411         * either.
 412         */
 413        spin_lock_irqsave(&priv->lock, flags);
 414        if (port->tty->termios->c_cflag & CBAUD)
 415                priv->control_state = TIOCM_DTR | TIOCM_RTS;
 416        else
 417                priv->control_state = 0;
 418        
 419        priv->last_lcr = (MCT_U232_DATA_BITS_8 | 
 420                          MCT_U232_PARITY_NONE |
 421                          MCT_U232_STOP_BITS_1);
 422        control_state = priv->control_state;
 423        last_lcr = priv->last_lcr;
 424        spin_unlock_irqrestore(&priv->lock, flags);
 425        mct_u232_set_modem_ctrl(serial, control_state);
 426        mct_u232_set_line_ctrl(serial, last_lcr);
 427
 428        /* Read modem status and update control state */
 429        mct_u232_get_modem_stat(serial, &last_msr);
 430        spin_lock_irqsave(&priv->lock, flags);
 431        priv->last_msr = last_msr;
 432        mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
 433        spin_unlock_irqrestore(&priv->lock, flags);
 434
 435        port->read_urb->dev = port->serial->dev;
 436        port->read_urb->interval = priv->ik[0].ibase;
 437        retval = usb_submit_urb(port->read_urb);
 438        if (retval) {
 439                err("usb_submit_urb(read bulk) failed pipe 0x%x err %d",
 440                    port->read_urb->pipe, retval);
 441                goto exit;
 442        }
 443
 444        port->interrupt_in_urb->dev = port->serial->dev;
 445        port->interrupt_in_urb->interval = priv->ik[1].ibase;
 446        retval = usb_submit_urb(port->interrupt_in_urb);
 447        if (retval)
 448                err(" usb_submit_urb(read int) failed pipe 0x%x err %d",
 449                    port->interrupt_in_urb->pipe, retval);
 450
 451exit:
 452        return 0;
 453} /* mct_u232_open */
 454
 455
 456static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
 457{
 458        dbg("%s port %d", __FUNCTION__, port->number);
 459
 460        if (port->serial->dev) {
 461                /* shutdown our urbs */
 462                usb_unlink_urb (port->write_urb);
 463                usb_unlink_urb (port->read_urb);
 464                usb_unlink_urb (port->interrupt_in_urb);
 465        }
 466} /* mct_u232_close */
 467
 468static void mct_u232_error_step (struct urb *urb,
 469    struct mct_u232_private *priv, int n)
 470{
 471        struct mct_u232_interval_kludge *ikp = &priv->ik[n];
 472
 473        if (ikp->ecnt >= 2) {
 474                if (urb->interval)
 475                        err("%s - too many errors: "
 476                            "status %d pipe 0x%x interval %d",
 477                            __FUNCTION__,
 478                            urb->status, urb->pipe, urb->interval);
 479                urb->interval = 0;
 480        } else {
 481                ++ikp->ecnt;
 482        }
 483}
 484
 485static void mct_u232_read_int_callback (struct urb *urb)
 486{
 487        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 488        struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 489        struct usb_serial *serial = port->serial;
 490        struct tty_struct *tty;
 491        unsigned char *data = urb->transfer_buffer;
 492        unsigned long flags;
 493
 494        /* The urb might have been killed. */
 495        if (urb->status) {
 496                dbg("%s - nonzero status %d, pipe 0x%x flags 0x%x interval %d",
 497                    __FUNCTION__,
 498                    urb->status, urb->pipe, urb->transfer_flags, urb->interval);
 499                /*
 500                 * The bad stuff happens when a device is disconnected.
 501                 * This can cause us to spin while trying to resubmit.
 502                 * Unfortunately, in kernel 2.4 error codes are wildly
 503                 * different between controllers, so the status is useless.
 504                 * Instead we just refuse to spin too much.
 505                 */
 506                if (urb == port->read_urb)
 507                        mct_u232_error_step(urb, priv, 0);
 508                if (urb == port->interrupt_in_urb)
 509                        mct_u232_error_step(urb, priv, 1);
 510                return;
 511        }
 512        if (!serial) {
 513                dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 514                return;
 515        }
 516
 517        dbg("%s - port %d", __FUNCTION__, port->number);
 518        usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 519
 520        if (urb == port->read_urb)
 521                priv->ik[0].ecnt = 0;
 522        if (urb == port->interrupt_in_urb)
 523                priv->ik[1].ecnt = 0;
 524
 525        /*
 526         * Work-a-round: handle the 'usual' bulk-in pipe here
 527         */
 528        if (urb->transfer_buffer_length > 2) {
 529                int i;
 530                tty = port->tty;
 531                if (urb->actual_length) {
 532                        for (i = 0; i < urb->actual_length ; ++i) {
 533                                tty_insert_flip_char(tty, data[i], 0);
 534                        }
 535                        tty_flip_buffer_push(tty);
 536                }
 537                /* INT urbs are automatically re-submitted */
 538                return;
 539        }
 540        
 541        /*
 542         * The interrupt-in pipe signals exceptional conditions (modem line
 543         * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
 544         */
 545        spin_lock_irqsave(&priv->lock, flags);
 546        priv->last_msr = data[MCT_U232_MSR_INDEX];
 547        
 548        /* Record Control Line states */
 549        mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
 550
 551#if 0
 552        /* Not yet handled. See belin_sa.c for further information */
 553        /* Now to report any errors */
 554        priv->last_lsr = data[MCT_U232_LSR_INDEX];
 555        /*
 556         * fill in the flip buffer here, but I do not know the relation
 557         * to the current/next receive buffer or characters.  I need
 558         * to look in to this before committing any code.
 559         */
 560        if (priv->last_lsr & MCT_U232_LSR_ERR) {
 561                tty = port->tty;
 562                /* Overrun Error */
 563                if (priv->last_lsr & MCT_U232_LSR_OE) {
 564                }
 565                /* Parity Error */
 566                if (priv->last_lsr & MCT_U232_LSR_PE) {
 567                }
 568                /* Framing Error */
 569                if (priv->last_lsr & MCT_U232_LSR_FE) {
 570                }
 571                /* Break Indicator */
 572                if (priv->last_lsr & MCT_U232_LSR_BI) {
 573                }
 574        }
 575#endif
 576        spin_unlock_irqrestore(&priv->lock, flags);
 577
 578        /* INT urbs are automatically re-submitted */
 579} /* mct_u232_read_int_callback */
 580
 581static void mct_u232_set_termios (struct usb_serial_port *port,
 582                                  struct termios *old_termios)
 583{
 584        struct usb_serial *serial = port->serial;
 585        struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 586        unsigned int iflag = port->tty->termios->c_iflag;
 587        unsigned int cflag = port->tty->termios->c_cflag;
 588        unsigned int old_cflag = old_termios->c_cflag;
 589        unsigned long flags;
 590        unsigned int control_state, new_state;
 591        unsigned char last_lcr;
 592
 593        /* get a local copy of the current port settings */
 594        spin_lock_irqsave(&priv->lock, flags);
 595        control_state = priv->control_state;
 596        spin_unlock_irqrestore(&priv->lock, flags);
 597        last_lcr = 0;
 598
 599        /*
 600         * Update baud rate.
 601         * Do not attempt to cache old rates and skip settings,
 602         * disconnects screw such tricks up completely.
 603         * Premature optimization is the root of all evil.
 604         */
 605
 606        /* reassert DTR and (maybe) RTS on transition from B0 */
 607        if ((old_cflag & CBAUD) == B0) {
 608                dbg("%s: baud was B0", __FUNCTION__);
 609                control_state |= TIOCM_DTR;
 610                /* don't set RTS if using hardware flow control */
 611                if (!(old_cflag & CRTSCTS)) {
 612                        control_state |= TIOCM_RTS;
 613                }
 614                mct_u232_set_modem_ctrl(serial, control_state);
 615        }
 616
 617        mct_u232_set_baud_rate(serial, cflag & CBAUD);
 618
 619        if ((cflag & CBAUD) == B0 ) {
 620                dbg("%s: baud is B0", __FUNCTION__);
 621                /* Drop RTS and DTR */
 622                control_state &= ~(TIOCM_DTR | TIOCM_RTS);
 623                mct_u232_set_modem_ctrl(serial, control_state);
 624        }
 625
 626        /*
 627         * Update line control register (LCR)
 628         */
 629
 630        /* set the parity */
 631        if (cflag & PARENB)
 632                last_lcr |= (cflag & PARODD) ?
 633                        MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
 634        else
 635                last_lcr |= MCT_U232_PARITY_NONE;
 636
 637        /* set the number of data bits */
 638        switch (cflag & CSIZE) {
 639        case CS5:
 640                last_lcr |= MCT_U232_DATA_BITS_5; break;
 641        case CS6:
 642                last_lcr |= MCT_U232_DATA_BITS_6; break;
 643        case CS7:
 644                last_lcr |= MCT_U232_DATA_BITS_7; break;
 645        case CS8:
 646                last_lcr |= MCT_U232_DATA_BITS_8; break;
 647        default:
 648                err("CSIZE was not CS5-CS8, using default of 8");
 649                last_lcr |= MCT_U232_DATA_BITS_8;
 650                break;
 651        }
 652
 653        /* set the number of stop bits */
 654        last_lcr |= (cflag & CSTOPB) ?
 655                MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
 656
 657        mct_u232_set_line_ctrl(serial, last_lcr);
 658
 659        /*
 660         * Set flow control: well, I do not really now how to handle DTR/RTS.
 661         * Just do what we have seen with SniffUSB on Win98.
 662         */
 663        /* Drop DTR/RTS if no flow control otherwise assert */
 664        new_state = control_state;
 665        if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
 666                new_state |= TIOCM_DTR | TIOCM_RTS;
 667        else
 668                new_state &= ~(TIOCM_DTR | TIOCM_RTS);
 669        if (new_state != control_state) {
 670                mct_u232_set_modem_ctrl(serial, new_state);
 671                control_state = new_state;
 672        }
 673
 674        /* save off the modified port settings */
 675        spin_lock_irqsave(&priv->lock, flags);
 676        priv->control_state = control_state;
 677        priv->last_lcr = last_lcr;
 678        spin_unlock_irqrestore(&priv->lock, flags);
 679} /* mct_u232_set_termios */
 680
 681static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
 682{
 683        struct usb_serial *serial = port->serial;
 684        struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 685        unsigned char lcr;
 686        unsigned long flags;
 687
 688        dbg("%sstate=%d", __FUNCTION__, break_state);
 689
 690        spin_lock_irqsave(&priv->lock, flags);
 691        lcr = priv->last_lcr;
 692        spin_unlock_irqrestore(&priv->lock, flags);
 693
 694        if (break_state)
 695                lcr |= MCT_U232_SET_BREAK;
 696
 697        mct_u232_set_line_ctrl(serial, lcr);
 698} /* mct_u232_break_ctl */
 699
 700
 701static int mct_u232_tiocmget (struct usb_serial_port *port, struct file *file)
 702{
 703        struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 704        unsigned int control_state;
 705        unsigned long flags;
 706        
 707        dbg("%s", __FUNCTION__);
 708
 709        spin_lock_irqsave(&priv->lock, flags);
 710        control_state = priv->control_state;
 711        spin_unlock_irqrestore(&priv->lock, flags);
 712
 713        return control_state;
 714}
 715
 716static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
 717                           unsigned int cmd, unsigned long arg)
 718{
 719        struct usb_serial *serial = port->serial;
 720        struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
 721        int mask;
 722        unsigned long flags;
 723
 724        dbg("%scmd=0x%x", __FUNCTION__, cmd);
 725
 726        /* Based on code from acm.c and others */
 727        switch (cmd) {
 728        case TIOCMGET:
 729                mask = mct_u232_tiocmget(port, file);
 730                return put_user(mask, (unsigned long *) arg);
 731
 732        case TIOCMSET: /* Turns on and off the lines as specified by the mask */
 733        case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
 734        case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
 735                if (get_user(mask, (unsigned long *) arg))
 736                        return -EFAULT;
 737
 738                spin_lock_irqsave(&priv->lock, flags);
 739                if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
 740                        /* RTS needs set */
 741                        if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
 742                            (cmd == TIOCMBIS) )
 743                                priv->control_state |=  TIOCM_RTS;
 744                        else
 745                                priv->control_state &= ~TIOCM_RTS;
 746                }
 747
 748                if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
 749                        /* DTR needs set */
 750                        if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
 751                            (cmd == TIOCMBIS) )
 752                                priv->control_state |=  TIOCM_DTR;
 753                        else
 754                                priv->control_state &= ~TIOCM_DTR;
 755                }
 756                spin_unlock_irqrestore(&priv->lock, flags);
 757                mct_u232_set_modem_ctrl(serial, priv->control_state);
 758                break;
 759                                        
 760        case TIOCMIWAIT:
 761                /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
 762                /* TODO */
 763                return( 0 );
 764
 765        case TIOCGICOUNT:
 766                /* return count of modemline transitions */
 767                /* TODO */
 768                return 0;
 769
 770        default:
 771                dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd);
 772                return(-ENOIOCTLCMD);
 773                break;
 774        }
 775        return 0;
 776} /* mct_u232_ioctl */
 777
 778
 779static int __init mct_u232_init (void)
 780{
 781        usb_serial_register (&mct_u232_device);
 782        info(DRIVER_DESC " " DRIVER_VERSION);
 783        return 0;
 784}
 785
 786
 787static void __exit mct_u232_exit (void)
 788{
 789        usb_serial_deregister (&mct_u232_device);
 790}
 791
 792
 793module_init (mct_u232_init);
 794module_exit(mct_u232_exit);
 795
 796MODULE_AUTHOR( DRIVER_AUTHOR );
 797MODULE_DESCRIPTION( DRIVER_DESC );
 798MODULE_LICENSE("GPL");
 799
 800MODULE_PARM(debug, "i");
 801MODULE_PARM_DESC(debug, "Debug enabled or not");
 802
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.