linux/drivers/usb/serial/ch341.c
<<
>>
Prefs
   1/*
   2 * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
   3 *
   4 * ch341.c implements a serial port driver for the Winchiphead CH341.
   5 *
   6 * The CH341 device can be used to implement an RS232 asynchronous
   7 * serial port, an IEEE-1284 parallel printer port or a memory-like
   8 * interface. In all cases the CH341 supports an I2C interface as well.
   9 * This driver only supports the asynchronous serial interface.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License version
  13 * 2 as published by the Free Software Foundation.
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/init.h>
  18#include <linux/tty.h>
  19#include <linux/module.h>
  20#include <linux/usb.h>
  21#include <linux/usb/serial.h>
  22#include <linux/serial.h>
  23
  24#define DEFAULT_BAUD_RATE 2400
  25#define DEFAULT_TIMEOUT   1000
  26
  27static int debug;
  28
  29static struct usb_device_id id_table [] = {
  30        { USB_DEVICE(0x4348, 0x5523) },
  31        { },
  32};
  33MODULE_DEVICE_TABLE(usb, id_table);
  34
  35struct ch341_private {
  36        unsigned baud_rate;
  37        u8 dtr;
  38        u8 rts;
  39};
  40
  41static int ch341_control_out(struct usb_device *dev, u8 request,
  42                             u16 value, u16 index)
  43{
  44        int r;
  45        dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
  46                (int)request, (int)value, (int)index);
  47
  48        r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
  49                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
  50                            value, index, NULL, 0, DEFAULT_TIMEOUT);
  51
  52        return r;
  53}
  54
  55static int ch341_control_in(struct usb_device *dev,
  56                            u8 request, u16 value, u16 index,
  57                            char *buf, unsigned bufsize)
  58{
  59        int r;
  60        dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
  61                (int)request, (int)value, (int)index, buf, (int)bufsize);
  62
  63        r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
  64                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
  65                            value, index, buf, bufsize, DEFAULT_TIMEOUT);
  66        return r;
  67}
  68
  69static int ch341_set_baudrate(struct usb_device *dev,
  70                              struct ch341_private *priv)
  71{
  72        short a, b;
  73        int r;
  74
  75        dbg("ch341_set_baudrate(%d)", priv->baud_rate);
  76        switch (priv->baud_rate) {
  77        case 2400:
  78                a = 0xd901;
  79                b = 0x0038;
  80                break;
  81        case 4800:
  82                a = 0x6402;
  83                b = 0x001f;
  84                break;
  85        case 9600:
  86                a = 0xb202;
  87                b = 0x0013;
  88                break;
  89        case 19200:
  90                a = 0xd902;
  91                b = 0x000d;
  92                break;
  93        case 38400:
  94                a = 0x6403;
  95                b = 0x000a;
  96                break;
  97        case 115200:
  98                a = 0xcc03;
  99                b = 0x0008;
 100                break;
 101        default:
 102                return -EINVAL;
 103        }
 104
 105        r = ch341_control_out(dev, 0x9a, 0x1312, a);
 106        if (!r)
 107                r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
 108
 109        return r;
 110}
 111
 112static int ch341_set_handshake(struct usb_device *dev,
 113                               struct ch341_private *priv)
 114{
 115        dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
 116        return ch341_control_out(dev, 0xa4,
 117                ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
 118}
 119
 120static int ch341_get_status(struct usb_device *dev)
 121{
 122        char *buffer;
 123        int r;
 124        const unsigned size = 8;
 125
 126        dbg("ch341_get_status()");
 127
 128        buffer = kmalloc(size, GFP_KERNEL);
 129        if (!buffer)
 130                return -ENOMEM;
 131
 132        r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
 133        if ( r < 0)
 134                goto out;
 135
 136        /* Not having the datasheet for the CH341, we ignore the bytes returned
 137         * from the device. Return error if the device did not respond in time.
 138         */
 139        r = 0;
 140
 141out:    kfree(buffer);
 142        return r;
 143}
 144
 145/* -------------------------------------------------------------------------- */
 146
 147static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
 148{
 149        char *buffer;
 150        int r;
 151        const unsigned size = 8;
 152
 153        dbg("ch341_configure()");
 154
 155        buffer = kmalloc(size, GFP_KERNEL);
 156        if (!buffer)
 157                return -ENOMEM;
 158
 159        /* expect two bytes 0x27 0x00 */
 160        r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
 161        if (r < 0)
 162                goto out;
 163
 164        r = ch341_control_out(dev, 0xa1, 0, 0);
 165        if (r < 0)
 166                goto out;
 167
 168        r = ch341_set_baudrate(dev, priv);
 169        if (r < 0)
 170                goto out;
 171
 172        /* expect two bytes 0x56 0x00 */
 173        r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
 174        if (r < 0)
 175                goto out;
 176
 177        r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
 178        if (r < 0)
 179                goto out;
 180
 181        /* expect 0xff 0xee */
 182        r = ch341_get_status(dev);
 183        if (r < 0)
 184                goto out;
 185
 186        r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
 187        if (r < 0)
 188                goto out;
 189
 190        r = ch341_set_baudrate(dev, priv);
 191        if (r < 0)
 192                goto out;
 193
 194        r = ch341_set_handshake(dev, priv);
 195        if (r < 0)
 196                goto out;
 197
 198        /* expect 0x9f 0xee */
 199        r = ch341_get_status(dev);
 200
 201out:    kfree(buffer);
 202        return r;
 203}
 204
 205/* allocate private data */
 206static int ch341_attach(struct usb_serial *serial)
 207{
 208        struct ch341_private *priv;
 209        int r;
 210
 211        dbg("ch341_attach()");
 212
 213        /* private data */
 214        priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
 215        if (!priv)
 216                return -ENOMEM;
 217
 218        priv->baud_rate = DEFAULT_BAUD_RATE;
 219        priv->dtr = 1;
 220        priv->rts = 1;
 221
 222        r = ch341_configure(serial->dev, priv);
 223        if (r < 0)
 224                goto error;
 225
 226        usb_set_serial_port_data(serial->port[0], priv);
 227        return 0;
 228
 229error:  kfree(priv);
 230        return r;
 231}
 232
 233/* open this device, set default parameters */
 234static int ch341_open(struct usb_serial_port *port, struct file *filp)
 235{
 236        struct usb_serial *serial = port->serial;
 237        struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
 238        int r;
 239
 240        dbg("ch341_open()");
 241
 242        priv->baud_rate = DEFAULT_BAUD_RATE;
 243        priv->dtr = 1;
 244        priv->rts = 1;
 245
 246        r = ch341_configure(serial->dev, priv);
 247        if (r)
 248                goto out;
 249
 250        r = ch341_set_handshake(serial->dev, priv);
 251        if (r)
 252                goto out;
 253
 254        r = ch341_set_baudrate(serial->dev, priv);
 255        if (r)
 256                goto out;
 257
 258        r = usb_serial_generic_open(port, filp);
 259
 260out:    return r;
 261}
 262
 263/* Old_termios contains the original termios settings and
 264 * tty->termios contains the new setting to be used.
 265 */
 266static void ch341_set_termios(struct usb_serial_port *port,
 267                              struct ktermios *old_termios)
 268{
 269        struct ch341_private *priv = usb_get_serial_port_data(port);
 270        struct tty_struct *tty = port->tty;
 271        unsigned baud_rate;
 272
 273        dbg("ch341_set_termios()");
 274
 275        baud_rate = tty_get_baud_rate(tty);
 276
 277        switch (baud_rate) {
 278        case 2400:
 279        case 4800:
 280        case 9600:
 281        case 19200:
 282        case 38400:
 283        case 115200:
 284                priv->baud_rate = baud_rate;
 285                break;
 286        default:
 287                dbg("Rate %d not supported, using %d",
 288                        baud_rate, DEFAULT_BAUD_RATE);
 289                priv->baud_rate = DEFAULT_BAUD_RATE;
 290        }
 291
 292        ch341_set_baudrate(port->serial->dev, priv);
 293
 294        /* Unimplemented:
 295         * (cflag & CSIZE) : data bits [5, 8]
 296         * (cflag & PARENB) : parity {NONE, EVEN, ODD}
 297         * (cflag & CSTOPB) : stop bits [1, 2]
 298         */
 299
 300         /* Copy back the old hardware settings */
 301         tty_termios_copy_hw(tty->termios, old_termios);
 302         /* And re-encode with the new baud */
 303         tty_encode_baud_rate(tty, baud_rate, baud_rate);
 304}
 305
 306static struct usb_driver ch341_driver = {
 307        .name           = "ch341",
 308        .probe          = usb_serial_probe,
 309        .disconnect     = usb_serial_disconnect,
 310        .id_table       = id_table,
 311        .no_dynamic_id  = 1,
 312};
 313
 314static struct usb_serial_driver ch341_device = {
 315        .driver = {
 316                .owner  = THIS_MODULE,
 317                .name   = "ch341-uart",
 318        },
 319        .id_table         = id_table,
 320        .usb_driver       = &ch341_driver,
 321        .num_interrupt_in = NUM_DONT_CARE,
 322        .num_bulk_in      = 1,
 323        .num_bulk_out     = 1,
 324        .num_ports        = 1,
 325        .open             = ch341_open,
 326        .set_termios      = ch341_set_termios,
 327        .attach           = ch341_attach,
 328};
 329
 330static int __init ch341_init(void)
 331{
 332        int retval;
 333
 334        retval = usb_serial_register(&ch341_device);
 335        if (retval)
 336                return retval;
 337        retval = usb_register(&ch341_driver);
 338        if (retval)
 339                usb_serial_deregister(&ch341_device);
 340        return retval;
 341}
 342
 343static void __exit ch341_exit(void)
 344{
 345        usb_deregister(&ch341_driver);
 346        usb_serial_deregister(&ch341_device);
 347}
 348
 349module_init(ch341_init);
 350module_exit(ch341_exit);
 351MODULE_LICENSE("GPL");
 352
 353module_param(debug, bool, S_IRUGO | S_IWUSR);
 354MODULE_PARM_DESC(debug, "Debug enabled or not");
 355
 356/* EOF ch341.c */
 357
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.