18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * spcp8x5 USB to serial adaptor driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010-2013 Johan Hovold (jhovold@gmail.com) 68c2ecf20Sopenharmony_ci * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn) 78c2ecf20Sopenharmony_ci * Copyright (C) 2006 S1 Corp. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Original driver for 2.6.10 pl2303 driver by 108c2ecf20Sopenharmony_ci * Greg Kroah-Hartman (greg@kroah.com) 118c2ecf20Sopenharmony_ci * Changes for 2.6.20 by Harald Klein <hari@vt100.at> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/tty.h> 178c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 188c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 218c2ecf20Sopenharmony_ci#include <linux/usb.h> 228c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define SPCP825_QUIRK_NO_UART_STATUS 0x01 278c2ecf20Sopenharmony_ci#define SPCP825_QUIRK_NO_WORK_MODE 0x02 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define SPCP8x5_007_VID 0x04FC 308c2ecf20Sopenharmony_ci#define SPCP8x5_007_PID 0x0201 318c2ecf20Sopenharmony_ci#define SPCP8x5_008_VID 0x04fc 328c2ecf20Sopenharmony_ci#define SPCP8x5_008_PID 0x0235 338c2ecf20Sopenharmony_ci#define SPCP8x5_PHILIPS_VID 0x0471 348c2ecf20Sopenharmony_ci#define SPCP8x5_PHILIPS_PID 0x081e 358c2ecf20Sopenharmony_ci#define SPCP8x5_INTERMATIC_VID 0x04FC 368c2ecf20Sopenharmony_ci#define SPCP8x5_INTERMATIC_PID 0x0204 378c2ecf20Sopenharmony_ci#define SPCP8x5_835_VID 0x04fc 388c2ecf20Sopenharmony_ci#define SPCP8x5_835_PID 0x0231 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = { 418c2ecf20Sopenharmony_ci { USB_DEVICE(SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID)}, 428c2ecf20Sopenharmony_ci { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)}, 438c2ecf20Sopenharmony_ci { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)}, 448c2ecf20Sopenharmony_ci { USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)}, 458c2ecf20Sopenharmony_ci { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID), 468c2ecf20Sopenharmony_ci .driver_info = SPCP825_QUIRK_NO_UART_STATUS | 478c2ecf20Sopenharmony_ci SPCP825_QUIRK_NO_WORK_MODE }, 488c2ecf20Sopenharmony_ci { } /* Terminating entry */ 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct spcp8x5_usb_ctrl_arg { 538c2ecf20Sopenharmony_ci u8 type; 548c2ecf20Sopenharmony_ci u8 cmd; 558c2ecf20Sopenharmony_ci u8 cmd_type; 568c2ecf20Sopenharmony_ci u16 value; 578c2ecf20Sopenharmony_ci u16 index; 588c2ecf20Sopenharmony_ci u16 length; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* spcp8x5 spec register define */ 638c2ecf20Sopenharmony_ci#define MCR_CONTROL_LINE_RTS 0x02 648c2ecf20Sopenharmony_ci#define MCR_CONTROL_LINE_DTR 0x01 658c2ecf20Sopenharmony_ci#define MCR_DTR 0x01 668c2ecf20Sopenharmony_ci#define MCR_RTS 0x02 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define MSR_STATUS_LINE_DCD 0x80 698c2ecf20Sopenharmony_ci#define MSR_STATUS_LINE_RI 0x40 708c2ecf20Sopenharmony_ci#define MSR_STATUS_LINE_DSR 0x20 718c2ecf20Sopenharmony_ci#define MSR_STATUS_LINE_CTS 0x10 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* verdor command here , we should define myself */ 748c2ecf20Sopenharmony_ci#define SET_DEFAULT 0x40 758c2ecf20Sopenharmony_ci#define SET_DEFAULT_TYPE 0x20 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define SET_UART_FORMAT 0x40 788c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_TYPE 0x21 798c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_SIZE_5 0x00 808c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_SIZE_6 0x01 818c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_SIZE_7 0x02 828c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_SIZE_8 0x03 838c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_STOP_1 0x00 848c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_STOP_2 0x04 858c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_PAR_NONE 0x00 868c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_PAR_ODD 0x10 878c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_PAR_EVEN 0x30 888c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_PAR_MASK 0xD0 898c2ecf20Sopenharmony_ci#define SET_UART_FORMAT_PAR_SPACE 0x90 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define GET_UART_STATUS_TYPE 0xc0 928c2ecf20Sopenharmony_ci#define GET_UART_STATUS 0x22 938c2ecf20Sopenharmony_ci#define GET_UART_STATUS_MSR 0x06 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define SET_UART_STATUS 0x40 968c2ecf20Sopenharmony_ci#define SET_UART_STATUS_TYPE 0x23 978c2ecf20Sopenharmony_ci#define SET_UART_STATUS_MCR 0x0004 988c2ecf20Sopenharmony_ci#define SET_UART_STATUS_MCR_DTR 0x01 998c2ecf20Sopenharmony_ci#define SET_UART_STATUS_MCR_RTS 0x02 1008c2ecf20Sopenharmony_ci#define SET_UART_STATUS_MCR_LOOP 0x10 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define SET_WORKING_MODE 0x40 1038c2ecf20Sopenharmony_ci#define SET_WORKING_MODE_TYPE 0x24 1048c2ecf20Sopenharmony_ci#define SET_WORKING_MODE_U2C 0x00 1058c2ecf20Sopenharmony_ci#define SET_WORKING_MODE_RS485 0x01 1068c2ecf20Sopenharmony_ci#define SET_WORKING_MODE_PDMA 0x02 1078c2ecf20Sopenharmony_ci#define SET_WORKING_MODE_SPP 0x03 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define SET_FLOWCTL_CHAR 0x40 1108c2ecf20Sopenharmony_ci#define SET_FLOWCTL_CHAR_TYPE 0x25 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define GET_VERSION 0xc0 1138c2ecf20Sopenharmony_ci#define GET_VERSION_TYPE 0x26 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define SET_REGISTER 0x40 1168c2ecf20Sopenharmony_ci#define SET_REGISTER_TYPE 0x27 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define GET_REGISTER 0xc0 1198c2ecf20Sopenharmony_ci#define GET_REGISTER_TYPE 0x28 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#define SET_RAM 0x40 1228c2ecf20Sopenharmony_ci#define SET_RAM_TYPE 0x31 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define GET_RAM 0xc0 1258c2ecf20Sopenharmony_ci#define GET_RAM_TYPE 0x32 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* how come ??? */ 1288c2ecf20Sopenharmony_ci#define UART_STATE 0x08 1298c2ecf20Sopenharmony_ci#define UART_STATE_TRANSIENT_MASK 0x75 1308c2ecf20Sopenharmony_ci#define UART_DCD 0x01 1318c2ecf20Sopenharmony_ci#define UART_DSR 0x02 1328c2ecf20Sopenharmony_ci#define UART_BREAK_ERROR 0x04 1338c2ecf20Sopenharmony_ci#define UART_RING 0x08 1348c2ecf20Sopenharmony_ci#define UART_FRAME_ERROR 0x10 1358c2ecf20Sopenharmony_ci#define UART_PARITY_ERROR 0x20 1368c2ecf20Sopenharmony_ci#define UART_OVERRUN_ERROR 0x40 1378c2ecf20Sopenharmony_ci#define UART_CTS 0x80 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistruct spcp8x5_private { 1408c2ecf20Sopenharmony_ci unsigned quirks; 1418c2ecf20Sopenharmony_ci spinlock_t lock; 1428c2ecf20Sopenharmony_ci u8 line_control; 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int spcp8x5_probe(struct usb_serial *serial, 1468c2ecf20Sopenharmony_ci const struct usb_device_id *id) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci usb_set_serial_data(serial, (void *)id); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int spcp8x5_port_probe(struct usb_serial_port *port) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci const struct usb_device_id *id = usb_get_serial_data(port->serial); 1568c2ecf20Sopenharmony_ci struct spcp8x5_private *priv; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1598c2ecf20Sopenharmony_ci if (!priv) 1608c2ecf20Sopenharmony_ci return -ENOMEM; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 1638c2ecf20Sopenharmony_ci priv->quirks = id->driver_info; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci usb_set_serial_port_data(port, priv); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci port->port.drain_delay = 256; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int spcp8x5_port_remove(struct usb_serial_port *port) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct spcp8x5_private *priv; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 1778c2ecf20Sopenharmony_ci kfree(priv); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct spcp8x5_private *priv = usb_get_serial_port_data(port); 1858c2ecf20Sopenharmony_ci struct usb_device *dev = port->serial->dev; 1868c2ecf20Sopenharmony_ci int retval; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS) 1898c2ecf20Sopenharmony_ci return -EPERM; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 1928c2ecf20Sopenharmony_ci SET_UART_STATUS_TYPE, SET_UART_STATUS, 1938c2ecf20Sopenharmony_ci mcr, 0x04, NULL, 0, 100); 1948c2ecf20Sopenharmony_ci if (retval != 0) { 1958c2ecf20Sopenharmony_ci dev_err(&port->dev, "failed to set control lines: %d\n", 1968c2ecf20Sopenharmony_ci retval); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci return retval; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct spcp8x5_private *priv = usb_get_serial_port_data(port); 2048c2ecf20Sopenharmony_ci struct usb_device *dev = port->serial->dev; 2058c2ecf20Sopenharmony_ci u8 *buf; 2068c2ecf20Sopenharmony_ci int ret; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS) 2098c2ecf20Sopenharmony_ci return -EPERM; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci buf = kzalloc(1, GFP_KERNEL); 2128c2ecf20Sopenharmony_ci if (!buf) 2138c2ecf20Sopenharmony_ci return -ENOMEM; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 2168c2ecf20Sopenharmony_ci GET_UART_STATUS, GET_UART_STATUS_TYPE, 2178c2ecf20Sopenharmony_ci 0, GET_UART_STATUS_MSR, buf, 1, 100); 2188c2ecf20Sopenharmony_ci if (ret < 1) { 2198c2ecf20Sopenharmony_ci dev_err(&port->dev, "failed to get modem status: %d\n", ret); 2208c2ecf20Sopenharmony_ci if (ret >= 0) 2218c2ecf20Sopenharmony_ci ret = -EIO; 2228c2ecf20Sopenharmony_ci goto out; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf); 2268c2ecf20Sopenharmony_ci *status = *buf; 2278c2ecf20Sopenharmony_ci ret = 0; 2288c2ecf20Sopenharmony_ciout: 2298c2ecf20Sopenharmony_ci kfree(buf); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value, 2358c2ecf20Sopenharmony_ci u16 index) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct spcp8x5_private *priv = usb_get_serial_port_data(port); 2388c2ecf20Sopenharmony_ci struct usb_device *dev = port->serial->dev; 2398c2ecf20Sopenharmony_ci int ret; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE) 2428c2ecf20Sopenharmony_ci return; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 2458c2ecf20Sopenharmony_ci SET_WORKING_MODE_TYPE, SET_WORKING_MODE, 2468c2ecf20Sopenharmony_ci value, index, NULL, 0, 100); 2478c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index); 2488c2ecf20Sopenharmony_ci if (ret < 0) 2498c2ecf20Sopenharmony_ci dev_err(&port->dev, "failed to set work mode: %d\n", ret); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int spcp8x5_carrier_raised(struct usb_serial_port *port) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci u8 msr; 2558c2ecf20Sopenharmony_ci int ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = spcp8x5_get_msr(port, &msr); 2588c2ecf20Sopenharmony_ci if (ret || msr & MSR_STATUS_LINE_DCD) 2598c2ecf20Sopenharmony_ci return 1; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct spcp8x5_private *priv = usb_get_serial_port_data(port); 2678c2ecf20Sopenharmony_ci unsigned long flags; 2688c2ecf20Sopenharmony_ci u8 control; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 2718c2ecf20Sopenharmony_ci if (on) 2728c2ecf20Sopenharmony_ci priv->line_control = MCR_CONTROL_LINE_DTR 2738c2ecf20Sopenharmony_ci | MCR_CONTROL_LINE_RTS; 2748c2ecf20Sopenharmony_ci else 2758c2ecf20Sopenharmony_ci priv->line_control &= ~ (MCR_CONTROL_LINE_DTR 2768c2ecf20Sopenharmony_ci | MCR_CONTROL_LINE_RTS); 2778c2ecf20Sopenharmony_ci control = priv->line_control; 2788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2798c2ecf20Sopenharmony_ci spcp8x5_set_ctrl_line(port, control); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void spcp8x5_init_termios(struct tty_struct *tty) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci tty_encode_baud_rate(tty, 115200, 115200); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic void spcp8x5_set_termios(struct tty_struct *tty, 2888c2ecf20Sopenharmony_ci struct usb_serial_port *port, struct ktermios *old_termios) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 2918c2ecf20Sopenharmony_ci struct spcp8x5_private *priv = usb_get_serial_port_data(port); 2928c2ecf20Sopenharmony_ci unsigned long flags; 2938c2ecf20Sopenharmony_ci unsigned int cflag = tty->termios.c_cflag; 2948c2ecf20Sopenharmony_ci unsigned short uartdata; 2958c2ecf20Sopenharmony_ci unsigned char buf[2] = {0, 0}; 2968c2ecf20Sopenharmony_ci int baud; 2978c2ecf20Sopenharmony_ci int i; 2988c2ecf20Sopenharmony_ci u8 control; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* check that they really want us to change something */ 3018c2ecf20Sopenharmony_ci if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) 3028c2ecf20Sopenharmony_ci return; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* set DTR/RTS active */ 3058c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3068c2ecf20Sopenharmony_ci control = priv->line_control; 3078c2ecf20Sopenharmony_ci if (old_termios && (old_termios->c_cflag & CBAUD) == B0) { 3088c2ecf20Sopenharmony_ci priv->line_control |= MCR_DTR; 3098c2ecf20Sopenharmony_ci if (!(old_termios->c_cflag & CRTSCTS)) 3108c2ecf20Sopenharmony_ci priv->line_control |= MCR_RTS; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci if (control != priv->line_control) { 3138c2ecf20Sopenharmony_ci control = priv->line_control; 3148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3158c2ecf20Sopenharmony_ci spcp8x5_set_ctrl_line(port, control); 3168c2ecf20Sopenharmony_ci } else { 3178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Set Baud Rate */ 3218c2ecf20Sopenharmony_ci baud = tty_get_baud_rate(tty); 3228c2ecf20Sopenharmony_ci switch (baud) { 3238c2ecf20Sopenharmony_ci case 300: buf[0] = 0x00; break; 3248c2ecf20Sopenharmony_ci case 600: buf[0] = 0x01; break; 3258c2ecf20Sopenharmony_ci case 1200: buf[0] = 0x02; break; 3268c2ecf20Sopenharmony_ci case 2400: buf[0] = 0x03; break; 3278c2ecf20Sopenharmony_ci case 4800: buf[0] = 0x04; break; 3288c2ecf20Sopenharmony_ci case 9600: buf[0] = 0x05; break; 3298c2ecf20Sopenharmony_ci case 19200: buf[0] = 0x07; break; 3308c2ecf20Sopenharmony_ci case 38400: buf[0] = 0x09; break; 3318c2ecf20Sopenharmony_ci case 57600: buf[0] = 0x0a; break; 3328c2ecf20Sopenharmony_ci case 115200: buf[0] = 0x0b; break; 3338c2ecf20Sopenharmony_ci case 230400: buf[0] = 0x0c; break; 3348c2ecf20Sopenharmony_ci case 460800: buf[0] = 0x0d; break; 3358c2ecf20Sopenharmony_ci case 921600: buf[0] = 0x0e; break; 3368c2ecf20Sopenharmony_ci/* case 1200000: buf[0] = 0x0f; break; */ 3378c2ecf20Sopenharmony_ci/* case 2400000: buf[0] = 0x10; break; */ 3388c2ecf20Sopenharmony_ci case 3000000: buf[0] = 0x11; break; 3398c2ecf20Sopenharmony_ci/* case 6000000: buf[0] = 0x12; break; */ 3408c2ecf20Sopenharmony_ci case 0: 3418c2ecf20Sopenharmony_ci case 1000000: 3428c2ecf20Sopenharmony_ci buf[0] = 0x0b; break; 3438c2ecf20Sopenharmony_ci default: 3448c2ecf20Sopenharmony_ci dev_err(&port->dev, "unsupported baudrate, using 9600\n"); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */ 3488c2ecf20Sopenharmony_ci switch (cflag & CSIZE) { 3498c2ecf20Sopenharmony_ci case CS5: 3508c2ecf20Sopenharmony_ci buf[1] |= SET_UART_FORMAT_SIZE_5; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci case CS6: 3538c2ecf20Sopenharmony_ci buf[1] |= SET_UART_FORMAT_SIZE_6; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case CS7: 3568c2ecf20Sopenharmony_ci buf[1] |= SET_UART_FORMAT_SIZE_7; 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci default: 3598c2ecf20Sopenharmony_ci case CS8: 3608c2ecf20Sopenharmony_ci buf[1] |= SET_UART_FORMAT_SIZE_8; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* Set Stop bit2 : 0:1bit 1:2bit */ 3658c2ecf20Sopenharmony_ci buf[1] |= (cflag & CSTOPB) ? SET_UART_FORMAT_STOP_2 : 3668c2ecf20Sopenharmony_ci SET_UART_FORMAT_STOP_1; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* Set Parity bit3-4 01:Odd 11:Even */ 3698c2ecf20Sopenharmony_ci if (cflag & PARENB) { 3708c2ecf20Sopenharmony_ci buf[1] |= (cflag & PARODD) ? 3718c2ecf20Sopenharmony_ci SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ; 3728c2ecf20Sopenharmony_ci } else { 3738c2ecf20Sopenharmony_ci buf[1] |= SET_UART_FORMAT_PAR_NONE; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci uartdata = buf[0] | buf[1]<<8; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 3788c2ecf20Sopenharmony_ci SET_UART_FORMAT_TYPE, SET_UART_FORMAT, 3798c2ecf20Sopenharmony_ci uartdata, 0, NULL, 0, 100); 3808c2ecf20Sopenharmony_ci if (i < 0) 3818c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n", 3828c2ecf20Sopenharmony_ci uartdata, i); 3838c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "0x21:0x40:0:0 %d\n", i); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (cflag & CRTSCTS) { 3868c2ecf20Sopenharmony_ci /* enable hardware flow control */ 3878c2ecf20Sopenharmony_ci spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C); 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 3948c2ecf20Sopenharmony_ci struct spcp8x5_private *priv = usb_get_serial_port_data(port); 3958c2ecf20Sopenharmony_ci int ret; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci usb_clear_halt(serial->dev, port->write_urb->pipe); 3988c2ecf20Sopenharmony_ci usb_clear_halt(serial->dev, port->read_urb->pipe); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 4018c2ecf20Sopenharmony_ci 0x09, 0x00, 4028c2ecf20Sopenharmony_ci 0x01, 0x00, NULL, 0x00, 100); 4038c2ecf20Sopenharmony_ci if (ret) 4048c2ecf20Sopenharmony_ci return ret; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci spcp8x5_set_ctrl_line(port, priv->line_control); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (tty) 4098c2ecf20Sopenharmony_ci spcp8x5_set_termios(tty, port, NULL); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return usb_serial_generic_open(tty, port); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int spcp8x5_tiocmset(struct tty_struct *tty, 4158c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 4188c2ecf20Sopenharmony_ci struct spcp8x5_private *priv = usb_get_serial_port_data(port); 4198c2ecf20Sopenharmony_ci unsigned long flags; 4208c2ecf20Sopenharmony_ci u8 control; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 4238c2ecf20Sopenharmony_ci if (set & TIOCM_RTS) 4248c2ecf20Sopenharmony_ci priv->line_control |= MCR_RTS; 4258c2ecf20Sopenharmony_ci if (set & TIOCM_DTR) 4268c2ecf20Sopenharmony_ci priv->line_control |= MCR_DTR; 4278c2ecf20Sopenharmony_ci if (clear & TIOCM_RTS) 4288c2ecf20Sopenharmony_ci priv->line_control &= ~MCR_RTS; 4298c2ecf20Sopenharmony_ci if (clear & TIOCM_DTR) 4308c2ecf20Sopenharmony_ci priv->line_control &= ~MCR_DTR; 4318c2ecf20Sopenharmony_ci control = priv->line_control; 4328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return spcp8x5_set_ctrl_line(port, control); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int spcp8x5_tiocmget(struct tty_struct *tty) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 4408c2ecf20Sopenharmony_ci struct spcp8x5_private *priv = usb_get_serial_port_data(port); 4418c2ecf20Sopenharmony_ci unsigned long flags; 4428c2ecf20Sopenharmony_ci unsigned int mcr; 4438c2ecf20Sopenharmony_ci u8 status; 4448c2ecf20Sopenharmony_ci unsigned int result; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci result = spcp8x5_get_msr(port, &status); 4478c2ecf20Sopenharmony_ci if (result) 4488c2ecf20Sopenharmony_ci return result; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 4518c2ecf20Sopenharmony_ci mcr = priv->line_control; 4528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) 4558c2ecf20Sopenharmony_ci | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) 4568c2ecf20Sopenharmony_ci | ((status & MSR_STATUS_LINE_CTS) ? TIOCM_CTS : 0) 4578c2ecf20Sopenharmony_ci | ((status & MSR_STATUS_LINE_DSR) ? TIOCM_DSR : 0) 4588c2ecf20Sopenharmony_ci | ((status & MSR_STATUS_LINE_RI) ? TIOCM_RI : 0) 4598c2ecf20Sopenharmony_ci | ((status & MSR_STATUS_LINE_DCD) ? TIOCM_CD : 0); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return result; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic struct usb_serial_driver spcp8x5_device = { 4658c2ecf20Sopenharmony_ci .driver = { 4668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4678c2ecf20Sopenharmony_ci .name = "SPCP8x5", 4688c2ecf20Sopenharmony_ci }, 4698c2ecf20Sopenharmony_ci .id_table = id_table, 4708c2ecf20Sopenharmony_ci .num_ports = 1, 4718c2ecf20Sopenharmony_ci .num_bulk_in = 1, 4728c2ecf20Sopenharmony_ci .num_bulk_out = 1, 4738c2ecf20Sopenharmony_ci .open = spcp8x5_open, 4748c2ecf20Sopenharmony_ci .dtr_rts = spcp8x5_dtr_rts, 4758c2ecf20Sopenharmony_ci .carrier_raised = spcp8x5_carrier_raised, 4768c2ecf20Sopenharmony_ci .set_termios = spcp8x5_set_termios, 4778c2ecf20Sopenharmony_ci .init_termios = spcp8x5_init_termios, 4788c2ecf20Sopenharmony_ci .tiocmget = spcp8x5_tiocmget, 4798c2ecf20Sopenharmony_ci .tiocmset = spcp8x5_tiocmset, 4808c2ecf20Sopenharmony_ci .probe = spcp8x5_probe, 4818c2ecf20Sopenharmony_ci .port_probe = spcp8x5_port_probe, 4828c2ecf20Sopenharmony_ci .port_remove = spcp8x5_port_remove, 4838c2ecf20Sopenharmony_ci}; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 4868c2ecf20Sopenharmony_ci &spcp8x5_device, NULL 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 4928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 493