1*03ee2515SGreg Kroah-Hartman /* 2*03ee2515SGreg Kroah-Hartman * Silicon Laboratories CP2101/CP2102 USB to RS232 serial adaptor driver 3*03ee2515SGreg Kroah-Hartman * 4*03ee2515SGreg Kroah-Hartman * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk) 5*03ee2515SGreg Kroah-Hartman * 6*03ee2515SGreg Kroah-Hartman * This program is free software; you can redistribute it and/or 7*03ee2515SGreg Kroah-Hartman * modify it under the terms of the GNU General Public License version 8*03ee2515SGreg Kroah-Hartman * 2 as published by the Free Software Foundation. 9*03ee2515SGreg Kroah-Hartman * 10*03ee2515SGreg Kroah-Hartman * Support to set flow control line levels using TIOCMGET and TIOCMSET 11*03ee2515SGreg Kroah-Hartman * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow 12*03ee2515SGreg Kroah-Hartman * control thanks to Munir Nassar nassarmu@real-time.com 13*03ee2515SGreg Kroah-Hartman * 14*03ee2515SGreg Kroah-Hartman */ 15*03ee2515SGreg Kroah-Hartman 16*03ee2515SGreg Kroah-Hartman #include <linux/kernel.h> 17*03ee2515SGreg Kroah-Hartman #include <linux/errno.h> 18*03ee2515SGreg Kroah-Hartman #include <linux/slab.h> 19*03ee2515SGreg Kroah-Hartman #include <linux/tty.h> 20*03ee2515SGreg Kroah-Hartman #include <linux/tty_flip.h> 21*03ee2515SGreg Kroah-Hartman #include <linux/module.h> 22*03ee2515SGreg Kroah-Hartman #include <linux/moduleparam.h> 23*03ee2515SGreg Kroah-Hartman #include <linux/usb.h> 24*03ee2515SGreg Kroah-Hartman #include <linux/uaccess.h> 25*03ee2515SGreg Kroah-Hartman #include <linux/usb/serial.h> 26*03ee2515SGreg Kroah-Hartman 27*03ee2515SGreg Kroah-Hartman /* 28*03ee2515SGreg Kroah-Hartman * Version Information 29*03ee2515SGreg Kroah-Hartman */ 30*03ee2515SGreg Kroah-Hartman #define DRIVER_VERSION "v0.08" 31*03ee2515SGreg Kroah-Hartman #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver" 32*03ee2515SGreg Kroah-Hartman 33*03ee2515SGreg Kroah-Hartman /* 34*03ee2515SGreg Kroah-Hartman * Function Prototypes 35*03ee2515SGreg Kroah-Hartman */ 36*03ee2515SGreg Kroah-Hartman static int cp2101_open(struct tty_struct *, struct usb_serial_port *, 37*03ee2515SGreg Kroah-Hartman struct file *); 38*03ee2515SGreg Kroah-Hartman static void cp2101_cleanup(struct usb_serial_port *); 39*03ee2515SGreg Kroah-Hartman static void cp2101_close(struct tty_struct *, struct usb_serial_port *, 40*03ee2515SGreg Kroah-Hartman struct file*); 41*03ee2515SGreg Kroah-Hartman static void cp2101_get_termios(struct tty_struct *); 42*03ee2515SGreg Kroah-Hartman static void cp2101_set_termios(struct tty_struct *, struct usb_serial_port *, 43*03ee2515SGreg Kroah-Hartman struct ktermios*); 44*03ee2515SGreg Kroah-Hartman static int cp2101_tiocmget(struct tty_struct *, struct file *); 45*03ee2515SGreg Kroah-Hartman static int cp2101_tiocmset(struct tty_struct *, struct file *, 46*03ee2515SGreg Kroah-Hartman unsigned int, unsigned int); 47*03ee2515SGreg Kroah-Hartman static void cp2101_break_ctl(struct tty_struct *, int); 48*03ee2515SGreg Kroah-Hartman static int cp2101_startup(struct usb_serial *); 49*03ee2515SGreg Kroah-Hartman static void cp2101_shutdown(struct usb_serial *); 50*03ee2515SGreg Kroah-Hartman 51*03ee2515SGreg Kroah-Hartman 52*03ee2515SGreg Kroah-Hartman static int debug; 53*03ee2515SGreg Kroah-Hartman 54*03ee2515SGreg Kroah-Hartman static struct usb_device_id id_table [] = { 55*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */ 56*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ 57*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ 58*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ 59*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ 60*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ 61*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ 62*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ 63*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ 64*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ 65*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ 66*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ 67*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */ 68*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ 69*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ 70*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ 71*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ 72*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ 73*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ 74*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ 75*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ 76*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ 77*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ 78*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ 79*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ 80*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ 81*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ 82*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ 83*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ 84*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ 85*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ 86*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */ 87*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */ 88*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ 89*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ 90*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ 91*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ 92*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ 93*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ 94*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ 95*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ 96*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ 97*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ 98*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ 99*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ 100*03ee2515SGreg Kroah-Hartman { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ 101*03ee2515SGreg Kroah-Hartman { } /* Terminating Entry */ 102*03ee2515SGreg Kroah-Hartman }; 103*03ee2515SGreg Kroah-Hartman 104*03ee2515SGreg Kroah-Hartman MODULE_DEVICE_TABLE(usb, id_table); 105*03ee2515SGreg Kroah-Hartman 106*03ee2515SGreg Kroah-Hartman static struct usb_driver cp2101_driver = { 107*03ee2515SGreg Kroah-Hartman .name = "cp2101", 108*03ee2515SGreg Kroah-Hartman .probe = usb_serial_probe, 109*03ee2515SGreg Kroah-Hartman .disconnect = usb_serial_disconnect, 110*03ee2515SGreg Kroah-Hartman .id_table = id_table, 111*03ee2515SGreg Kroah-Hartman .no_dynamic_id = 1, 112*03ee2515SGreg Kroah-Hartman }; 113*03ee2515SGreg Kroah-Hartman 114*03ee2515SGreg Kroah-Hartman static struct usb_serial_driver cp2101_device = { 115*03ee2515SGreg Kroah-Hartman .driver = { 116*03ee2515SGreg Kroah-Hartman .owner = THIS_MODULE, 117*03ee2515SGreg Kroah-Hartman .name = "cp2101", 118*03ee2515SGreg Kroah-Hartman }, 119*03ee2515SGreg Kroah-Hartman .usb_driver = &cp2101_driver, 120*03ee2515SGreg Kroah-Hartman .id_table = id_table, 121*03ee2515SGreg Kroah-Hartman .num_ports = 1, 122*03ee2515SGreg Kroah-Hartman .open = cp2101_open, 123*03ee2515SGreg Kroah-Hartman .close = cp2101_close, 124*03ee2515SGreg Kroah-Hartman .break_ctl = cp2101_break_ctl, 125*03ee2515SGreg Kroah-Hartman .set_termios = cp2101_set_termios, 126*03ee2515SGreg Kroah-Hartman .tiocmget = cp2101_tiocmget, 127*03ee2515SGreg Kroah-Hartman .tiocmset = cp2101_tiocmset, 128*03ee2515SGreg Kroah-Hartman .attach = cp2101_startup, 129*03ee2515SGreg Kroah-Hartman .shutdown = cp2101_shutdown, 130*03ee2515SGreg Kroah-Hartman }; 131*03ee2515SGreg Kroah-Hartman 132*03ee2515SGreg Kroah-Hartman /* Config request types */ 133*03ee2515SGreg Kroah-Hartman #define REQTYPE_HOST_TO_DEVICE 0x41 134*03ee2515SGreg Kroah-Hartman #define REQTYPE_DEVICE_TO_HOST 0xc1 135*03ee2515SGreg Kroah-Hartman 136*03ee2515SGreg Kroah-Hartman /* Config SET requests. To GET, add 1 to the request number */ 137*03ee2515SGreg Kroah-Hartman #define CP2101_UART 0x00 /* Enable / Disable */ 138*03ee2515SGreg Kroah-Hartman #define CP2101_BAUDRATE 0x01 /* (BAUD_RATE_GEN_FREQ / baudrate) */ 139*03ee2515SGreg Kroah-Hartman #define CP2101_BITS 0x03 /* 0x(0)(databits)(parity)(stopbits) */ 140*03ee2515SGreg Kroah-Hartman #define CP2101_BREAK 0x05 /* On / Off */ 141*03ee2515SGreg Kroah-Hartman #define CP2101_CONTROL 0x07 /* Flow control line states */ 142*03ee2515SGreg Kroah-Hartman #define CP2101_MODEMCTL 0x13 /* Modem controls */ 143*03ee2515SGreg Kroah-Hartman #define CP2101_CONFIG_6 0x19 /* 6 bytes of config data ??? */ 144*03ee2515SGreg Kroah-Hartman 145*03ee2515SGreg Kroah-Hartman /* CP2101_UART */ 146*03ee2515SGreg Kroah-Hartman #define UART_ENABLE 0x0001 147*03ee2515SGreg Kroah-Hartman #define UART_DISABLE 0x0000 148*03ee2515SGreg Kroah-Hartman 149*03ee2515SGreg Kroah-Hartman /* CP2101_BAUDRATE */ 150*03ee2515SGreg Kroah-Hartman #define BAUD_RATE_GEN_FREQ 0x384000 151*03ee2515SGreg Kroah-Hartman 152*03ee2515SGreg Kroah-Hartman /* CP2101_BITS */ 153*03ee2515SGreg Kroah-Hartman #define BITS_DATA_MASK 0X0f00 154*03ee2515SGreg Kroah-Hartman #define BITS_DATA_5 0X0500 155*03ee2515SGreg Kroah-Hartman #define BITS_DATA_6 0X0600 156*03ee2515SGreg Kroah-Hartman #define BITS_DATA_7 0X0700 157*03ee2515SGreg Kroah-Hartman #define BITS_DATA_8 0X0800 158*03ee2515SGreg Kroah-Hartman #define BITS_DATA_9 0X0900 159*03ee2515SGreg Kroah-Hartman 160*03ee2515SGreg Kroah-Hartman #define BITS_PARITY_MASK 0x00f0 161*03ee2515SGreg Kroah-Hartman #define BITS_PARITY_NONE 0x0000 162*03ee2515SGreg Kroah-Hartman #define BITS_PARITY_ODD 0x0010 163*03ee2515SGreg Kroah-Hartman #define BITS_PARITY_EVEN 0x0020 164*03ee2515SGreg Kroah-Hartman #define BITS_PARITY_MARK 0x0030 165*03ee2515SGreg Kroah-Hartman #define BITS_PARITY_SPACE 0x0040 166*03ee2515SGreg Kroah-Hartman 167*03ee2515SGreg Kroah-Hartman #define BITS_STOP_MASK 0x000f 168*03ee2515SGreg Kroah-Hartman #define BITS_STOP_1 0x0000 169*03ee2515SGreg Kroah-Hartman #define BITS_STOP_1_5 0x0001 170*03ee2515SGreg Kroah-Hartman #define BITS_STOP_2 0x0002 171*03ee2515SGreg Kroah-Hartman 172*03ee2515SGreg Kroah-Hartman /* CP2101_BREAK */ 173*03ee2515SGreg Kroah-Hartman #define BREAK_ON 0x0000 174*03ee2515SGreg Kroah-Hartman #define BREAK_OFF 0x0001 175*03ee2515SGreg Kroah-Hartman 176*03ee2515SGreg Kroah-Hartman /* CP2101_CONTROL */ 177*03ee2515SGreg Kroah-Hartman #define CONTROL_DTR 0x0001 178*03ee2515SGreg Kroah-Hartman #define CONTROL_RTS 0x0002 179*03ee2515SGreg Kroah-Hartman #define CONTROL_CTS 0x0010 180*03ee2515SGreg Kroah-Hartman #define CONTROL_DSR 0x0020 181*03ee2515SGreg Kroah-Hartman #define CONTROL_RING 0x0040 182*03ee2515SGreg Kroah-Hartman #define CONTROL_DCD 0x0080 183*03ee2515SGreg Kroah-Hartman #define CONTROL_WRITE_DTR 0x0100 184*03ee2515SGreg Kroah-Hartman #define CONTROL_WRITE_RTS 0x0200 185*03ee2515SGreg Kroah-Hartman 186*03ee2515SGreg Kroah-Hartman /* 187*03ee2515SGreg Kroah-Hartman * cp2101_get_config 188*03ee2515SGreg Kroah-Hartman * Reads from the CP2101 configuration registers 189*03ee2515SGreg Kroah-Hartman * 'size' is specified in bytes. 190*03ee2515SGreg Kroah-Hartman * 'data' is a pointer to a pre-allocated array of integers large 191*03ee2515SGreg Kroah-Hartman * enough to hold 'size' bytes (with 4 bytes to each integer) 192*03ee2515SGreg Kroah-Hartman */ 193*03ee2515SGreg Kroah-Hartman static int cp2101_get_config(struct usb_serial_port *port, u8 request, 194*03ee2515SGreg Kroah-Hartman unsigned int *data, int size) 195*03ee2515SGreg Kroah-Hartman { 196*03ee2515SGreg Kroah-Hartman struct usb_serial *serial = port->serial; 197*03ee2515SGreg Kroah-Hartman __le32 *buf; 198*03ee2515SGreg Kroah-Hartman int result, i, length; 199*03ee2515SGreg Kroah-Hartman 200*03ee2515SGreg Kroah-Hartman /* Number of integers required to contain the array */ 201*03ee2515SGreg Kroah-Hartman length = (((size - 1) | 3) + 1)/4; 202*03ee2515SGreg Kroah-Hartman 203*03ee2515SGreg Kroah-Hartman buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); 204*03ee2515SGreg Kroah-Hartman if (!buf) { 205*03ee2515SGreg Kroah-Hartman dev_err(&port->dev, "%s - out of memory.\n", __func__); 206*03ee2515SGreg Kroah-Hartman return -ENOMEM; 207*03ee2515SGreg Kroah-Hartman } 208*03ee2515SGreg Kroah-Hartman 209*03ee2515SGreg Kroah-Hartman /* For get requests, the request number must be incremented */ 210*03ee2515SGreg Kroah-Hartman request++; 211*03ee2515SGreg Kroah-Hartman 212*03ee2515SGreg Kroah-Hartman /* Issue the request, attempting to read 'size' bytes */ 213*03ee2515SGreg Kroah-Hartman result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 214*03ee2515SGreg Kroah-Hartman request, REQTYPE_DEVICE_TO_HOST, 0x0000, 215*03ee2515SGreg Kroah-Hartman 0, buf, size, 300); 216*03ee2515SGreg Kroah-Hartman 217*03ee2515SGreg Kroah-Hartman /* Convert data into an array of integers */ 218*03ee2515SGreg Kroah-Hartman for (i = 0; i < length; i++) 219*03ee2515SGreg Kroah-Hartman data[i] = le32_to_cpu(buf[i]); 220*03ee2515SGreg Kroah-Hartman 221*03ee2515SGreg Kroah-Hartman kfree(buf); 222*03ee2515SGreg Kroah-Hartman 223*03ee2515SGreg Kroah-Hartman if (result != size) { 224*03ee2515SGreg Kroah-Hartman dbg("%s - Unable to send config request, " 225*03ee2515SGreg Kroah-Hartman "request=0x%x size=%d result=%d\n", 226*03ee2515SGreg Kroah-Hartman __func__, request, size, result); 227*03ee2515SGreg Kroah-Hartman return -EPROTO; 228*03ee2515SGreg Kroah-Hartman } 229*03ee2515SGreg Kroah-Hartman 230*03ee2515SGreg Kroah-Hartman return 0; 231*03ee2515SGreg Kroah-Hartman } 232*03ee2515SGreg Kroah-Hartman 233*03ee2515SGreg Kroah-Hartman /* 234*03ee2515SGreg Kroah-Hartman * cp2101_set_config 235*03ee2515SGreg Kroah-Hartman * Writes to the CP2101 configuration registers 236*03ee2515SGreg Kroah-Hartman * Values less than 16 bits wide are sent directly 237*03ee2515SGreg Kroah-Hartman * 'size' is specified in bytes. 238*03ee2515SGreg Kroah-Hartman */ 239*03ee2515SGreg Kroah-Hartman static int cp2101_set_config(struct usb_serial_port *port, u8 request, 240*03ee2515SGreg Kroah-Hartman unsigned int *data, int size) 241*03ee2515SGreg Kroah-Hartman { 242*03ee2515SGreg Kroah-Hartman struct usb_serial *serial = port->serial; 243*03ee2515SGreg Kroah-Hartman __le32 *buf; 244*03ee2515SGreg Kroah-Hartman int result, i, length; 245*03ee2515SGreg Kroah-Hartman 246*03ee2515SGreg Kroah-Hartman /* Number of integers required to contain the array */ 247*03ee2515SGreg Kroah-Hartman length = (((size - 1) | 3) + 1)/4; 248*03ee2515SGreg Kroah-Hartman 249*03ee2515SGreg Kroah-Hartman buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); 250*03ee2515SGreg Kroah-Hartman if (!buf) { 251*03ee2515SGreg Kroah-Hartman dev_err(&port->dev, "%s - out of memory.\n", 252*03ee2515SGreg Kroah-Hartman __func__); 253*03ee2515SGreg Kroah-Hartman return -ENOMEM; 254*03ee2515SGreg Kroah-Hartman } 255*03ee2515SGreg Kroah-Hartman 256*03ee2515SGreg Kroah-Hartman /* Array of integers into bytes */ 257*03ee2515SGreg Kroah-Hartman for (i = 0; i < length; i++) 258*03ee2515SGreg Kroah-Hartman buf[i] = cpu_to_le32(data[i]); 259*03ee2515SGreg Kroah-Hartman 260*03ee2515SGreg Kroah-Hartman if (size > 2) { 261*03ee2515SGreg Kroah-Hartman result = usb_control_msg(serial->dev, 262*03ee2515SGreg Kroah-Hartman usb_sndctrlpipe(serial->dev, 0), 263*03ee2515SGreg Kroah-Hartman request, REQTYPE_HOST_TO_DEVICE, 0x0000, 264*03ee2515SGreg Kroah-Hartman 0, buf, size, 300); 265*03ee2515SGreg Kroah-Hartman } else { 266*03ee2515SGreg Kroah-Hartman result = usb_control_msg(serial->dev, 267*03ee2515SGreg Kroah-Hartman usb_sndctrlpipe(serial->dev, 0), 268*03ee2515SGreg Kroah-Hartman request, REQTYPE_HOST_TO_DEVICE, data[0], 269*03ee2515SGreg Kroah-Hartman 0, NULL, 0, 300); 270*03ee2515SGreg Kroah-Hartman } 271*03ee2515SGreg Kroah-Hartman 272*03ee2515SGreg Kroah-Hartman kfree(buf); 273*03ee2515SGreg Kroah-Hartman 274*03ee2515SGreg Kroah-Hartman if ((size > 2 && result != size) || result < 0) { 275*03ee2515SGreg Kroah-Hartman dbg("%s - Unable to send request, " 276*03ee2515SGreg Kroah-Hartman "request=0x%x size=%d result=%d\n", 277*03ee2515SGreg Kroah-Hartman __func__, request, size, result); 278*03ee2515SGreg Kroah-Hartman return -EPROTO; 279*03ee2515SGreg Kroah-Hartman } 280*03ee2515SGreg Kroah-Hartman 281*03ee2515SGreg Kroah-Hartman /* Single data value */ 282*03ee2515SGreg Kroah-Hartman result = usb_control_msg(serial->dev, 283*03ee2515SGreg Kroah-Hartman usb_sndctrlpipe(serial->dev, 0), 284*03ee2515SGreg Kroah-Hartman request, REQTYPE_HOST_TO_DEVICE, data[0], 285*03ee2515SGreg Kroah-Hartman 0, NULL, 0, 300); 286*03ee2515SGreg Kroah-Hartman return 0; 287*03ee2515SGreg Kroah-Hartman } 288*03ee2515SGreg Kroah-Hartman 289*03ee2515SGreg Kroah-Hartman /* 290*03ee2515SGreg Kroah-Hartman * cp2101_set_config_single 291*03ee2515SGreg Kroah-Hartman * Convenience function for calling cp2101_set_config on single data values 292*03ee2515SGreg Kroah-Hartman * without requiring an integer pointer 293*03ee2515SGreg Kroah-Hartman */ 294*03ee2515SGreg Kroah-Hartman static inline int cp2101_set_config_single(struct usb_serial_port *port, 295*03ee2515SGreg Kroah-Hartman u8 request, unsigned int data) 296*03ee2515SGreg Kroah-Hartman { 297*03ee2515SGreg Kroah-Hartman return cp2101_set_config(port, request, &data, 2); 298*03ee2515SGreg Kroah-Hartman } 299*03ee2515SGreg Kroah-Hartman 300*03ee2515SGreg Kroah-Hartman /* 301*03ee2515SGreg Kroah-Hartman * cp2101_quantise_baudrate 302*03ee2515SGreg Kroah-Hartman * Quantises the baud rate as per AN205 Table 1 303*03ee2515SGreg Kroah-Hartman */ 304*03ee2515SGreg Kroah-Hartman static unsigned int cp2101_quantise_baudrate(unsigned int baud) { 305*03ee2515SGreg Kroah-Hartman if (baud <= 56) baud = 0; 306*03ee2515SGreg Kroah-Hartman else if (baud <= 300) baud = 300; 307*03ee2515SGreg Kroah-Hartman else if (baud <= 600) baud = 600; 308*03ee2515SGreg Kroah-Hartman else if (baud <= 1200) baud = 1200; 309*03ee2515SGreg Kroah-Hartman else if (baud <= 1800) baud = 1800; 310*03ee2515SGreg Kroah-Hartman else if (baud <= 2400) baud = 2400; 311*03ee2515SGreg Kroah-Hartman else if (baud <= 4000) baud = 4000; 312*03ee2515SGreg Kroah-Hartman else if (baud <= 4803) baud = 4800; 313*03ee2515SGreg Kroah-Hartman else if (baud <= 7207) baud = 7200; 314*03ee2515SGreg Kroah-Hartman else if (baud <= 9612) baud = 9600; 315*03ee2515SGreg Kroah-Hartman else if (baud <= 14428) baud = 14400; 316*03ee2515SGreg Kroah-Hartman else if (baud <= 16062) baud = 16000; 317*03ee2515SGreg Kroah-Hartman else if (baud <= 19250) baud = 19200; 318*03ee2515SGreg Kroah-Hartman else if (baud <= 28912) baud = 28800; 319*03ee2515SGreg Kroah-Hartman else if (baud <= 38601) baud = 38400; 320*03ee2515SGreg Kroah-Hartman else if (baud <= 51558) baud = 51200; 321*03ee2515SGreg Kroah-Hartman else if (baud <= 56280) baud = 56000; 322*03ee2515SGreg Kroah-Hartman else if (baud <= 58053) baud = 57600; 323*03ee2515SGreg Kroah-Hartman else if (baud <= 64111) baud = 64000; 324*03ee2515SGreg Kroah-Hartman else if (baud <= 77608) baud = 76800; 325*03ee2515SGreg Kroah-Hartman else if (baud <= 117028) baud = 115200; 326*03ee2515SGreg Kroah-Hartman else if (baud <= 129347) baud = 128000; 327*03ee2515SGreg Kroah-Hartman else if (baud <= 156868) baud = 153600; 328*03ee2515SGreg Kroah-Hartman else if (baud <= 237832) baud = 230400; 329*03ee2515SGreg Kroah-Hartman else if (baud <= 254234) baud = 250000; 330*03ee2515SGreg Kroah-Hartman else if (baud <= 273066) baud = 256000; 331*03ee2515SGreg Kroah-Hartman else if (baud <= 491520) baud = 460800; 332*03ee2515SGreg Kroah-Hartman else if (baud <= 567138) baud = 500000; 333*03ee2515SGreg Kroah-Hartman else if (baud <= 670254) baud = 576000; 334*03ee2515SGreg Kroah-Hartman else if (baud <= 1053257) baud = 921600; 335*03ee2515SGreg Kroah-Hartman else if (baud <= 1474560) baud = 1228800; 336*03ee2515SGreg Kroah-Hartman else if (baud <= 2457600) baud = 1843200; 337*03ee2515SGreg Kroah-Hartman else baud = 3686400; 338*03ee2515SGreg Kroah-Hartman return baud; 339*03ee2515SGreg Kroah-Hartman } 340*03ee2515SGreg Kroah-Hartman 341*03ee2515SGreg Kroah-Hartman static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port, 342*03ee2515SGreg Kroah-Hartman struct file *filp) 343*03ee2515SGreg Kroah-Hartman { 344*03ee2515SGreg Kroah-Hartman struct usb_serial *serial = port->serial; 345*03ee2515SGreg Kroah-Hartman int result; 346*03ee2515SGreg Kroah-Hartman 347*03ee2515SGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 348*03ee2515SGreg Kroah-Hartman 349*03ee2515SGreg Kroah-Hartman if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) { 350*03ee2515SGreg Kroah-Hartman dev_err(&port->dev, "%s - Unable to enable UART\n", 351*03ee2515SGreg Kroah-Hartman __func__); 352*03ee2515SGreg Kroah-Hartman return -EPROTO; 353*03ee2515SGreg Kroah-Hartman } 354*03ee2515SGreg Kroah-Hartman 355*03ee2515SGreg Kroah-Hartman /* Start reading from the device */ 356*03ee2515SGreg Kroah-Hartman usb_fill_bulk_urb(port->read_urb, serial->dev, 357*03ee2515SGreg Kroah-Hartman usb_rcvbulkpipe(serial->dev, 358*03ee2515SGreg Kroah-Hartman port->bulk_in_endpointAddress), 359*03ee2515SGreg Kroah-Hartman port->read_urb->transfer_buffer, 360*03ee2515SGreg Kroah-Hartman port->read_urb->transfer_buffer_length, 361*03ee2515SGreg Kroah-Hartman serial->type->read_bulk_callback, 362*03ee2515SGreg Kroah-Hartman port); 363*03ee2515SGreg Kroah-Hartman result = usb_submit_urb(port->read_urb, GFP_KERNEL); 364*03ee2515SGreg Kroah-Hartman if (result) { 365*03ee2515SGreg Kroah-Hartman dev_err(&port->dev, "%s - failed resubmitting read urb, " 366*03ee2515SGreg Kroah-Hartman "error %d\n", __func__, result); 367*03ee2515SGreg Kroah-Hartman return result; 368*03ee2515SGreg Kroah-Hartman } 369*03ee2515SGreg Kroah-Hartman 370*03ee2515SGreg Kroah-Hartman /* Configure the termios structure */ 371*03ee2515SGreg Kroah-Hartman cp2101_get_termios(tty); 372*03ee2515SGreg Kroah-Hartman 373*03ee2515SGreg Kroah-Hartman /* Set the DTR and RTS pins low */ 374*03ee2515SGreg Kroah-Hartman cp2101_tiocmset(tty, NULL, TIOCM_DTR | TIOCM_RTS, 0); 375*03ee2515SGreg Kroah-Hartman 376*03ee2515SGreg Kroah-Hartman return 0; 377*03ee2515SGreg Kroah-Hartman } 378*03ee2515SGreg Kroah-Hartman 379*03ee2515SGreg Kroah-Hartman static void cp2101_cleanup(struct usb_serial_port *port) 380*03ee2515SGreg Kroah-Hartman { 381*03ee2515SGreg Kroah-Hartman struct usb_serial *serial = port->serial; 382*03ee2515SGreg Kroah-Hartman 383*03ee2515SGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 384*03ee2515SGreg Kroah-Hartman 385*03ee2515SGreg Kroah-Hartman if (serial->dev) { 386*03ee2515SGreg Kroah-Hartman /* shutdown any bulk reads that might be going on */ 387*03ee2515SGreg Kroah-Hartman if (serial->num_bulk_out) 388*03ee2515SGreg Kroah-Hartman usb_kill_urb(port->write_urb); 389*03ee2515SGreg Kroah-Hartman if (serial->num_bulk_in) 390*03ee2515SGreg Kroah-Hartman usb_kill_urb(port->read_urb); 391*03ee2515SGreg Kroah-Hartman } 392*03ee2515SGreg Kroah-Hartman } 393*03ee2515SGreg Kroah-Hartman 394*03ee2515SGreg Kroah-Hartman static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port, 395*03ee2515SGreg Kroah-Hartman struct file *filp) 396*03ee2515SGreg Kroah-Hartman { 397*03ee2515SGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 398*03ee2515SGreg Kroah-Hartman 399*03ee2515SGreg Kroah-Hartman /* shutdown our urbs */ 400*03ee2515SGreg Kroah-Hartman dbg("%s - shutting down urbs", __func__); 401*03ee2515SGreg Kroah-Hartman usb_kill_urb(port->write_urb); 402*03ee2515SGreg Kroah-Hartman usb_kill_urb(port->read_urb); 403*03ee2515SGreg Kroah-Hartman 404*03ee2515SGreg Kroah-Hartman mutex_lock(&port->serial->disc_mutex); 405*03ee2515SGreg Kroah-Hartman if (!port->serial->disconnected) 406*03ee2515SGreg Kroah-Hartman cp2101_set_config_single(port, CP2101_UART, UART_DISABLE); 407*03ee2515SGreg Kroah-Hartman mutex_unlock(&port->serial->disc_mutex); 408*03ee2515SGreg Kroah-Hartman } 409*03ee2515SGreg Kroah-Hartman 410*03ee2515SGreg Kroah-Hartman /* 411*03ee2515SGreg Kroah-Hartman * cp2101_get_termios 412*03ee2515SGreg Kroah-Hartman * Reads the baud rate, data bits, parity, stop bits and flow control mode 413*03ee2515SGreg Kroah-Hartman * from the device, corrects any unsupported values, and configures the 414*03ee2515SGreg Kroah-Hartman * termios structure to reflect the state of the device 415*03ee2515SGreg Kroah-Hartman */ 416*03ee2515SGreg Kroah-Hartman static void cp2101_get_termios (struct tty_struct *tty) 417*03ee2515SGreg Kroah-Hartman { 418*03ee2515SGreg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 419*03ee2515SGreg Kroah-Hartman unsigned int cflag, modem_ctl[4]; 420*03ee2515SGreg Kroah-Hartman unsigned int baud; 421*03ee2515SGreg Kroah-Hartman unsigned int bits; 422*03ee2515SGreg Kroah-Hartman 423*03ee2515SGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 424*03ee2515SGreg Kroah-Hartman 425*03ee2515SGreg Kroah-Hartman cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2); 426*03ee2515SGreg Kroah-Hartman /* Convert to baudrate */ 427*03ee2515SGreg Kroah-Hartman if (baud) 428*03ee2515SGreg Kroah-Hartman baud = cp2101_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud); 429*03ee2515SGreg Kroah-Hartman 430*03ee2515SGreg Kroah-Hartman dbg("%s - baud rate = %d", __func__, baud); 431*03ee2515SGreg Kroah-Hartman 432*03ee2515SGreg Kroah-Hartman tty_encode_baud_rate(tty, baud, baud); 433*03ee2515SGreg Kroah-Hartman cflag = tty->termios->c_cflag; 434*03ee2515SGreg Kroah-Hartman 435*03ee2515SGreg Kroah-Hartman cp2101_get_config(port, CP2101_BITS, &bits, 2); 436*03ee2515SGreg Kroah-Hartman cflag &= ~CSIZE; 437*03ee2515SGreg Kroah-Hartman switch (bits & BITS_DATA_MASK) { 438*03ee2515SGreg Kroah-Hartman case BITS_DATA_5: 439*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 5", __func__); 440*03ee2515SGreg Kroah-Hartman cflag |= CS5; 441*03ee2515SGreg Kroah-Hartman break; 442*03ee2515SGreg Kroah-Hartman case BITS_DATA_6: 443*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 6", __func__); 444*03ee2515SGreg Kroah-Hartman cflag |= CS6; 445*03ee2515SGreg Kroah-Hartman break; 446*03ee2515SGreg Kroah-Hartman case BITS_DATA_7: 447*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 7", __func__); 448*03ee2515SGreg Kroah-Hartman cflag |= CS7; 449*03ee2515SGreg Kroah-Hartman break; 450*03ee2515SGreg Kroah-Hartman case BITS_DATA_8: 451*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 8", __func__); 452*03ee2515SGreg Kroah-Hartman cflag |= CS8; 453*03ee2515SGreg Kroah-Hartman break; 454*03ee2515SGreg Kroah-Hartman case BITS_DATA_9: 455*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 9 (not supported, using 8 data bits)", 456*03ee2515SGreg Kroah-Hartman __func__); 457*03ee2515SGreg Kroah-Hartman cflag |= CS8; 458*03ee2515SGreg Kroah-Hartman bits &= ~BITS_DATA_MASK; 459*03ee2515SGreg Kroah-Hartman bits |= BITS_DATA_8; 460*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_BITS, &bits, 2); 461*03ee2515SGreg Kroah-Hartman break; 462*03ee2515SGreg Kroah-Hartman default: 463*03ee2515SGreg Kroah-Hartman dbg("%s - Unknown number of data bits, using 8", __func__); 464*03ee2515SGreg Kroah-Hartman cflag |= CS8; 465*03ee2515SGreg Kroah-Hartman bits &= ~BITS_DATA_MASK; 466*03ee2515SGreg Kroah-Hartman bits |= BITS_DATA_8; 467*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_BITS, &bits, 2); 468*03ee2515SGreg Kroah-Hartman break; 469*03ee2515SGreg Kroah-Hartman } 470*03ee2515SGreg Kroah-Hartman 471*03ee2515SGreg Kroah-Hartman switch (bits & BITS_PARITY_MASK) { 472*03ee2515SGreg Kroah-Hartman case BITS_PARITY_NONE: 473*03ee2515SGreg Kroah-Hartman dbg("%s - parity = NONE", __func__); 474*03ee2515SGreg Kroah-Hartman cflag &= ~PARENB; 475*03ee2515SGreg Kroah-Hartman break; 476*03ee2515SGreg Kroah-Hartman case BITS_PARITY_ODD: 477*03ee2515SGreg Kroah-Hartman dbg("%s - parity = ODD", __func__); 478*03ee2515SGreg Kroah-Hartman cflag |= (PARENB|PARODD); 479*03ee2515SGreg Kroah-Hartman break; 480*03ee2515SGreg Kroah-Hartman case BITS_PARITY_EVEN: 481*03ee2515SGreg Kroah-Hartman dbg("%s - parity = EVEN", __func__); 482*03ee2515SGreg Kroah-Hartman cflag &= ~PARODD; 483*03ee2515SGreg Kroah-Hartman cflag |= PARENB; 484*03ee2515SGreg Kroah-Hartman break; 485*03ee2515SGreg Kroah-Hartman case BITS_PARITY_MARK: 486*03ee2515SGreg Kroah-Hartman dbg("%s - parity = MARK (not supported, disabling parity)", 487*03ee2515SGreg Kroah-Hartman __func__); 488*03ee2515SGreg Kroah-Hartman cflag &= ~PARENB; 489*03ee2515SGreg Kroah-Hartman bits &= ~BITS_PARITY_MASK; 490*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_BITS, &bits, 2); 491*03ee2515SGreg Kroah-Hartman break; 492*03ee2515SGreg Kroah-Hartman case BITS_PARITY_SPACE: 493*03ee2515SGreg Kroah-Hartman dbg("%s - parity = SPACE (not supported, disabling parity)", 494*03ee2515SGreg Kroah-Hartman __func__); 495*03ee2515SGreg Kroah-Hartman cflag &= ~PARENB; 496*03ee2515SGreg Kroah-Hartman bits &= ~BITS_PARITY_MASK; 497*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_BITS, &bits, 2); 498*03ee2515SGreg Kroah-Hartman break; 499*03ee2515SGreg Kroah-Hartman default: 500*03ee2515SGreg Kroah-Hartman dbg("%s - Unknown parity mode, disabling parity", __func__); 501*03ee2515SGreg Kroah-Hartman cflag &= ~PARENB; 502*03ee2515SGreg Kroah-Hartman bits &= ~BITS_PARITY_MASK; 503*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_BITS, &bits, 2); 504*03ee2515SGreg Kroah-Hartman break; 505*03ee2515SGreg Kroah-Hartman } 506*03ee2515SGreg Kroah-Hartman 507*03ee2515SGreg Kroah-Hartman cflag &= ~CSTOPB; 508*03ee2515SGreg Kroah-Hartman switch (bits & BITS_STOP_MASK) { 509*03ee2515SGreg Kroah-Hartman case BITS_STOP_1: 510*03ee2515SGreg Kroah-Hartman dbg("%s - stop bits = 1", __func__); 511*03ee2515SGreg Kroah-Hartman break; 512*03ee2515SGreg Kroah-Hartman case BITS_STOP_1_5: 513*03ee2515SGreg Kroah-Hartman dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)", 514*03ee2515SGreg Kroah-Hartman __func__); 515*03ee2515SGreg Kroah-Hartman bits &= ~BITS_STOP_MASK; 516*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_BITS, &bits, 2); 517*03ee2515SGreg Kroah-Hartman break; 518*03ee2515SGreg Kroah-Hartman case BITS_STOP_2: 519*03ee2515SGreg Kroah-Hartman dbg("%s - stop bits = 2", __func__); 520*03ee2515SGreg Kroah-Hartman cflag |= CSTOPB; 521*03ee2515SGreg Kroah-Hartman break; 522*03ee2515SGreg Kroah-Hartman default: 523*03ee2515SGreg Kroah-Hartman dbg("%s - Unknown number of stop bits, using 1 stop bit", 524*03ee2515SGreg Kroah-Hartman __func__); 525*03ee2515SGreg Kroah-Hartman bits &= ~BITS_STOP_MASK; 526*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_BITS, &bits, 2); 527*03ee2515SGreg Kroah-Hartman break; 528*03ee2515SGreg Kroah-Hartman } 529*03ee2515SGreg Kroah-Hartman 530*03ee2515SGreg Kroah-Hartman cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16); 531*03ee2515SGreg Kroah-Hartman if (modem_ctl[0] & 0x0008) { 532*03ee2515SGreg Kroah-Hartman dbg("%s - flow control = CRTSCTS", __func__); 533*03ee2515SGreg Kroah-Hartman cflag |= CRTSCTS; 534*03ee2515SGreg Kroah-Hartman } else { 535*03ee2515SGreg Kroah-Hartman dbg("%s - flow control = NONE", __func__); 536*03ee2515SGreg Kroah-Hartman cflag &= ~CRTSCTS; 537*03ee2515SGreg Kroah-Hartman } 538*03ee2515SGreg Kroah-Hartman 539*03ee2515SGreg Kroah-Hartman tty->termios->c_cflag = cflag; 540*03ee2515SGreg Kroah-Hartman } 541*03ee2515SGreg Kroah-Hartman 542*03ee2515SGreg Kroah-Hartman static void cp2101_set_termios(struct tty_struct *tty, 543*03ee2515SGreg Kroah-Hartman struct usb_serial_port *port, struct ktermios *old_termios) 544*03ee2515SGreg Kroah-Hartman { 545*03ee2515SGreg Kroah-Hartman unsigned int cflag, old_cflag; 546*03ee2515SGreg Kroah-Hartman unsigned int baud = 0, bits; 547*03ee2515SGreg Kroah-Hartman unsigned int modem_ctl[4]; 548*03ee2515SGreg Kroah-Hartman 549*03ee2515SGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 550*03ee2515SGreg Kroah-Hartman 551*03ee2515SGreg Kroah-Hartman if (!tty) 552*03ee2515SGreg Kroah-Hartman return; 553*03ee2515SGreg Kroah-Hartman 554*03ee2515SGreg Kroah-Hartman tty->termios->c_cflag &= ~CMSPAR; 555*03ee2515SGreg Kroah-Hartman cflag = tty->termios->c_cflag; 556*03ee2515SGreg Kroah-Hartman old_cflag = old_termios->c_cflag; 557*03ee2515SGreg Kroah-Hartman baud = cp2101_quantise_baudrate(tty_get_baud_rate(tty)); 558*03ee2515SGreg Kroah-Hartman 559*03ee2515SGreg Kroah-Hartman /* If the baud rate is to be updated*/ 560*03ee2515SGreg Kroah-Hartman if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { 561*03ee2515SGreg Kroah-Hartman dbg("%s - Setting baud rate to %d baud", __func__, 562*03ee2515SGreg Kroah-Hartman baud); 563*03ee2515SGreg Kroah-Hartman if (cp2101_set_config_single(port, CP2101_BAUDRATE, 564*03ee2515SGreg Kroah-Hartman ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) { 565*03ee2515SGreg Kroah-Hartman dbg("Baud rate requested not supported by device\n"); 566*03ee2515SGreg Kroah-Hartman baud = tty_termios_baud_rate(old_termios); 567*03ee2515SGreg Kroah-Hartman } 568*03ee2515SGreg Kroah-Hartman } 569*03ee2515SGreg Kroah-Hartman /* Report back the resulting baud rate */ 570*03ee2515SGreg Kroah-Hartman tty_encode_baud_rate(tty, baud, baud); 571*03ee2515SGreg Kroah-Hartman 572*03ee2515SGreg Kroah-Hartman /* If the number of data bits is to be updated */ 573*03ee2515SGreg Kroah-Hartman if ((cflag & CSIZE) != (old_cflag & CSIZE)) { 574*03ee2515SGreg Kroah-Hartman cp2101_get_config(port, CP2101_BITS, &bits, 2); 575*03ee2515SGreg Kroah-Hartman bits &= ~BITS_DATA_MASK; 576*03ee2515SGreg Kroah-Hartman switch (cflag & CSIZE) { 577*03ee2515SGreg Kroah-Hartman case CS5: 578*03ee2515SGreg Kroah-Hartman bits |= BITS_DATA_5; 579*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 5", __func__); 580*03ee2515SGreg Kroah-Hartman break; 581*03ee2515SGreg Kroah-Hartman case CS6: 582*03ee2515SGreg Kroah-Hartman bits |= BITS_DATA_6; 583*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 6", __func__); 584*03ee2515SGreg Kroah-Hartman break; 585*03ee2515SGreg Kroah-Hartman case CS7: 586*03ee2515SGreg Kroah-Hartman bits |= BITS_DATA_7; 587*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 7", __func__); 588*03ee2515SGreg Kroah-Hartman break; 589*03ee2515SGreg Kroah-Hartman case CS8: 590*03ee2515SGreg Kroah-Hartman bits |= BITS_DATA_8; 591*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 8", __func__); 592*03ee2515SGreg Kroah-Hartman break; 593*03ee2515SGreg Kroah-Hartman /*case CS9: 594*03ee2515SGreg Kroah-Hartman bits |= BITS_DATA_9; 595*03ee2515SGreg Kroah-Hartman dbg("%s - data bits = 9", __func__); 596*03ee2515SGreg Kroah-Hartman break;*/ 597*03ee2515SGreg Kroah-Hartman default: 598*03ee2515SGreg Kroah-Hartman dbg("cp2101 driver does not " 599*03ee2515SGreg Kroah-Hartman "support the number of bits requested," 600*03ee2515SGreg Kroah-Hartman " using 8 bit mode\n"); 601*03ee2515SGreg Kroah-Hartman bits |= BITS_DATA_8; 602*03ee2515SGreg Kroah-Hartman break; 603*03ee2515SGreg Kroah-Hartman } 604*03ee2515SGreg Kroah-Hartman if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) 605*03ee2515SGreg Kroah-Hartman dbg("Number of data bits requested " 606*03ee2515SGreg Kroah-Hartman "not supported by device\n"); 607*03ee2515SGreg Kroah-Hartman } 608*03ee2515SGreg Kroah-Hartman 609*03ee2515SGreg Kroah-Hartman if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) { 610*03ee2515SGreg Kroah-Hartman cp2101_get_config(port, CP2101_BITS, &bits, 2); 611*03ee2515SGreg Kroah-Hartman bits &= ~BITS_PARITY_MASK; 612*03ee2515SGreg Kroah-Hartman if (cflag & PARENB) { 613*03ee2515SGreg Kroah-Hartman if (cflag & PARODD) { 614*03ee2515SGreg Kroah-Hartman bits |= BITS_PARITY_ODD; 615*03ee2515SGreg Kroah-Hartman dbg("%s - parity = ODD", __func__); 616*03ee2515SGreg Kroah-Hartman } else { 617*03ee2515SGreg Kroah-Hartman bits |= BITS_PARITY_EVEN; 618*03ee2515SGreg Kroah-Hartman dbg("%s - parity = EVEN", __func__); 619*03ee2515SGreg Kroah-Hartman } 620*03ee2515SGreg Kroah-Hartman } 621*03ee2515SGreg Kroah-Hartman if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) 622*03ee2515SGreg Kroah-Hartman dbg("Parity mode not supported " 623*03ee2515SGreg Kroah-Hartman "by device\n"); 624*03ee2515SGreg Kroah-Hartman } 625*03ee2515SGreg Kroah-Hartman 626*03ee2515SGreg Kroah-Hartman if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { 627*03ee2515SGreg Kroah-Hartman cp2101_get_config(port, CP2101_BITS, &bits, 2); 628*03ee2515SGreg Kroah-Hartman bits &= ~BITS_STOP_MASK; 629*03ee2515SGreg Kroah-Hartman if (cflag & CSTOPB) { 630*03ee2515SGreg Kroah-Hartman bits |= BITS_STOP_2; 631*03ee2515SGreg Kroah-Hartman dbg("%s - stop bits = 2", __func__); 632*03ee2515SGreg Kroah-Hartman } else { 633*03ee2515SGreg Kroah-Hartman bits |= BITS_STOP_1; 634*03ee2515SGreg Kroah-Hartman dbg("%s - stop bits = 1", __func__); 635*03ee2515SGreg Kroah-Hartman } 636*03ee2515SGreg Kroah-Hartman if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) 637*03ee2515SGreg Kroah-Hartman dbg("Number of stop bits requested " 638*03ee2515SGreg Kroah-Hartman "not supported by device\n"); 639*03ee2515SGreg Kroah-Hartman } 640*03ee2515SGreg Kroah-Hartman 641*03ee2515SGreg Kroah-Hartman if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { 642*03ee2515SGreg Kroah-Hartman cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16); 643*03ee2515SGreg Kroah-Hartman dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", 644*03ee2515SGreg Kroah-Hartman __func__, modem_ctl[0], modem_ctl[1], 645*03ee2515SGreg Kroah-Hartman modem_ctl[2], modem_ctl[3]); 646*03ee2515SGreg Kroah-Hartman 647*03ee2515SGreg Kroah-Hartman if (cflag & CRTSCTS) { 648*03ee2515SGreg Kroah-Hartman modem_ctl[0] &= ~0x7B; 649*03ee2515SGreg Kroah-Hartman modem_ctl[0] |= 0x09; 650*03ee2515SGreg Kroah-Hartman modem_ctl[1] = 0x80; 651*03ee2515SGreg Kroah-Hartman dbg("%s - flow control = CRTSCTS", __func__); 652*03ee2515SGreg Kroah-Hartman } else { 653*03ee2515SGreg Kroah-Hartman modem_ctl[0] &= ~0x7B; 654*03ee2515SGreg Kroah-Hartman modem_ctl[0] |= 0x01; 655*03ee2515SGreg Kroah-Hartman modem_ctl[1] |= 0x40; 656*03ee2515SGreg Kroah-Hartman dbg("%s - flow control = NONE", __func__); 657*03ee2515SGreg Kroah-Hartman } 658*03ee2515SGreg Kroah-Hartman 659*03ee2515SGreg Kroah-Hartman dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", 660*03ee2515SGreg Kroah-Hartman __func__, modem_ctl[0], modem_ctl[1], 661*03ee2515SGreg Kroah-Hartman modem_ctl[2], modem_ctl[3]); 662*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16); 663*03ee2515SGreg Kroah-Hartman } 664*03ee2515SGreg Kroah-Hartman 665*03ee2515SGreg Kroah-Hartman } 666*03ee2515SGreg Kroah-Hartman 667*03ee2515SGreg Kroah-Hartman static int cp2101_tiocmset (struct tty_struct *tty, struct file *file, 668*03ee2515SGreg Kroah-Hartman unsigned int set, unsigned int clear) 669*03ee2515SGreg Kroah-Hartman { 670*03ee2515SGreg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 671*03ee2515SGreg Kroah-Hartman unsigned int control = 0; 672*03ee2515SGreg Kroah-Hartman 673*03ee2515SGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 674*03ee2515SGreg Kroah-Hartman 675*03ee2515SGreg Kroah-Hartman if (set & TIOCM_RTS) { 676*03ee2515SGreg Kroah-Hartman control |= CONTROL_RTS; 677*03ee2515SGreg Kroah-Hartman control |= CONTROL_WRITE_RTS; 678*03ee2515SGreg Kroah-Hartman } 679*03ee2515SGreg Kroah-Hartman if (set & TIOCM_DTR) { 680*03ee2515SGreg Kroah-Hartman control |= CONTROL_DTR; 681*03ee2515SGreg Kroah-Hartman control |= CONTROL_WRITE_DTR; 682*03ee2515SGreg Kroah-Hartman } 683*03ee2515SGreg Kroah-Hartman if (clear & TIOCM_RTS) { 684*03ee2515SGreg Kroah-Hartman control &= ~CONTROL_RTS; 685*03ee2515SGreg Kroah-Hartman control |= CONTROL_WRITE_RTS; 686*03ee2515SGreg Kroah-Hartman } 687*03ee2515SGreg Kroah-Hartman if (clear & TIOCM_DTR) { 688*03ee2515SGreg Kroah-Hartman control &= ~CONTROL_DTR; 689*03ee2515SGreg Kroah-Hartman control |= CONTROL_WRITE_DTR; 690*03ee2515SGreg Kroah-Hartman } 691*03ee2515SGreg Kroah-Hartman 692*03ee2515SGreg Kroah-Hartman dbg("%s - control = 0x%.4x", __func__, control); 693*03ee2515SGreg Kroah-Hartman 694*03ee2515SGreg Kroah-Hartman return cp2101_set_config(port, CP2101_CONTROL, &control, 2); 695*03ee2515SGreg Kroah-Hartman 696*03ee2515SGreg Kroah-Hartman } 697*03ee2515SGreg Kroah-Hartman 698*03ee2515SGreg Kroah-Hartman static int cp2101_tiocmget (struct tty_struct *tty, struct file *file) 699*03ee2515SGreg Kroah-Hartman { 700*03ee2515SGreg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 701*03ee2515SGreg Kroah-Hartman unsigned int control; 702*03ee2515SGreg Kroah-Hartman int result; 703*03ee2515SGreg Kroah-Hartman 704*03ee2515SGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 705*03ee2515SGreg Kroah-Hartman 706*03ee2515SGreg Kroah-Hartman cp2101_get_config(port, CP2101_CONTROL, &control, 1); 707*03ee2515SGreg Kroah-Hartman 708*03ee2515SGreg Kroah-Hartman result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) 709*03ee2515SGreg Kroah-Hartman |((control & CONTROL_RTS) ? TIOCM_RTS : 0) 710*03ee2515SGreg Kroah-Hartman |((control & CONTROL_CTS) ? TIOCM_CTS : 0) 711*03ee2515SGreg Kroah-Hartman |((control & CONTROL_DSR) ? TIOCM_DSR : 0) 712*03ee2515SGreg Kroah-Hartman |((control & CONTROL_RING)? TIOCM_RI : 0) 713*03ee2515SGreg Kroah-Hartman |((control & CONTROL_DCD) ? TIOCM_CD : 0); 714*03ee2515SGreg Kroah-Hartman 715*03ee2515SGreg Kroah-Hartman dbg("%s - control = 0x%.2x", __func__, control); 716*03ee2515SGreg Kroah-Hartman 717*03ee2515SGreg Kroah-Hartman return result; 718*03ee2515SGreg Kroah-Hartman } 719*03ee2515SGreg Kroah-Hartman 720*03ee2515SGreg Kroah-Hartman static void cp2101_break_ctl (struct tty_struct *tty, int break_state) 721*03ee2515SGreg Kroah-Hartman { 722*03ee2515SGreg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 723*03ee2515SGreg Kroah-Hartman unsigned int state; 724*03ee2515SGreg Kroah-Hartman 725*03ee2515SGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 726*03ee2515SGreg Kroah-Hartman if (break_state == 0) 727*03ee2515SGreg Kroah-Hartman state = BREAK_OFF; 728*03ee2515SGreg Kroah-Hartman else 729*03ee2515SGreg Kroah-Hartman state = BREAK_ON; 730*03ee2515SGreg Kroah-Hartman dbg("%s - turning break %s", __func__, 731*03ee2515SGreg Kroah-Hartman state == BREAK_OFF ? "off" : "on"); 732*03ee2515SGreg Kroah-Hartman cp2101_set_config(port, CP2101_BREAK, &state, 2); 733*03ee2515SGreg Kroah-Hartman } 734*03ee2515SGreg Kroah-Hartman 735*03ee2515SGreg Kroah-Hartman static int cp2101_startup(struct usb_serial *serial) 736*03ee2515SGreg Kroah-Hartman { 737*03ee2515SGreg Kroah-Hartman /* CP2101 buffers behave strangely unless device is reset */ 738*03ee2515SGreg Kroah-Hartman usb_reset_device(serial->dev); 739*03ee2515SGreg Kroah-Hartman return 0; 740*03ee2515SGreg Kroah-Hartman } 741*03ee2515SGreg Kroah-Hartman 742*03ee2515SGreg Kroah-Hartman static void cp2101_shutdown(struct usb_serial *serial) 743*03ee2515SGreg Kroah-Hartman { 744*03ee2515SGreg Kroah-Hartman int i; 745*03ee2515SGreg Kroah-Hartman 746*03ee2515SGreg Kroah-Hartman dbg("%s", __func__); 747*03ee2515SGreg Kroah-Hartman 748*03ee2515SGreg Kroah-Hartman /* Stop reads and writes on all ports */ 749*03ee2515SGreg Kroah-Hartman for (i = 0; i < serial->num_ports; ++i) 750*03ee2515SGreg Kroah-Hartman cp2101_cleanup(serial->port[i]); 751*03ee2515SGreg Kroah-Hartman } 752*03ee2515SGreg Kroah-Hartman 753*03ee2515SGreg Kroah-Hartman static int __init cp2101_init(void) 754*03ee2515SGreg Kroah-Hartman { 755*03ee2515SGreg Kroah-Hartman int retval; 756*03ee2515SGreg Kroah-Hartman 757*03ee2515SGreg Kroah-Hartman retval = usb_serial_register(&cp2101_device); 758*03ee2515SGreg Kroah-Hartman if (retval) 759*03ee2515SGreg Kroah-Hartman return retval; /* Failed to register */ 760*03ee2515SGreg Kroah-Hartman 761*03ee2515SGreg Kroah-Hartman retval = usb_register(&cp2101_driver); 762*03ee2515SGreg Kroah-Hartman if (retval) { 763*03ee2515SGreg Kroah-Hartman /* Failed to register */ 764*03ee2515SGreg Kroah-Hartman usb_serial_deregister(&cp2101_device); 765*03ee2515SGreg Kroah-Hartman return retval; 766*03ee2515SGreg Kroah-Hartman } 767*03ee2515SGreg Kroah-Hartman 768*03ee2515SGreg Kroah-Hartman /* Success */ 769*03ee2515SGreg Kroah-Hartman printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" 770*03ee2515SGreg Kroah-Hartman DRIVER_DESC "\n"); 771*03ee2515SGreg Kroah-Hartman return 0; 772*03ee2515SGreg Kroah-Hartman } 773*03ee2515SGreg Kroah-Hartman 774*03ee2515SGreg Kroah-Hartman static void __exit cp2101_exit(void) 775*03ee2515SGreg Kroah-Hartman { 776*03ee2515SGreg Kroah-Hartman usb_deregister(&cp2101_driver); 777*03ee2515SGreg Kroah-Hartman usb_serial_deregister(&cp2101_device); 778*03ee2515SGreg Kroah-Hartman } 779*03ee2515SGreg Kroah-Hartman 780*03ee2515SGreg Kroah-Hartman module_init(cp2101_init); 781*03ee2515SGreg Kroah-Hartman module_exit(cp2101_exit); 782*03ee2515SGreg Kroah-Hartman 783*03ee2515SGreg Kroah-Hartman MODULE_DESCRIPTION(DRIVER_DESC); 784*03ee2515SGreg Kroah-Hartman MODULE_VERSION(DRIVER_VERSION); 785*03ee2515SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 786*03ee2515SGreg Kroah-Hartman 787*03ee2515SGreg Kroah-Hartman module_param(debug, bool, S_IRUGO | S_IWUSR); 788*03ee2515SGreg Kroah-Hartman MODULE_PARM_DESC(debug, "Enable verbose debugging messages"); 789