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