linux/drivers/usb/serial/ark3116.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006
   3 *   Simon Schulz (ark3116_driver <at> auctionant.de)
   4 *
   5 * ark3116
   6 * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547,
   7 *   productid=0x0232) (used in a datacable called KQ-U8A)
   8 *
   9 * - based on code by krisfx -> thanks !!
  10 *   (see http://www.linuxquestions.org/questions/showthread.php?p=2184457#post2184457)
  11 *
  12 *  - based on logs created by usbsnoopy
  13 *
  14 * This program is free software; you can redistribute it and/or modify it
  15 * under the terms of the GNU General Public License as published by the
  16 * Free Software Foundation; either version 2 of the License, or (at your
  17 * option) any later version.
  18 */
  19
  20#include <linux/kernel.h>
  21#include <linux/init.h>
  22#include <linux/tty.h>
  23#include <linux/module.h>
  24#include <linux/usb.h>
  25#include <linux/usb/serial.h>
  26#include <linux/serial.h>
  27#include <linux/uaccess.h>
  28
  29
  30static int debug;
  31
  32static struct usb_device_id id_table [] = {
  33        { USB_DEVICE(0x6547, 0x0232) },
  34        { USB_DEVICE(0x18ec, 0x3118) },         /* USB to IrDA adapter */
  35        { },
  36};
  37MODULE_DEVICE_TABLE(usb, id_table);
  38
  39static int is_irda(struct usb_serial *serial)
  40{
  41        struct usb_device *dev = serial->dev;
  42        if (le16_to_cpu(dev->descriptor.idVendor) == 0x18ec &&
  43                        le16_to_cpu(dev->descriptor.idProduct) == 0x3118)
  44                return 1;
  45        return 0;
  46}
  47
  48static inline void ARK3116_SND(struct usb_serial *serial, int seq,
  49                               __u8 request, __u8 requesttype,
  50                               __u16 value, __u16 index)
  51{
  52        int result;
  53        result = usb_control_msg(serial->dev,
  54                                 usb_sndctrlpipe(serial->dev, 0),
  55                                 request, requesttype, value, index,
  56                                 NULL, 0x00, 1000);
  57        dbg("%03d > ok", seq);
  58}
  59
  60static inline void ARK3116_RCV(struct usb_serial *serial, int seq,
  61                               __u8 request, __u8 requesttype,
  62                               __u16 value, __u16 index, __u8 expected,
  63                               char *buf)
  64{
  65        int result;
  66        result = usb_control_msg(serial->dev,
  67                                 usb_rcvctrlpipe(serial->dev, 0),
  68                                 request, requesttype, value, index,
  69                                 buf, 0x0000001, 1000);
  70        if (result)
  71                dbg("%03d < %d bytes [0x%02X]", seq, result,
  72                    ((unsigned char *)buf)[0]);
  73        else
  74                dbg("%03d < 0 bytes", seq);
  75}
  76
  77static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
  78                                     __u8 request, __u8 requesttype,
  79                                     __u16 value, __u16 index, char *buf)
  80{
  81        usb_control_msg(serial->dev,
  82                        usb_rcvctrlpipe(serial->dev, 0),
  83                        request, requesttype, value, index,
  84                        buf, 0x0000001, 1000);
  85}
  86
  87static int ark3116_attach(struct usb_serial *serial)
  88{
  89        char *buf;
  90
  91        buf = kmalloc(1, GFP_KERNEL);
  92        if (!buf) {
  93                dbg("error kmalloc -> out of mem?");
  94                return -ENOMEM;
  95        }
  96
  97        if (is_irda(serial))
  98                dbg("IrDA mode");
  99
 100        /* 3 */
 101        ARK3116_SND(serial, 3, 0xFE, 0x40, 0x0008, 0x0002);
 102        ARK3116_SND(serial, 4, 0xFE, 0x40, 0x0008, 0x0001);
 103        ARK3116_SND(serial, 5, 0xFE, 0x40, 0x0000, 0x0008);
 104        ARK3116_SND(serial, 6, 0xFE, 0x40, is_irda(serial) ? 0x0001 : 0x0000,
 105                    0x000B);
 106
 107        if (is_irda(serial)) {
 108                ARK3116_SND(serial, 1001, 0xFE, 0x40, 0x0000, 0x000C);
 109                ARK3116_SND(serial, 1002, 0xFE, 0x40, 0x0041, 0x000D);
 110                ARK3116_SND(serial, 1003, 0xFE, 0x40, 0x0001, 0x000A);
 111        }
 112
 113        /* <-- seq7 */
 114        ARK3116_RCV(serial,  7, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
 115        ARK3116_SND(serial,  8, 0xFE, 0x40, 0x0080, 0x0003);
 116        ARK3116_SND(serial,  9, 0xFE, 0x40, 0x001A, 0x0000);
 117        ARK3116_SND(serial, 10, 0xFE, 0x40, 0x0000, 0x0001);
 118        ARK3116_SND(serial, 11, 0xFE, 0x40, 0x0000, 0x0003);
 119
 120        /* <-- seq12 */
 121        ARK3116_RCV(serial, 12, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
 122        ARK3116_SND(serial, 13, 0xFE, 0x40, 0x0000, 0x0004);
 123
 124        /* 14 */
 125        ARK3116_RCV(serial, 14, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
 126        ARK3116_SND(serial, 15, 0xFE, 0x40, 0x0000, 0x0004);
 127
 128        /* 16 */
 129        ARK3116_RCV(serial, 16, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
 130        /* --> seq17 */
 131        ARK3116_SND(serial, 17, 0xFE, 0x40, 0x0001, 0x0004);
 132
 133        /* <-- seq18 */
 134        ARK3116_RCV(serial, 18, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
 135
 136        /* --> seq19 */
 137        ARK3116_SND(serial, 19, 0xFE, 0x40, 0x0003, 0x0004);
 138
 139        /* <-- seq20 */
 140        /* seems like serial port status info (RTS, CTS, ...) */
 141        /* returns modem control line status?! */
 142        ARK3116_RCV(serial, 20, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
 143
 144        /* set 9600 baud & do some init?! */
 145        ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
 146        ARK3116_SND(serial, 148, 0xFE, 0x40, 0x0038, 0x0000);
 147        ARK3116_SND(serial, 149, 0xFE, 0x40, 0x0001, 0x0001);
 148        if (is_irda(serial))
 149                ARK3116_SND(serial, 1004, 0xFE, 0x40, 0x0000, 0x0009);
 150        ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
 151        ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
 152        ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
 153        ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
 154        ARK3116_SND(serial, 154, 0xFE, 0x40, 0x0003, 0x0003);
 155
 156        kfree(buf);
 157        return 0;
 158}
 159
 160static void ark3116_init_termios(struct tty_struct *tty)
 161{
 162        struct ktermios *termios = tty->termios;
 163        *termios = tty_std_termios;
 164        termios->c_cflag = B9600 | CS8
 165                                      | CREAD | HUPCL | CLOCAL;
 166        termios->c_ispeed = 9600;
 167        termios->c_ospeed = 9600;
 168}
 169
 170static void ark3116_set_termios(struct tty_struct *tty,
 171                                struct usb_serial_port *port,
 172                                struct ktermios *old_termios)
 173{
 174        struct usb_serial *serial = port->serial;
 175        struct ktermios *termios = tty->termios;
 176        unsigned int cflag = termios->c_cflag;
 177        int baud;
 178        int ark3116_baud;
 179        char *buf;
 180        char config;
 181
 182        config = 0;
 183
 184        dbg("%s - port %d", __func__, port->number);
 185
 186
 187        cflag = termios->c_cflag;
 188        termios->c_cflag &= ~(CMSPAR|CRTSCTS);
 189
 190        buf = kmalloc(1, GFP_KERNEL);
 191        if (!buf) {
 192                dbg("error kmalloc");
 193                *termios = *old_termios;
 194                return;
 195        }
 196
 197        /* set data bit count (8/7/6/5) */
 198        if (cflag & CSIZE) {
 199                switch (cflag & CSIZE) {
 200                case CS5:
 201                        config |= 0x00;
 202                        dbg("setting CS5");
 203                        break;
 204                case CS6:
 205                        config |= 0x01;
 206                        dbg("setting CS6");
 207                        break;
 208                case CS7:
 209                        config |= 0x02;
 210                        dbg("setting CS7");
 211                        break;
 212                default:
 213                        dbg("CSIZE was set but not CS5-CS8, using CS8!");
 214                        /* fall through */
 215                case CS8:
 216                        config |= 0x03;
 217                        dbg("setting CS8");
 218                        break;
 219                }
 220        }
 221
 222        /* set parity (NONE/EVEN/ODD) */
 223        if (cflag & PARENB) {
 224                if (cflag & PARODD) {
 225                        config |= 0x08;
 226                        dbg("setting parity to ODD");
 227                } else {
 228                        config |= 0x18;
 229                        dbg("setting parity to EVEN");
 230                }
 231        } else {
 232                dbg("setting parity to NONE");
 233        }
 234
 235        /* set stop bit (1/2) */
 236        if (cflag & CSTOPB) {
 237                config |= 0x04;
 238                dbg("setting 2 stop bits");
 239        } else {
 240                dbg("setting 1 stop bit");
 241        }
 242
 243        /* set baudrate */
 244        baud = tty_get_baud_rate(tty);
 245
 246        switch (baud) {
 247        case 75:
 248        case 150:
 249        case 300:
 250        case 600:
 251        case 1200:
 252        case 1800:
 253        case 2400:
 254        case 4800:
 255        case 9600:
 256        case 19200:
 257        case 38400:
 258        case 57600:
 259        case 115200:
 260        case 230400:
 261        case 460800:
 262                /* Report the resulting rate back to the caller */
 263                tty_encode_baud_rate(tty, baud, baud);
 264                break;
 265        /* set 9600 as default (if given baudrate is invalid for example) */
 266        default:
 267                tty_encode_baud_rate(tty, 9600, 9600);
 268        case 0:
 269                baud = 9600;
 270        }
 271
 272        /*
 273         * found by try'n'error, be careful, maybe there are other options
 274         * for multiplicator etc! (3.5 for example)
 275         */
 276        if (baud == 460800)
 277                /* strange, for 460800 the formula is wrong
 278                 * if using round() then 9600baud is wrong) */
 279                ark3116_baud = 7;
 280        else
 281                ark3116_baud = 3000000 / baud;
 282
 283        /* ? */
 284        ARK3116_RCV(serial, 0, 0xFE, 0xC0, 0x0000, 0x0003, 0x03, buf);
 285
 286        /* offset = buf[0]; */
 287        /* offset = 0x03; */
 288        /* dbg("using 0x%04X as target for 0x0003:", 0x0080 + offset); */
 289
 290        /* set baudrate */
 291        dbg("setting baudrate to %d (->reg=%d)", baud, ark3116_baud);
 292        ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
 293        ARK3116_SND(serial, 148, 0xFE, 0x40,
 294                            (ark3116_baud & 0x00FF), 0x0000);
 295        ARK3116_SND(serial, 149, 0xFE, 0x40,
 296                            (ark3116_baud & 0xFF00) >> 8, 0x0001);
 297        ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
 298
 299        /* ? */
 300        ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
 301        ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
 302
 303        /* set data bit count, stop bit count & parity: */
 304        dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config);
 305        ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
 306        ARK3116_SND(serial, 154, 0xFE, 0x40, config, 0x0003);
 307
 308        if (cflag & CRTSCTS)
 309                dbg("CRTSCTS not supported by chipset?!");
 310
 311        /* TEST ARK3116_SND(154, 0xFE, 0x40, 0xFFFF, 0x0006); */
 312
 313        kfree(buf);
 314
 315        return;
 316}
 317
 318static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
 319{
 320        struct ktermios tmp_termios;
 321        struct usb_serial *serial = port->serial;
 322        char *buf;
 323        int result = 0;
 324
 325        dbg("%s - port %d", __func__, port->number);
 326
 327        buf = kmalloc(1, GFP_KERNEL);
 328        if (!buf) {
 329                dbg("error kmalloc -> out of mem?");
 330                return -ENOMEM;
 331        }
 332
 333        result = usb_serial_generic_open(tty, port);
 334        if (result)
 335                goto err_out;
 336
 337        /* open */
 338        ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf);
 339
 340        ARK3116_SND(serial, 112, 0xFE, 0x40, 0x0082, 0x0003);
 341        ARK3116_SND(serial, 113, 0xFE, 0x40, 0x001A, 0x0000);
 342        ARK3116_SND(serial, 114, 0xFE, 0x40, 0x0000, 0x0001);
 343        ARK3116_SND(serial, 115, 0xFE, 0x40, 0x0002, 0x0003);
 344
 345        ARK3116_RCV(serial, 116, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
 346        ARK3116_SND(serial, 117, 0xFE, 0x40, 0x0002, 0x0004);
 347
 348        ARK3116_RCV(serial, 118, 0xFE, 0xC0, 0x0000, 0x0004, 0x02, buf);
 349        ARK3116_SND(serial, 119, 0xFE, 0x40, 0x0000, 0x0004);
 350
 351        ARK3116_RCV(serial, 120, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
 352
 353        ARK3116_SND(serial, 121, 0xFE, 0x40, 0x0001, 0x0004);
 354
 355        ARK3116_RCV(serial, 122, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
 356
 357        ARK3116_SND(serial, 123, 0xFE, 0x40, 0x0003, 0x0004);
 358
 359        /* returns different values (control lines?!) */
 360        ARK3116_RCV(serial, 124, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
 361
 362        /* initialise termios */
 363        if (tty)
 364                ark3116_set_termios(tty, port, &tmp_termios);
 365
 366err_out:
 367        kfree(buf);
 368
 369        return result;
 370}
 371
 372static int ark3116_ioctl(struct tty_struct *tty, struct file *file,
 373                         unsigned int cmd, unsigned long arg)
 374{
 375        struct usb_serial_port *port = tty->driver_data;
 376        struct serial_struct serstruct;
 377        void __user *user_arg = (void __user *)arg;
 378
 379        switch (cmd) {
 380        case TIOCGSERIAL:
 381                /* XXX: Some of these values are probably wrong. */
 382                memset(&serstruct, 0, sizeof(serstruct));
 383                serstruct.type = PORT_16654;
 384                serstruct.line = port->serial->minor;
 385                serstruct.port = port->number;
 386                serstruct.custom_divisor = 0;
 387                serstruct.baud_base = 460800;
 388
 389                if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
 390                        return -EFAULT;
 391
 392                return 0;
 393        case TIOCSSERIAL:
 394                if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
 395                        return -EFAULT;
 396                return 0;
 397        default:
 398                dbg("%s cmd 0x%04x not supported", __func__, cmd);
 399                break;
 400        }
 401
 402        return -ENOIOCTLCMD;
 403}
 404
 405static int ark3116_tiocmget(struct tty_struct *tty, struct file *file)
 406{
 407        struct usb_serial_port *port = tty->driver_data;
 408        struct usb_serial *serial = port->serial;
 409        char *buf;
 410        char temp;
 411
 412        /* seems like serial port status info (RTS, CTS, ...) is stored
 413         * in reg(?) 0x0006
 414         * pcb connection point 11 = GND -> sets bit4 of response
 415         * pcb connection point  7 = GND -> sets bit6 of response
 416         */
 417
 418        buf = kmalloc(1, GFP_KERNEL);
 419        if (!buf) {
 420                dbg("error kmalloc");
 421                return -ENOMEM;
 422        }
 423
 424        /* read register */
 425        ARK3116_RCV_QUIET(serial, 0xFE, 0xC0, 0x0000, 0x0006, buf);
 426        temp = buf[0];
 427        kfree(buf);
 428
 429        /* i do not really know if bit4=CTS and bit6=DSR... just a
 430         * quick guess!
 431         */
 432        return (temp & (1<<4) ? TIOCM_CTS : 0)
 433               | (temp & (1<<6) ? TIOCM_DSR : 0);
 434}
 435
 436static struct usb_driver ark3116_driver = {
 437        .name =         "ark3116",
 438        .probe =        usb_serial_probe,
 439        .disconnect =   usb_serial_disconnect,
 440        .id_table =     id_table,
 441        .no_dynamic_id =        1,
 442};
 443
 444static struct usb_serial_driver ark3116_device = {
 445        .driver = {
 446                .owner =        THIS_MODULE,
 447                .name =         "ark3116",
 448        },
 449        .id_table =             id_table,
 450        .usb_driver =           &ark3116_driver,
 451        .num_ports =            1,
 452        .attach =               ark3116_attach,
 453        .set_termios =          ark3116_set_termios,
 454        .init_termios =         ark3116_init_termios,
 455        .ioctl =                ark3116_ioctl,
 456        .tiocmget =             ark3116_tiocmget,
 457        .open =                 ark3116_open,
 458};
 459
 460static int __init ark3116_init(void)
 461{
 462        int retval;
 463
 464        retval = usb_serial_register(&ark3116_device);
 465        if (retval)
 466                return retval;
 467        retval = usb_register(&ark3116_driver);
 468        if (retval)
 469                usb_serial_deregister(&ark3116_device);
 470        return retval;
 471}
 472
 473static void __exit ark3116_exit(void)
 474{
 475        usb_deregister(&ark3116_driver);
 476        usb_serial_deregister(&ark3116_device);
 477}
 478
 479module_init(ark3116_init);
 480module_exit(ark3116_exit);
 481MODULE_LICENSE("GPL");
 482
 483module_param(debug, bool, S_IRUGO | S_IWUSR);
 484MODULE_PARM_DESC(debug, "Debug enabled or not");
 485
 486