18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Fintek F81232 USB to serial adaptor driver 48c2ecf20Sopenharmony_ci * Fintek F81532A/534A/535/536 USB to 2/4/8/12 serial adaptor driver 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org) 78c2ecf20Sopenharmony_ci * Copyright (C) 2012 Linux Foundation 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/tty.h> 148c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 158c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 168c2ecf20Sopenharmony_ci#include <linux/serial.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 198c2ecf20Sopenharmony_ci#include <linux/mutex.h> 208c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 218c2ecf20Sopenharmony_ci#include <linux/usb.h> 228c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 238c2ecf20Sopenharmony_ci#include <linux/serial_reg.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define F81232_ID \ 268c2ecf20Sopenharmony_ci { USB_DEVICE(0x1934, 0x0706) } /* 1 port UART device */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define F81534A_SERIES_ID \ 298c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1602) }, /* In-Box 2 port UART device */ \ 308c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1604) }, /* In-Box 4 port UART device */ \ 318c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1605) }, /* In-Box 8 port UART device */ \ 328c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1606) }, /* In-Box 12 port UART device */ \ 338c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1608) }, /* Non-Flash type */ \ 348c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1632) }, /* 2 port UART device */ \ 358c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1634) }, /* 4 port UART device */ \ 368c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1635) }, /* 8 port UART device */ \ 378c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x1636) } /* 12 port UART device */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define F81534A_CTRL_ID \ 408c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c42, 0x16f8) } /* Global control device */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const struct usb_device_id f81232_id_table[] = { 438c2ecf20Sopenharmony_ci F81232_ID, 448c2ecf20Sopenharmony_ci { } /* Terminating entry */ 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic const struct usb_device_id f81534a_id_table[] = { 488c2ecf20Sopenharmony_ci F81534A_SERIES_ID, 498c2ecf20Sopenharmony_ci { } /* Terminating entry */ 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic const struct usb_device_id f81534a_ctrl_id_table[] = { 538c2ecf20Sopenharmony_ci F81534A_CTRL_ID, 548c2ecf20Sopenharmony_ci { } /* Terminating entry */ 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const struct usb_device_id combined_id_table[] = { 588c2ecf20Sopenharmony_ci F81232_ID, 598c2ecf20Sopenharmony_ci F81534A_SERIES_ID, 608c2ecf20Sopenharmony_ci F81534A_CTRL_ID, 618c2ecf20Sopenharmony_ci { } /* Terminating entry */ 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, combined_id_table); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Maximum baudrate for F81232 */ 668c2ecf20Sopenharmony_ci#define F81232_MAX_BAUDRATE 1500000 678c2ecf20Sopenharmony_ci#define F81232_DEF_BAUDRATE 9600 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* USB Control EP parameter */ 708c2ecf20Sopenharmony_ci#define F81232_REGISTER_REQUEST 0xa0 718c2ecf20Sopenharmony_ci#define F81232_GET_REGISTER 0xc0 728c2ecf20Sopenharmony_ci#define F81232_SET_REGISTER 0x40 738c2ecf20Sopenharmony_ci#define F81534A_ACCESS_REG_RETRY 2 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define SERIAL_BASE_ADDRESS 0x0120 768c2ecf20Sopenharmony_ci#define RECEIVE_BUFFER_REGISTER (0x00 + SERIAL_BASE_ADDRESS) 778c2ecf20Sopenharmony_ci#define INTERRUPT_ENABLE_REGISTER (0x01 + SERIAL_BASE_ADDRESS) 788c2ecf20Sopenharmony_ci#define FIFO_CONTROL_REGISTER (0x02 + SERIAL_BASE_ADDRESS) 798c2ecf20Sopenharmony_ci#define LINE_CONTROL_REGISTER (0x03 + SERIAL_BASE_ADDRESS) 808c2ecf20Sopenharmony_ci#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS) 818c2ecf20Sopenharmony_ci#define LINE_STATUS_REGISTER (0x05 + SERIAL_BASE_ADDRESS) 828c2ecf20Sopenharmony_ci#define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * F81232 Clock registers (106h) 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * Bit1-0: Clock source selector 888c2ecf20Sopenharmony_ci * 00: 1.846MHz. 898c2ecf20Sopenharmony_ci * 01: 18.46MHz. 908c2ecf20Sopenharmony_ci * 10: 24MHz. 918c2ecf20Sopenharmony_ci * 11: 14.77MHz. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci#define F81232_CLK_REGISTER 0x106 948c2ecf20Sopenharmony_ci#define F81232_CLK_1_846_MHZ 0 958c2ecf20Sopenharmony_ci#define F81232_CLK_18_46_MHZ BIT(0) 968c2ecf20Sopenharmony_ci#define F81232_CLK_24_MHZ BIT(1) 978c2ecf20Sopenharmony_ci#define F81232_CLK_14_77_MHZ (BIT(1) | BIT(0)) 988c2ecf20Sopenharmony_ci#define F81232_CLK_MASK GENMASK(1, 0) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define F81534A_MODE_REG 0x107 1018c2ecf20Sopenharmony_ci#define F81534A_TRIGGER_MASK GENMASK(3, 2) 1028c2ecf20Sopenharmony_ci#define F81534A_TRIGGER_MULTIPLE_4X BIT(3) 1038c2ecf20Sopenharmony_ci#define F81534A_FIFO_128BYTE (BIT(1) | BIT(0)) 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* Serial port self GPIO control, 2bytes [control&output data][input data] */ 1068c2ecf20Sopenharmony_ci#define F81534A_GPIO_REG 0x10e 1078c2ecf20Sopenharmony_ci#define F81534A_GPIO_MODE2_DIR BIT(6) /* 1: input, 0: output */ 1088c2ecf20Sopenharmony_ci#define F81534A_GPIO_MODE1_DIR BIT(5) 1098c2ecf20Sopenharmony_ci#define F81534A_GPIO_MODE0_DIR BIT(4) 1108c2ecf20Sopenharmony_ci#define F81534A_GPIO_MODE2_OUTPUT BIT(2) 1118c2ecf20Sopenharmony_ci#define F81534A_GPIO_MODE1_OUTPUT BIT(1) 1128c2ecf20Sopenharmony_ci#define F81534A_GPIO_MODE0_OUTPUT BIT(0) 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define F81534A_CTRL_CMD_ENABLE_PORT 0x116 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistruct f81232_private { 1178c2ecf20Sopenharmony_ci struct mutex lock; 1188c2ecf20Sopenharmony_ci u8 modem_control; 1198c2ecf20Sopenharmony_ci u8 modem_status; 1208c2ecf20Sopenharmony_ci u8 shadow_lcr; 1218c2ecf20Sopenharmony_ci speed_t baud_base; 1228c2ecf20Sopenharmony_ci struct work_struct lsr_work; 1238c2ecf20Sopenharmony_ci struct work_struct interrupt_work; 1248c2ecf20Sopenharmony_ci struct usb_serial_port *port; 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 }; 1288c2ecf20Sopenharmony_cistatic u8 const clock_table[] = { F81232_CLK_1_846_MHZ, F81232_CLK_14_77_MHZ, 1298c2ecf20Sopenharmony_ci F81232_CLK_18_46_MHZ, F81232_CLK_24_MHZ }; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int calc_baud_divisor(speed_t baudrate, speed_t clockrate) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci return DIV_ROUND_CLOSEST(clockrate, baudrate); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci int status; 1398c2ecf20Sopenharmony_ci u8 *tmp; 1408c2ecf20Sopenharmony_ci struct usb_device *dev = port->serial->dev; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci tmp = kmalloc(sizeof(*val), GFP_KERNEL); 1438c2ecf20Sopenharmony_ci if (!tmp) 1448c2ecf20Sopenharmony_ci return -ENOMEM; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci status = usb_control_msg(dev, 1478c2ecf20Sopenharmony_ci usb_rcvctrlpipe(dev, 0), 1488c2ecf20Sopenharmony_ci F81232_REGISTER_REQUEST, 1498c2ecf20Sopenharmony_ci F81232_GET_REGISTER, 1508c2ecf20Sopenharmony_ci reg, 1518c2ecf20Sopenharmony_ci 0, 1528c2ecf20Sopenharmony_ci tmp, 1538c2ecf20Sopenharmony_ci sizeof(*val), 1548c2ecf20Sopenharmony_ci USB_CTRL_GET_TIMEOUT); 1558c2ecf20Sopenharmony_ci if (status != sizeof(*val)) { 1568c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed status: %d\n", __func__, status); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (status < 0) 1598c2ecf20Sopenharmony_ci status = usb_translate_errors(status); 1608c2ecf20Sopenharmony_ci else 1618c2ecf20Sopenharmony_ci status = -EIO; 1628c2ecf20Sopenharmony_ci } else { 1638c2ecf20Sopenharmony_ci status = 0; 1648c2ecf20Sopenharmony_ci *val = *tmp; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci kfree(tmp); 1688c2ecf20Sopenharmony_ci return status; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci int status; 1748c2ecf20Sopenharmony_ci u8 *tmp; 1758c2ecf20Sopenharmony_ci struct usb_device *dev = port->serial->dev; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci tmp = kmalloc(sizeof(val), GFP_KERNEL); 1788c2ecf20Sopenharmony_ci if (!tmp) 1798c2ecf20Sopenharmony_ci return -ENOMEM; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci *tmp = val; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci status = usb_control_msg(dev, 1848c2ecf20Sopenharmony_ci usb_sndctrlpipe(dev, 0), 1858c2ecf20Sopenharmony_ci F81232_REGISTER_REQUEST, 1868c2ecf20Sopenharmony_ci F81232_SET_REGISTER, 1878c2ecf20Sopenharmony_ci reg, 1888c2ecf20Sopenharmony_ci 0, 1898c2ecf20Sopenharmony_ci tmp, 1908c2ecf20Sopenharmony_ci sizeof(val), 1918c2ecf20Sopenharmony_ci USB_CTRL_SET_TIMEOUT); 1928c2ecf20Sopenharmony_ci if (status != sizeof(val)) { 1938c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed status: %d\n", __func__, status); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (status < 0) 1968c2ecf20Sopenharmony_ci status = usb_translate_errors(status); 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci status = -EIO; 1998c2ecf20Sopenharmony_ci } else { 2008c2ecf20Sopenharmony_ci status = 0; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci kfree(tmp); 2048c2ecf20Sopenharmony_ci return status; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int f81232_set_mask_register(struct usb_serial_port *port, u16 reg, 2088c2ecf20Sopenharmony_ci u8 mask, u8 val) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int status; 2118c2ecf20Sopenharmony_ci u8 tmp; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci status = f81232_get_register(port, reg, &tmp); 2148c2ecf20Sopenharmony_ci if (status) 2158c2ecf20Sopenharmony_ci return status; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci tmp = (tmp & ~mask) | (val & mask); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return f81232_set_register(port, reg, tmp); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void f81232_read_msr(struct usb_serial_port *port) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int status; 2258c2ecf20Sopenharmony_ci u8 current_msr; 2268c2ecf20Sopenharmony_ci struct tty_struct *tty; 2278c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 2308c2ecf20Sopenharmony_ci status = f81232_get_register(port, MODEM_STATUS_REGISTER, 2318c2ecf20Sopenharmony_ci ¤t_msr); 2328c2ecf20Sopenharmony_ci if (status) { 2338c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s fail, status: %d\n", __func__, status); 2348c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 2358c2ecf20Sopenharmony_ci return; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!(current_msr & UART_MSR_ANY_DELTA)) { 2398c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 2408c2ecf20Sopenharmony_ci return; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci priv->modem_status = current_msr; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (current_msr & UART_MSR_DCTS) 2468c2ecf20Sopenharmony_ci port->icount.cts++; 2478c2ecf20Sopenharmony_ci if (current_msr & UART_MSR_DDSR) 2488c2ecf20Sopenharmony_ci port->icount.dsr++; 2498c2ecf20Sopenharmony_ci if (current_msr & UART_MSR_TERI) 2508c2ecf20Sopenharmony_ci port->icount.rng++; 2518c2ecf20Sopenharmony_ci if (current_msr & UART_MSR_DDCD) { 2528c2ecf20Sopenharmony_ci port->icount.dcd++; 2538c2ecf20Sopenharmony_ci tty = tty_port_tty_get(&port->port); 2548c2ecf20Sopenharmony_ci if (tty) { 2558c2ecf20Sopenharmony_ci usb_serial_handle_dcd_change(port, tty, 2568c2ecf20Sopenharmony_ci current_msr & UART_MSR_DCD); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci tty_kref_put(tty); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci wake_up_interruptible(&port->port.delta_msr_wait); 2638c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int f81232_set_mctrl(struct usb_serial_port *port, 2678c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci u8 val; 2708c2ecf20Sopenharmony_ci int status; 2718c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) 2748c2ecf20Sopenharmony_ci return 0; /* no change */ 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* 'set' takes precedence over 'clear' */ 2778c2ecf20Sopenharmony_ci clear &= ~set; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* force enable interrupt with OUT2 */ 2808c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 2818c2ecf20Sopenharmony_ci val = UART_MCR_OUT2 | priv->modem_control; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (clear & TIOCM_DTR) 2848c2ecf20Sopenharmony_ci val &= ~UART_MCR_DTR; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (clear & TIOCM_RTS) 2878c2ecf20Sopenharmony_ci val &= ~UART_MCR_RTS; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (set & TIOCM_DTR) 2908c2ecf20Sopenharmony_ci val |= UART_MCR_DTR; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (set & TIOCM_RTS) 2938c2ecf20Sopenharmony_ci val |= UART_MCR_RTS; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s new:%02x old:%02x\n", __func__, 2968c2ecf20Sopenharmony_ci val, priv->modem_control); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci status = f81232_set_register(port, MODEM_CONTROL_REGISTER, val); 2998c2ecf20Sopenharmony_ci if (status) { 3008c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s set MCR status < 0\n", __func__); 3018c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 3028c2ecf20Sopenharmony_ci return status; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci priv->modem_control = val; 3068c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return 0; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic void f81232_update_line_status(struct usb_serial_port *port, 3128c2ecf20Sopenharmony_ci unsigned char *data, 3138c2ecf20Sopenharmony_ci size_t actual_length) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (!actual_length) 3188c2ecf20Sopenharmony_ci return; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci switch (data[0] & 0x07) { 3218c2ecf20Sopenharmony_ci case 0x00: /* msr change */ 3228c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "IIR: MSR Change: %02x\n", data[0]); 3238c2ecf20Sopenharmony_ci schedule_work(&priv->interrupt_work); 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci case 0x02: /* tx-empty */ 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci case 0x04: /* rx data available */ 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci case 0x06: /* lsr change */ 3308c2ecf20Sopenharmony_ci /* we can forget it. the LSR will read from bulk-in */ 3318c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "IIR: LSR Change: %02x\n", data[0]); 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic void f81232_read_int_callback(struct urb *urb) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 3398c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 3408c2ecf20Sopenharmony_ci unsigned int actual_length = urb->actual_length; 3418c2ecf20Sopenharmony_ci int status = urb->status; 3428c2ecf20Sopenharmony_ci int retval; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci switch (status) { 3458c2ecf20Sopenharmony_ci case 0: 3468c2ecf20Sopenharmony_ci /* success */ 3478c2ecf20Sopenharmony_ci break; 3488c2ecf20Sopenharmony_ci case -ECONNRESET: 3498c2ecf20Sopenharmony_ci case -ENOENT: 3508c2ecf20Sopenharmony_ci case -ESHUTDOWN: 3518c2ecf20Sopenharmony_ci /* this urb is terminated, clean up */ 3528c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", 3538c2ecf20Sopenharmony_ci __func__, status); 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci default: 3568c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", 3578c2ecf20Sopenharmony_ci __func__, status); 3588c2ecf20Sopenharmony_ci goto exit; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, 3628c2ecf20Sopenharmony_ci urb->actual_length, urb->transfer_buffer); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci f81232_update_line_status(port, data, actual_length); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ciexit: 3678c2ecf20Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 3688c2ecf20Sopenharmony_ci if (retval) 3698c2ecf20Sopenharmony_ci dev_err(&urb->dev->dev, 3708c2ecf20Sopenharmony_ci "%s - usb_submit_urb failed with result %d\n", 3718c2ecf20Sopenharmony_ci __func__, retval); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic char f81232_handle_lsr(struct usb_serial_port *port, u8 lsr) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 3778c2ecf20Sopenharmony_ci char tty_flag = TTY_NORMAL; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (!(lsr & UART_LSR_BRK_ERROR_BITS)) 3808c2ecf20Sopenharmony_ci return tty_flag; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (lsr & UART_LSR_BI) { 3838c2ecf20Sopenharmony_ci tty_flag = TTY_BREAK; 3848c2ecf20Sopenharmony_ci port->icount.brk++; 3858c2ecf20Sopenharmony_ci usb_serial_handle_break(port); 3868c2ecf20Sopenharmony_ci } else if (lsr & UART_LSR_PE) { 3878c2ecf20Sopenharmony_ci tty_flag = TTY_PARITY; 3888c2ecf20Sopenharmony_ci port->icount.parity++; 3898c2ecf20Sopenharmony_ci } else if (lsr & UART_LSR_FE) { 3908c2ecf20Sopenharmony_ci tty_flag = TTY_FRAME; 3918c2ecf20Sopenharmony_ci port->icount.frame++; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (lsr & UART_LSR_OE) { 3958c2ecf20Sopenharmony_ci port->icount.overrun++; 3968c2ecf20Sopenharmony_ci schedule_work(&priv->lsr_work); 3978c2ecf20Sopenharmony_ci tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return tty_flag; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic void f81232_process_read_urb(struct urb *urb) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 4068c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 4078c2ecf20Sopenharmony_ci char tty_flag; 4088c2ecf20Sopenharmony_ci unsigned int i; 4098c2ecf20Sopenharmony_ci u8 lsr; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* 4128c2ecf20Sopenharmony_ci * When opening the port we get a 1-byte packet with the current LSR, 4138c2ecf20Sopenharmony_ci * which we discard. 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_ci if ((urb->actual_length < 2) || (urb->actual_length % 2)) 4168c2ecf20Sopenharmony_ci return; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */ 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci for (i = 0; i < urb->actual_length; i += 2) { 4218c2ecf20Sopenharmony_ci lsr = data[i]; 4228c2ecf20Sopenharmony_ci tty_flag = f81232_handle_lsr(port, lsr); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (port->sysrq) { 4258c2ecf20Sopenharmony_ci if (usb_serial_handle_sysrq_char(port, data[i + 1])) 4268c2ecf20Sopenharmony_ci continue; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci tty_insert_flip_char(&port->port, data[i + 1], tty_flag); 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->port); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic void f81534a_process_read_urb(struct urb *urb) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 4388c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 4398c2ecf20Sopenharmony_ci char tty_flag; 4408c2ecf20Sopenharmony_ci unsigned int i; 4418c2ecf20Sopenharmony_ci u8 lsr; 4428c2ecf20Sopenharmony_ci u8 len; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (urb->actual_length < 3) { 4458c2ecf20Sopenharmony_ci dev_err(&port->dev, "short message received: %d\n", 4468c2ecf20Sopenharmony_ci urb->actual_length); 4478c2ecf20Sopenharmony_ci return; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci len = data[0]; 4518c2ecf20Sopenharmony_ci if (len != urb->actual_length) { 4528c2ecf20Sopenharmony_ci dev_err(&port->dev, "malformed message received: %d (%d)\n", 4538c2ecf20Sopenharmony_ci urb->actual_length, len); 4548c2ecf20Sopenharmony_ci return; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* bulk-in data: [LEN][Data.....][LSR] */ 4588c2ecf20Sopenharmony_ci lsr = data[len - 1]; 4598c2ecf20Sopenharmony_ci tty_flag = f81232_handle_lsr(port, lsr); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (port->sysrq) { 4628c2ecf20Sopenharmony_ci for (i = 1; i < len - 1; ++i) { 4638c2ecf20Sopenharmony_ci if (!usb_serial_handle_sysrq_char(port, data[i])) { 4648c2ecf20Sopenharmony_ci tty_insert_flip_char(&port->port, data[i], 4658c2ecf20Sopenharmony_ci tty_flag); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci } else { 4698c2ecf20Sopenharmony_ci tty_insert_flip_string_fixed_flag(&port->port, &data[1], 4708c2ecf20Sopenharmony_ci tty_flag, len - 2); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->port); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void f81232_break_ctl(struct tty_struct *tty, int break_state) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 4798c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 4808c2ecf20Sopenharmony_ci int status; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (break_state) 4858c2ecf20Sopenharmony_ci priv->shadow_lcr |= UART_LCR_SBC; 4868c2ecf20Sopenharmony_ci else 4878c2ecf20Sopenharmony_ci priv->shadow_lcr &= ~UART_LCR_SBC; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci status = f81232_set_register(port, LINE_CONTROL_REGISTER, 4908c2ecf20Sopenharmony_ci priv->shadow_lcr); 4918c2ecf20Sopenharmony_ci if (status) 4928c2ecf20Sopenharmony_ci dev_err(&port->dev, "set break failed: %d\n", status); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int f81232_find_clk(speed_t baudrate) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci int idx; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(baudrate_table); ++idx) { 5028c2ecf20Sopenharmony_ci if (baudrate <= baudrate_table[idx] && 5038c2ecf20Sopenharmony_ci baudrate_table[idx] % baudrate == 0) 5048c2ecf20Sopenharmony_ci return idx; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return -EINVAL; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic void f81232_set_baudrate(struct tty_struct *tty, 5118c2ecf20Sopenharmony_ci struct usb_serial_port *port, speed_t baudrate, 5128c2ecf20Sopenharmony_ci speed_t old_baudrate) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 5158c2ecf20Sopenharmony_ci u8 lcr; 5168c2ecf20Sopenharmony_ci int divisor; 5178c2ecf20Sopenharmony_ci int status = 0; 5188c2ecf20Sopenharmony_ci int i; 5198c2ecf20Sopenharmony_ci int idx; 5208c2ecf20Sopenharmony_ci speed_t baud_list[] = { baudrate, old_baudrate, F81232_DEF_BAUDRATE }; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(baud_list); ++i) { 5238c2ecf20Sopenharmony_ci baudrate = baud_list[i]; 5248c2ecf20Sopenharmony_ci if (baudrate == 0) { 5258c2ecf20Sopenharmony_ci tty_encode_baud_rate(tty, 0, 0); 5268c2ecf20Sopenharmony_ci return; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci idx = f81232_find_clk(baudrate); 5308c2ecf20Sopenharmony_ci if (idx >= 0) { 5318c2ecf20Sopenharmony_ci tty_encode_baud_rate(tty, baudrate, baudrate); 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (idx < 0) 5378c2ecf20Sopenharmony_ci return; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci priv->baud_base = baudrate_table[idx]; 5408c2ecf20Sopenharmony_ci divisor = calc_baud_divisor(baudrate, priv->baud_base); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci status = f81232_set_mask_register(port, F81232_CLK_REGISTER, 5438c2ecf20Sopenharmony_ci F81232_CLK_MASK, clock_table[idx]); 5448c2ecf20Sopenharmony_ci if (status) { 5458c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set CLK_REG: %d\n", 5468c2ecf20Sopenharmony_ci __func__, status); 5478c2ecf20Sopenharmony_ci return; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci status = f81232_get_register(port, LINE_CONTROL_REGISTER, 5518c2ecf20Sopenharmony_ci &lcr); /* get LCR */ 5528c2ecf20Sopenharmony_ci if (status) { 5538c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to get LCR: %d\n", 5548c2ecf20Sopenharmony_ci __func__, status); 5558c2ecf20Sopenharmony_ci return; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci status = f81232_set_register(port, LINE_CONTROL_REGISTER, 5598c2ecf20Sopenharmony_ci lcr | UART_LCR_DLAB); /* Enable DLAB */ 5608c2ecf20Sopenharmony_ci if (status) { 5618c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set DLAB: %d\n", 5628c2ecf20Sopenharmony_ci __func__, status); 5638c2ecf20Sopenharmony_ci return; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci status = f81232_set_register(port, RECEIVE_BUFFER_REGISTER, 5678c2ecf20Sopenharmony_ci divisor & 0x00ff); /* low */ 5688c2ecf20Sopenharmony_ci if (status) { 5698c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set baudrate MSB: %d\n", 5708c2ecf20Sopenharmony_ci __func__, status); 5718c2ecf20Sopenharmony_ci goto reapply_lcr; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, 5758c2ecf20Sopenharmony_ci (divisor & 0xff00) >> 8); /* high */ 5768c2ecf20Sopenharmony_ci if (status) { 5778c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set baudrate LSB: %d\n", 5788c2ecf20Sopenharmony_ci __func__, status); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cireapply_lcr: 5828c2ecf20Sopenharmony_ci status = f81232_set_register(port, LINE_CONTROL_REGISTER, 5838c2ecf20Sopenharmony_ci lcr & ~UART_LCR_DLAB); 5848c2ecf20Sopenharmony_ci if (status) { 5858c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set DLAB: %d\n", 5868c2ecf20Sopenharmony_ci __func__, status); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic int f81232_port_enable(struct usb_serial_port *port) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci u8 val; 5938c2ecf20Sopenharmony_ci int status; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* fifo on, trigger8, clear TX/RX*/ 5968c2ecf20Sopenharmony_ci val = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | 5978c2ecf20Sopenharmony_ci UART_FCR_CLEAR_XMIT; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci status = f81232_set_register(port, FIFO_CONTROL_REGISTER, val); 6008c2ecf20Sopenharmony_ci if (status) { 6018c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set FCR: %d\n", 6028c2ecf20Sopenharmony_ci __func__, status); 6038c2ecf20Sopenharmony_ci return status; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* MSR Interrupt only, LSR will read from Bulk-in odd byte */ 6078c2ecf20Sopenharmony_ci status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, 6088c2ecf20Sopenharmony_ci UART_IER_MSI); 6098c2ecf20Sopenharmony_ci if (status) { 6108c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set IER: %d\n", 6118c2ecf20Sopenharmony_ci __func__, status); 6128c2ecf20Sopenharmony_ci return status; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int f81232_port_disable(struct usb_serial_port *port) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci int status; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci status = f81232_set_register(port, INTERRUPT_ENABLE_REGISTER, 0); 6238c2ecf20Sopenharmony_ci if (status) { 6248c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set IER: %d\n", 6258c2ecf20Sopenharmony_ci __func__, status); 6268c2ecf20Sopenharmony_ci return status; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic void f81232_set_termios(struct tty_struct *tty, 6338c2ecf20Sopenharmony_ci struct usb_serial_port *port, struct ktermios *old_termios) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 6368c2ecf20Sopenharmony_ci u8 new_lcr = 0; 6378c2ecf20Sopenharmony_ci int status = 0; 6388c2ecf20Sopenharmony_ci speed_t baudrate; 6398c2ecf20Sopenharmony_ci speed_t old_baud; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* Don't change anything if nothing has changed */ 6428c2ecf20Sopenharmony_ci if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) 6438c2ecf20Sopenharmony_ci return; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (C_BAUD(tty) == B0) 6468c2ecf20Sopenharmony_ci f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS); 6478c2ecf20Sopenharmony_ci else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) 6488c2ecf20Sopenharmony_ci f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci baudrate = tty_get_baud_rate(tty); 6518c2ecf20Sopenharmony_ci if (baudrate > 0) { 6528c2ecf20Sopenharmony_ci if (old_termios) 6538c2ecf20Sopenharmony_ci old_baud = tty_termios_baud_rate(old_termios); 6548c2ecf20Sopenharmony_ci else 6558c2ecf20Sopenharmony_ci old_baud = F81232_DEF_BAUDRATE; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci f81232_set_baudrate(tty, port, baudrate, old_baud); 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (C_PARENB(tty)) { 6618c2ecf20Sopenharmony_ci new_lcr |= UART_LCR_PARITY; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (!C_PARODD(tty)) 6648c2ecf20Sopenharmony_ci new_lcr |= UART_LCR_EPAR; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (C_CMSPAR(tty)) 6678c2ecf20Sopenharmony_ci new_lcr |= UART_LCR_SPAR; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (C_CSTOPB(tty)) 6718c2ecf20Sopenharmony_ci new_lcr |= UART_LCR_STOP; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci switch (C_CSIZE(tty)) { 6748c2ecf20Sopenharmony_ci case CS5: 6758c2ecf20Sopenharmony_ci new_lcr |= UART_LCR_WLEN5; 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci case CS6: 6788c2ecf20Sopenharmony_ci new_lcr |= UART_LCR_WLEN6; 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci case CS7: 6818c2ecf20Sopenharmony_ci new_lcr |= UART_LCR_WLEN7; 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci default: 6848c2ecf20Sopenharmony_ci case CS8: 6858c2ecf20Sopenharmony_ci new_lcr |= UART_LCR_WLEN8; 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci new_lcr |= (priv->shadow_lcr & UART_LCR_SBC); 6928c2ecf20Sopenharmony_ci status = f81232_set_register(port, LINE_CONTROL_REGISTER, new_lcr); 6938c2ecf20Sopenharmony_ci if (status) { 6948c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s failed to set LCR: %d\n", 6958c2ecf20Sopenharmony_ci __func__, status); 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci priv->shadow_lcr = new_lcr; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic int f81232_tiocmget(struct tty_struct *tty) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci int r; 7068c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 7078c2ecf20Sopenharmony_ci struct f81232_private *port_priv = usb_get_serial_port_data(port); 7088c2ecf20Sopenharmony_ci u8 mcr, msr; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* force get current MSR changed state */ 7118c2ecf20Sopenharmony_ci f81232_read_msr(port); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci mutex_lock(&port_priv->lock); 7148c2ecf20Sopenharmony_ci mcr = port_priv->modem_control; 7158c2ecf20Sopenharmony_ci msr = port_priv->modem_status; 7168c2ecf20Sopenharmony_ci mutex_unlock(&port_priv->lock); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) | 7198c2ecf20Sopenharmony_ci (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) | 7208c2ecf20Sopenharmony_ci (msr & UART_MSR_CTS ? TIOCM_CTS : 0) | 7218c2ecf20Sopenharmony_ci (msr & UART_MSR_DCD ? TIOCM_CAR : 0) | 7228c2ecf20Sopenharmony_ci (msr & UART_MSR_RI ? TIOCM_RI : 0) | 7238c2ecf20Sopenharmony_ci (msr & UART_MSR_DSR ? TIOCM_DSR : 0); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return r; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic int f81232_tiocmset(struct tty_struct *tty, 7298c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci return f81232_set_mctrl(port, set, clear); 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci int result; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci result = f81232_port_enable(port); 7418c2ecf20Sopenharmony_ci if (result) 7428c2ecf20Sopenharmony_ci return result; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* Setup termios */ 7458c2ecf20Sopenharmony_ci if (tty) 7468c2ecf20Sopenharmony_ci f81232_set_termios(tty, port, NULL); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 7498c2ecf20Sopenharmony_ci if (result) { 7508c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s - failed submitting interrupt urb," 7518c2ecf20Sopenharmony_ci " error %d\n", __func__, result); 7528c2ecf20Sopenharmony_ci return result; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci result = usb_serial_generic_open(tty, port); 7568c2ecf20Sopenharmony_ci if (result) { 7578c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 7588c2ecf20Sopenharmony_ci return result; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return 0; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int f81534a_open(struct tty_struct *tty, struct usb_serial_port *port) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci int status; 7678c2ecf20Sopenharmony_ci u8 mask; 7688c2ecf20Sopenharmony_ci u8 val; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci val = F81534A_TRIGGER_MULTIPLE_4X | F81534A_FIFO_128BYTE; 7718c2ecf20Sopenharmony_ci mask = F81534A_TRIGGER_MASK | F81534A_FIFO_128BYTE; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci status = f81232_set_mask_register(port, F81534A_MODE_REG, mask, val); 7748c2ecf20Sopenharmony_ci if (status) { 7758c2ecf20Sopenharmony_ci dev_err(&port->dev, "failed to set MODE_REG: %d\n", status); 7768c2ecf20Sopenharmony_ci return status; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return f81232_open(tty, port); 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic void f81232_close(struct usb_serial_port *port) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct f81232_private *port_priv = usb_get_serial_port_data(port); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci f81232_port_disable(port); 7878c2ecf20Sopenharmony_ci usb_serial_generic_close(port); 7888c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 7898c2ecf20Sopenharmony_ci flush_work(&port_priv->interrupt_work); 7908c2ecf20Sopenharmony_ci flush_work(&port_priv->lsr_work); 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic void f81232_dtr_rts(struct usb_serial_port *port, int on) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci if (on) 7968c2ecf20Sopenharmony_ci f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0); 7978c2ecf20Sopenharmony_ci else 7988c2ecf20Sopenharmony_ci f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS); 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic bool f81232_tx_empty(struct usb_serial_port *port) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci int status; 8048c2ecf20Sopenharmony_ci u8 tmp; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp); 8078c2ecf20Sopenharmony_ci if (!status) { 8088c2ecf20Sopenharmony_ci if ((tmp & UART_LSR_TEMT) != UART_LSR_TEMT) 8098c2ecf20Sopenharmony_ci return false; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return true; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int f81232_carrier_raised(struct usb_serial_port *port) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci u8 msr; 8188c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 8218c2ecf20Sopenharmony_ci msr = priv->modem_status; 8228c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (msr & UART_MSR_DCD) 8258c2ecf20Sopenharmony_ci return 1; 8268c2ecf20Sopenharmony_ci return 0; 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic int f81232_get_serial_info(struct tty_struct *tty, 8308c2ecf20Sopenharmony_ci struct serial_struct *ss) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 8338c2ecf20Sopenharmony_ci struct f81232_private *priv = usb_get_serial_port_data(port); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci ss->type = PORT_16550A; 8368c2ecf20Sopenharmony_ci ss->line = port->minor; 8378c2ecf20Sopenharmony_ci ss->port = port->port_number; 8388c2ecf20Sopenharmony_ci ss->baud_base = priv->baud_base; 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic void f81232_interrupt_work(struct work_struct *work) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci struct f81232_private *priv = 8458c2ecf20Sopenharmony_ci container_of(work, struct f81232_private, interrupt_work); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci f81232_read_msr(priv->port); 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic void f81232_lsr_worker(struct work_struct *work) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci struct f81232_private *priv; 8538c2ecf20Sopenharmony_ci struct usb_serial_port *port; 8548c2ecf20Sopenharmony_ci int status; 8558c2ecf20Sopenharmony_ci u8 tmp; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci priv = container_of(work, struct f81232_private, lsr_work); 8588c2ecf20Sopenharmony_ci port = priv->port; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp); 8618c2ecf20Sopenharmony_ci if (status) 8628c2ecf20Sopenharmony_ci dev_warn(&port->dev, "read LSR failed: %d\n", status); 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg, 8668c2ecf20Sopenharmony_ci u16 size, void *val) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct usb_device *dev = interface_to_usbdev(intf); 8698c2ecf20Sopenharmony_ci int retry = F81534A_ACCESS_REG_RETRY; 8708c2ecf20Sopenharmony_ci int status; 8718c2ecf20Sopenharmony_ci u8 *tmp; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci tmp = kmemdup(val, size, GFP_KERNEL); 8748c2ecf20Sopenharmony_ci if (!tmp) 8758c2ecf20Sopenharmony_ci return -ENOMEM; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci while (retry--) { 8788c2ecf20Sopenharmony_ci status = usb_control_msg(dev, 8798c2ecf20Sopenharmony_ci usb_sndctrlpipe(dev, 0), 8808c2ecf20Sopenharmony_ci F81232_REGISTER_REQUEST, 8818c2ecf20Sopenharmony_ci F81232_SET_REGISTER, 8828c2ecf20Sopenharmony_ci reg, 8838c2ecf20Sopenharmony_ci 0, 8848c2ecf20Sopenharmony_ci tmp, 8858c2ecf20Sopenharmony_ci size, 8868c2ecf20Sopenharmony_ci USB_CTRL_SET_TIMEOUT); 8878c2ecf20Sopenharmony_ci if (status < 0) { 8888c2ecf20Sopenharmony_ci status = usb_translate_errors(status); 8898c2ecf20Sopenharmony_ci if (status == -EIO) 8908c2ecf20Sopenharmony_ci continue; 8918c2ecf20Sopenharmony_ci } else if (status != size) { 8928c2ecf20Sopenharmony_ci /* Retry on short transfers */ 8938c2ecf20Sopenharmony_ci status = -EIO; 8948c2ecf20Sopenharmony_ci continue; 8958c2ecf20Sopenharmony_ci } else { 8968c2ecf20Sopenharmony_ci status = 0; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci break; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (status) { 9038c2ecf20Sopenharmony_ci dev_err(&intf->dev, "failed to set register 0x%x: %d\n", 9048c2ecf20Sopenharmony_ci reg, status); 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci kfree(tmp); 9088c2ecf20Sopenharmony_ci return status; 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic int f81534a_ctrl_enable_all_ports(struct usb_interface *intf, bool en) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci unsigned char enable[2] = {0}; 9148c2ecf20Sopenharmony_ci int status; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* 9178c2ecf20Sopenharmony_ci * Enable all available serial ports, define as following: 9188c2ecf20Sopenharmony_ci * bit 15 : Reset behavior (when HUB got soft reset) 9198c2ecf20Sopenharmony_ci * 0: maintain all serial port enabled state. 9208c2ecf20Sopenharmony_ci * 1: disable all serial port. 9218c2ecf20Sopenharmony_ci * bit 0~11 : Serial port enable bit. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci if (en) { 9248c2ecf20Sopenharmony_ci enable[0] = 0xff; 9258c2ecf20Sopenharmony_ci enable[1] = 0x8f; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci status = f81534a_ctrl_set_register(intf, F81534A_CTRL_CMD_ENABLE_PORT, 9298c2ecf20Sopenharmony_ci sizeof(enable), enable); 9308c2ecf20Sopenharmony_ci if (status) 9318c2ecf20Sopenharmony_ci dev_err(&intf->dev, "failed to enable ports: %d\n", status); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci return status; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic int f81534a_ctrl_probe(struct usb_interface *intf, 9378c2ecf20Sopenharmony_ci const struct usb_device_id *id) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci return f81534a_ctrl_enable_all_ports(intf, true); 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic void f81534a_ctrl_disconnect(struct usb_interface *intf) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci f81534a_ctrl_enable_all_ports(intf, false); 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int f81534a_ctrl_resume(struct usb_interface *intf) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci return f81534a_ctrl_enable_all_ports(intf, true); 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic int f81232_port_probe(struct usb_serial_port *port) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci struct f81232_private *priv; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci priv = devm_kzalloc(&port->dev, sizeof(*priv), GFP_KERNEL); 9578c2ecf20Sopenharmony_ci if (!priv) 9588c2ecf20Sopenharmony_ci return -ENOMEM; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci mutex_init(&priv->lock); 9618c2ecf20Sopenharmony_ci INIT_WORK(&priv->interrupt_work, f81232_interrupt_work); 9628c2ecf20Sopenharmony_ci INIT_WORK(&priv->lsr_work, f81232_lsr_worker); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci usb_set_serial_port_data(port, priv); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci port->port.drain_delay = 256; 9678c2ecf20Sopenharmony_ci priv->port = port; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci return 0; 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic int f81534a_port_probe(struct usb_serial_port *port) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci int status; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* tri-state with pull-high, default RS232 Mode */ 9778c2ecf20Sopenharmony_ci status = f81232_set_register(port, F81534A_GPIO_REG, 9788c2ecf20Sopenharmony_ci F81534A_GPIO_MODE2_DIR); 9798c2ecf20Sopenharmony_ci if (status) 9808c2ecf20Sopenharmony_ci return status; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci return f81232_port_probe(port); 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic int f81232_suspend(struct usb_serial *serial, pm_message_t message) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct usb_serial_port *port = serial->port[0]; 9888c2ecf20Sopenharmony_ci struct f81232_private *port_priv = usb_get_serial_port_data(port); 9898c2ecf20Sopenharmony_ci int i; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) 9928c2ecf20Sopenharmony_ci usb_kill_urb(port->read_urbs[i]); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (port_priv) { 9978c2ecf20Sopenharmony_ci flush_work(&port_priv->interrupt_work); 9988c2ecf20Sopenharmony_ci flush_work(&port_priv->lsr_work); 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return 0; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic int f81232_resume(struct usb_serial *serial) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct usb_serial_port *port = serial->port[0]; 10078c2ecf20Sopenharmony_ci int result; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (tty_port_initialized(&port->port)) { 10108c2ecf20Sopenharmony_ci result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); 10118c2ecf20Sopenharmony_ci if (result) { 10128c2ecf20Sopenharmony_ci dev_err(&port->dev, "submit interrupt urb failed: %d\n", 10138c2ecf20Sopenharmony_ci result); 10148c2ecf20Sopenharmony_ci return result; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return usb_serial_generic_resume(serial); 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic struct usb_serial_driver f81232_device = { 10228c2ecf20Sopenharmony_ci .driver = { 10238c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10248c2ecf20Sopenharmony_ci .name = "f81232", 10258c2ecf20Sopenharmony_ci }, 10268c2ecf20Sopenharmony_ci .id_table = f81232_id_table, 10278c2ecf20Sopenharmony_ci .num_ports = 1, 10288c2ecf20Sopenharmony_ci .bulk_in_size = 256, 10298c2ecf20Sopenharmony_ci .bulk_out_size = 256, 10308c2ecf20Sopenharmony_ci .open = f81232_open, 10318c2ecf20Sopenharmony_ci .close = f81232_close, 10328c2ecf20Sopenharmony_ci .dtr_rts = f81232_dtr_rts, 10338c2ecf20Sopenharmony_ci .carrier_raised = f81232_carrier_raised, 10348c2ecf20Sopenharmony_ci .get_serial = f81232_get_serial_info, 10358c2ecf20Sopenharmony_ci .break_ctl = f81232_break_ctl, 10368c2ecf20Sopenharmony_ci .set_termios = f81232_set_termios, 10378c2ecf20Sopenharmony_ci .tiocmget = f81232_tiocmget, 10388c2ecf20Sopenharmony_ci .tiocmset = f81232_tiocmset, 10398c2ecf20Sopenharmony_ci .tiocmiwait = usb_serial_generic_tiocmiwait, 10408c2ecf20Sopenharmony_ci .tx_empty = f81232_tx_empty, 10418c2ecf20Sopenharmony_ci .process_read_urb = f81232_process_read_urb, 10428c2ecf20Sopenharmony_ci .read_int_callback = f81232_read_int_callback, 10438c2ecf20Sopenharmony_ci .port_probe = f81232_port_probe, 10448c2ecf20Sopenharmony_ci .suspend = f81232_suspend, 10458c2ecf20Sopenharmony_ci .resume = f81232_resume, 10468c2ecf20Sopenharmony_ci}; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic struct usb_serial_driver f81534a_device = { 10498c2ecf20Sopenharmony_ci .driver = { 10508c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10518c2ecf20Sopenharmony_ci .name = "f81534a", 10528c2ecf20Sopenharmony_ci }, 10538c2ecf20Sopenharmony_ci .id_table = f81534a_id_table, 10548c2ecf20Sopenharmony_ci .num_ports = 1, 10558c2ecf20Sopenharmony_ci .open = f81534a_open, 10568c2ecf20Sopenharmony_ci .close = f81232_close, 10578c2ecf20Sopenharmony_ci .dtr_rts = f81232_dtr_rts, 10588c2ecf20Sopenharmony_ci .carrier_raised = f81232_carrier_raised, 10598c2ecf20Sopenharmony_ci .get_serial = f81232_get_serial_info, 10608c2ecf20Sopenharmony_ci .break_ctl = f81232_break_ctl, 10618c2ecf20Sopenharmony_ci .set_termios = f81232_set_termios, 10628c2ecf20Sopenharmony_ci .tiocmget = f81232_tiocmget, 10638c2ecf20Sopenharmony_ci .tiocmset = f81232_tiocmset, 10648c2ecf20Sopenharmony_ci .tiocmiwait = usb_serial_generic_tiocmiwait, 10658c2ecf20Sopenharmony_ci .tx_empty = f81232_tx_empty, 10668c2ecf20Sopenharmony_ci .process_read_urb = f81534a_process_read_urb, 10678c2ecf20Sopenharmony_ci .read_int_callback = f81232_read_int_callback, 10688c2ecf20Sopenharmony_ci .port_probe = f81534a_port_probe, 10698c2ecf20Sopenharmony_ci .suspend = f81232_suspend, 10708c2ecf20Sopenharmony_ci .resume = f81232_resume, 10718c2ecf20Sopenharmony_ci}; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 10748c2ecf20Sopenharmony_ci &f81232_device, 10758c2ecf20Sopenharmony_ci &f81534a_device, 10768c2ecf20Sopenharmony_ci NULL, 10778c2ecf20Sopenharmony_ci}; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic struct usb_driver f81534a_ctrl_driver = { 10808c2ecf20Sopenharmony_ci .name = "f81534a_ctrl", 10818c2ecf20Sopenharmony_ci .id_table = f81534a_ctrl_id_table, 10828c2ecf20Sopenharmony_ci .probe = f81534a_ctrl_probe, 10838c2ecf20Sopenharmony_ci .disconnect = f81534a_ctrl_disconnect, 10848c2ecf20Sopenharmony_ci .resume = f81534a_ctrl_resume, 10858c2ecf20Sopenharmony_ci}; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic int __init f81232_init(void) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci int status; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci status = usb_register_driver(&f81534a_ctrl_driver, THIS_MODULE, 10928c2ecf20Sopenharmony_ci KBUILD_MODNAME); 10938c2ecf20Sopenharmony_ci if (status) 10948c2ecf20Sopenharmony_ci return status; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci status = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, 10978c2ecf20Sopenharmony_ci combined_id_table); 10988c2ecf20Sopenharmony_ci if (status) { 10998c2ecf20Sopenharmony_ci usb_deregister(&f81534a_ctrl_driver); 11008c2ecf20Sopenharmony_ci return status; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci return 0; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic void __exit f81232_exit(void) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci usb_serial_deregister_drivers(serial_drivers); 11098c2ecf20Sopenharmony_ci usb_deregister(&f81534a_ctrl_driver); 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cimodule_init(f81232_init); 11138c2ecf20Sopenharmony_cimodule_exit(f81232_exit); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Fintek F81232/532A/534A/535/536 USB to serial driver"); 11168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>"); 11178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Hong <peter_hong@fintek.com.tw>"); 11188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1119