18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Belkin USB Serial Adapter Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2000 William Greathouse (wgreathouse@smva.com) 68c2ecf20Sopenharmony_ci * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) 78c2ecf20Sopenharmony_ci * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is largely derived from work by the linux-usb group 108c2ecf20Sopenharmony_ci * and associated source files. Please see the usb/serial files for 118c2ecf20Sopenharmony_ci * individual credits and copyrights. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * See Documentation/usb/usb-serial.rst for more information on using this 148c2ecf20Sopenharmony_ci * driver 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * TODO: 178c2ecf20Sopenharmony_ci * -- Add true modem control line query capability. Currently we track the 188c2ecf20Sopenharmony_ci * states reported by the interrupt and the states we request. 198c2ecf20Sopenharmony_ci * -- Add support for flush commands 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/kernel.h> 238c2ecf20Sopenharmony_ci#include <linux/errno.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/tty.h> 268c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 278c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 288c2ecf20Sopenharmony_ci#include <linux/module.h> 298c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 308c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 318c2ecf20Sopenharmony_ci#include <linux/usb.h> 328c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 338c2ecf20Sopenharmony_ci#include "belkin_sa.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "William Greathouse <wgreathouse@smva.com>" 368c2ecf20Sopenharmony_ci#define DRIVER_DESC "USB Belkin Serial converter driver" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* function prototypes for a Belkin USB Serial Adapter F5U103 */ 398c2ecf20Sopenharmony_cistatic int belkin_sa_port_probe(struct usb_serial_port *port); 408c2ecf20Sopenharmony_cistatic int belkin_sa_port_remove(struct usb_serial_port *port); 418c2ecf20Sopenharmony_cistatic int belkin_sa_open(struct tty_struct *tty, 428c2ecf20Sopenharmony_ci struct usb_serial_port *port); 438c2ecf20Sopenharmony_cistatic void belkin_sa_close(struct usb_serial_port *port); 448c2ecf20Sopenharmony_cistatic void belkin_sa_read_int_callback(struct urb *urb); 458c2ecf20Sopenharmony_cistatic void belkin_sa_process_read_urb(struct urb *urb); 468c2ecf20Sopenharmony_cistatic void belkin_sa_set_termios(struct tty_struct *tty, 478c2ecf20Sopenharmony_ci struct usb_serial_port *port, struct ktermios * old); 488c2ecf20Sopenharmony_cistatic void belkin_sa_break_ctl(struct tty_struct *tty, int break_state); 498c2ecf20Sopenharmony_cistatic int belkin_sa_tiocmget(struct tty_struct *tty); 508c2ecf20Sopenharmony_cistatic int belkin_sa_tiocmset(struct tty_struct *tty, 518c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = { 558c2ecf20Sopenharmony_ci { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) }, 568c2ecf20Sopenharmony_ci { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, 578c2ecf20Sopenharmony_ci { USB_DEVICE(PERACOM_VID, PERACOM_PID) }, 588c2ecf20Sopenharmony_ci { USB_DEVICE(GOHUBS_VID, GOHUBS_PID) }, 598c2ecf20Sopenharmony_ci { USB_DEVICE(GOHUBS_VID, HANDYLINK_PID) }, 608c2ecf20Sopenharmony_ci { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, 618c2ecf20Sopenharmony_ci { } /* Terminating entry */ 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* All of the device info needed for the serial converters */ 668c2ecf20Sopenharmony_cistatic struct usb_serial_driver belkin_device = { 678c2ecf20Sopenharmony_ci .driver = { 688c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 698c2ecf20Sopenharmony_ci .name = "belkin", 708c2ecf20Sopenharmony_ci }, 718c2ecf20Sopenharmony_ci .description = "Belkin / Peracom / GoHubs USB Serial Adapter", 728c2ecf20Sopenharmony_ci .id_table = id_table, 738c2ecf20Sopenharmony_ci .num_ports = 1, 748c2ecf20Sopenharmony_ci .open = belkin_sa_open, 758c2ecf20Sopenharmony_ci .close = belkin_sa_close, 768c2ecf20Sopenharmony_ci .read_int_callback = belkin_sa_read_int_callback, 778c2ecf20Sopenharmony_ci .process_read_urb = belkin_sa_process_read_urb, 788c2ecf20Sopenharmony_ci .set_termios = belkin_sa_set_termios, 798c2ecf20Sopenharmony_ci .break_ctl = belkin_sa_break_ctl, 808c2ecf20Sopenharmony_ci .tiocmget = belkin_sa_tiocmget, 818c2ecf20Sopenharmony_ci .tiocmset = belkin_sa_tiocmset, 828c2ecf20Sopenharmony_ci .port_probe = belkin_sa_port_probe, 838c2ecf20Sopenharmony_ci .port_remove = belkin_sa_port_remove, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 878c2ecf20Sopenharmony_ci &belkin_device, NULL 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct belkin_sa_private { 918c2ecf20Sopenharmony_ci spinlock_t lock; 928c2ecf20Sopenharmony_ci unsigned long control_state; 938c2ecf20Sopenharmony_ci unsigned char last_lsr; 948c2ecf20Sopenharmony_ci unsigned char last_msr; 958c2ecf20Sopenharmony_ci int bad_flow_control; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * *************************************************************************** 1018c2ecf20Sopenharmony_ci * Belkin USB Serial Adapter F5U103 specific driver functions 1028c2ecf20Sopenharmony_ci * *************************************************************************** 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define WDR_TIMEOUT 5000 /* default urb timeout */ 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* assumes that struct usb_serial *serial is available */ 1088c2ecf20Sopenharmony_ci#define BSA_USB_CMD(c, v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \ 1098c2ecf20Sopenharmony_ci (c), BELKIN_SA_SET_REQUEST_TYPE, \ 1108c2ecf20Sopenharmony_ci (v), 0, NULL, 0, WDR_TIMEOUT) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int belkin_sa_port_probe(struct usb_serial_port *port) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct usb_device *dev = port->serial->dev; 1158c2ecf20Sopenharmony_ci struct belkin_sa_private *priv; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci priv = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL); 1188c2ecf20Sopenharmony_ci if (!priv) 1198c2ecf20Sopenharmony_ci return -ENOMEM; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 1228c2ecf20Sopenharmony_ci priv->control_state = 0; 1238c2ecf20Sopenharmony_ci priv->last_lsr = 0; 1248c2ecf20Sopenharmony_ci priv->last_msr = 0; 1258c2ecf20Sopenharmony_ci /* see comments at top of file */ 1268c2ecf20Sopenharmony_ci priv->bad_flow_control = 1278c2ecf20Sopenharmony_ci (le16_to_cpu(dev->descriptor.bcdDevice) <= 0x0206) ? 1 : 0; 1288c2ecf20Sopenharmony_ci dev_info(&dev->dev, "bcdDevice: %04x, bfc: %d\n", 1298c2ecf20Sopenharmony_ci le16_to_cpu(dev->descriptor.bcdDevice), 1308c2ecf20Sopenharmony_ci priv->bad_flow_control); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci usb_set_serial_port_data(port, priv); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int belkin_sa_port_remove(struct usb_serial_port *port) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct belkin_sa_private *priv; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 1428c2ecf20Sopenharmony_ci kfree(priv); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int belkin_sa_open(struct tty_struct *tty, 1488c2ecf20Sopenharmony_ci struct usb_serial_port *port) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int retval; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 1538c2ecf20Sopenharmony_ci if (retval) { 1548c2ecf20Sopenharmony_ci dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); 1558c2ecf20Sopenharmony_ci return retval; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci retval = usb_serial_generic_open(tty, port); 1598c2ecf20Sopenharmony_ci if (retval) 1608c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return retval; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void belkin_sa_close(struct usb_serial_port *port) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci usb_serial_generic_close(port); 1688c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void belkin_sa_read_int_callback(struct urb *urb) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 1748c2ecf20Sopenharmony_ci struct belkin_sa_private *priv; 1758c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 1768c2ecf20Sopenharmony_ci int retval; 1778c2ecf20Sopenharmony_ci int status = urb->status; 1788c2ecf20Sopenharmony_ci unsigned long flags; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci switch (status) { 1818c2ecf20Sopenharmony_ci case 0: 1828c2ecf20Sopenharmony_ci /* success */ 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case -ECONNRESET: 1858c2ecf20Sopenharmony_ci case -ENOENT: 1868c2ecf20Sopenharmony_ci case -ESHUTDOWN: 1878c2ecf20Sopenharmony_ci /* this urb is terminated, clean up */ 1888c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", 1898c2ecf20Sopenharmony_ci __func__, status); 1908c2ecf20Sopenharmony_ci return; 1918c2ecf20Sopenharmony_ci default: 1928c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", 1938c2ecf20Sopenharmony_ci __func__, status); 1948c2ecf20Sopenharmony_ci goto exit; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Handle known interrupt data */ 2008c2ecf20Sopenharmony_ci /* ignore data[0] and data[1] */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 2038c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 2048c2ecf20Sopenharmony_ci priv->last_msr = data[BELKIN_SA_MSR_INDEX]; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Record Control Line states */ 2078c2ecf20Sopenharmony_ci if (priv->last_msr & BELKIN_SA_MSR_DSR) 2088c2ecf20Sopenharmony_ci priv->control_state |= TIOCM_DSR; 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci priv->control_state &= ~TIOCM_DSR; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (priv->last_msr & BELKIN_SA_MSR_CTS) 2138c2ecf20Sopenharmony_ci priv->control_state |= TIOCM_CTS; 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci priv->control_state &= ~TIOCM_CTS; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (priv->last_msr & BELKIN_SA_MSR_RI) 2188c2ecf20Sopenharmony_ci priv->control_state |= TIOCM_RI; 2198c2ecf20Sopenharmony_ci else 2208c2ecf20Sopenharmony_ci priv->control_state &= ~TIOCM_RI; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (priv->last_msr & BELKIN_SA_MSR_CD) 2238c2ecf20Sopenharmony_ci priv->control_state |= TIOCM_CD; 2248c2ecf20Sopenharmony_ci else 2258c2ecf20Sopenharmony_ci priv->control_state &= ~TIOCM_CD; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci priv->last_lsr = data[BELKIN_SA_LSR_INDEX]; 2288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2298c2ecf20Sopenharmony_ciexit: 2308c2ecf20Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 2318c2ecf20Sopenharmony_ci if (retval) 2328c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s - usb_submit_urb failed with " 2338c2ecf20Sopenharmony_ci "result %d\n", __func__, retval); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void belkin_sa_process_read_urb(struct urb *urb) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 2398c2ecf20Sopenharmony_ci struct belkin_sa_private *priv = usb_get_serial_port_data(port); 2408c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 2418c2ecf20Sopenharmony_ci unsigned long flags; 2428c2ecf20Sopenharmony_ci unsigned char status; 2438c2ecf20Sopenharmony_ci char tty_flag; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Update line status */ 2468c2ecf20Sopenharmony_ci tty_flag = TTY_NORMAL; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 2498c2ecf20Sopenharmony_ci status = priv->last_lsr; 2508c2ecf20Sopenharmony_ci priv->last_lsr &= ~BELKIN_SA_LSR_ERR; 2518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (!urb->actual_length) 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (status & BELKIN_SA_LSR_ERR) { 2578c2ecf20Sopenharmony_ci /* Break takes precedence over parity, which takes precedence 2588c2ecf20Sopenharmony_ci * over framing errors. */ 2598c2ecf20Sopenharmony_ci if (status & BELKIN_SA_LSR_BI) 2608c2ecf20Sopenharmony_ci tty_flag = TTY_BREAK; 2618c2ecf20Sopenharmony_ci else if (status & BELKIN_SA_LSR_PE) 2628c2ecf20Sopenharmony_ci tty_flag = TTY_PARITY; 2638c2ecf20Sopenharmony_ci else if (status & BELKIN_SA_LSR_FE) 2648c2ecf20Sopenharmony_ci tty_flag = TTY_FRAME; 2658c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Overrun is special, not associated with a char. */ 2688c2ecf20Sopenharmony_ci if (status & BELKIN_SA_LSR_OE) 2698c2ecf20Sopenharmony_ci tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, 2738c2ecf20Sopenharmony_ci urb->actual_length); 2748c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->port); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void belkin_sa_set_termios(struct tty_struct *tty, 2788c2ecf20Sopenharmony_ci struct usb_serial_port *port, struct ktermios *old_termios) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 2818c2ecf20Sopenharmony_ci struct belkin_sa_private *priv = usb_get_serial_port_data(port); 2828c2ecf20Sopenharmony_ci unsigned int iflag; 2838c2ecf20Sopenharmony_ci unsigned int cflag; 2848c2ecf20Sopenharmony_ci unsigned int old_iflag = 0; 2858c2ecf20Sopenharmony_ci unsigned int old_cflag = 0; 2868c2ecf20Sopenharmony_ci __u16 urb_value = 0; /* Will hold the new flags */ 2878c2ecf20Sopenharmony_ci unsigned long flags; 2888c2ecf20Sopenharmony_ci unsigned long control_state; 2898c2ecf20Sopenharmony_ci int bad_flow_control; 2908c2ecf20Sopenharmony_ci speed_t baud; 2918c2ecf20Sopenharmony_ci struct ktermios *termios = &tty->termios; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci iflag = termios->c_iflag; 2948c2ecf20Sopenharmony_ci cflag = termios->c_cflag; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci termios->c_cflag &= ~CMSPAR; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* get a local copy of the current port settings */ 2998c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3008c2ecf20Sopenharmony_ci control_state = priv->control_state; 3018c2ecf20Sopenharmony_ci bad_flow_control = priv->bad_flow_control; 3028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci old_iflag = old_termios->c_iflag; 3058c2ecf20Sopenharmony_ci old_cflag = old_termios->c_cflag; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* Set the baud rate */ 3088c2ecf20Sopenharmony_ci if ((cflag & CBAUD) != (old_cflag & CBAUD)) { 3098c2ecf20Sopenharmony_ci /* reassert DTR and (maybe) RTS on transition from B0 */ 3108c2ecf20Sopenharmony_ci if ((old_cflag & CBAUD) == B0) { 3118c2ecf20Sopenharmony_ci control_state |= (TIOCM_DTR|TIOCM_RTS); 3128c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0) 3138c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set DTR error\n"); 3148c2ecf20Sopenharmony_ci /* don't set RTS if using hardware flow control */ 3158c2ecf20Sopenharmony_ci if (!(old_cflag & CRTSCTS)) 3168c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST 3178c2ecf20Sopenharmony_ci , 1) < 0) 3188c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set RTS error\n"); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci baud = tty_get_baud_rate(tty); 3238c2ecf20Sopenharmony_ci if (baud) { 3248c2ecf20Sopenharmony_ci urb_value = BELKIN_SA_BAUD(baud); 3258c2ecf20Sopenharmony_ci /* Clip to maximum speed */ 3268c2ecf20Sopenharmony_ci if (urb_value == 0) 3278c2ecf20Sopenharmony_ci urb_value = 1; 3288c2ecf20Sopenharmony_ci /* Turn it back into a resulting real baud rate */ 3298c2ecf20Sopenharmony_ci baud = BELKIN_SA_BAUD(urb_value); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Report the actual baud rate back to the caller */ 3328c2ecf20Sopenharmony_ci tty_encode_baud_rate(tty, baud, baud); 3338c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0) 3348c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set baudrate error\n"); 3358c2ecf20Sopenharmony_ci } else { 3368c2ecf20Sopenharmony_ci /* Disable flow control */ 3378c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, 3388c2ecf20Sopenharmony_ci BELKIN_SA_FLOW_NONE) < 0) 3398c2ecf20Sopenharmony_ci dev_err(&port->dev, "Disable flowcontrol error\n"); 3408c2ecf20Sopenharmony_ci /* Drop RTS and DTR */ 3418c2ecf20Sopenharmony_ci control_state &= ~(TIOCM_DTR | TIOCM_RTS); 3428c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0) 3438c2ecf20Sopenharmony_ci dev_err(&port->dev, "DTR LOW error\n"); 3448c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0) 3458c2ecf20Sopenharmony_ci dev_err(&port->dev, "RTS LOW error\n"); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* set the parity */ 3498c2ecf20Sopenharmony_ci if ((cflag ^ old_cflag) & (PARENB | PARODD)) { 3508c2ecf20Sopenharmony_ci if (cflag & PARENB) 3518c2ecf20Sopenharmony_ci urb_value = (cflag & PARODD) ? BELKIN_SA_PARITY_ODD 3528c2ecf20Sopenharmony_ci : BELKIN_SA_PARITY_EVEN; 3538c2ecf20Sopenharmony_ci else 3548c2ecf20Sopenharmony_ci urb_value = BELKIN_SA_PARITY_NONE; 3558c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_PARITY_REQUEST, urb_value) < 0) 3568c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set parity error\n"); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* set the number of data bits */ 3608c2ecf20Sopenharmony_ci if ((cflag & CSIZE) != (old_cflag & CSIZE)) { 3618c2ecf20Sopenharmony_ci switch (cflag & CSIZE) { 3628c2ecf20Sopenharmony_ci case CS5: 3638c2ecf20Sopenharmony_ci urb_value = BELKIN_SA_DATA_BITS(5); 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci case CS6: 3668c2ecf20Sopenharmony_ci urb_value = BELKIN_SA_DATA_BITS(6); 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci case CS7: 3698c2ecf20Sopenharmony_ci urb_value = BELKIN_SA_DATA_BITS(7); 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci case CS8: 3728c2ecf20Sopenharmony_ci urb_value = BELKIN_SA_DATA_BITS(8); 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci default: 3758c2ecf20Sopenharmony_ci dev_dbg(&port->dev, 3768c2ecf20Sopenharmony_ci "CSIZE was not CS5-CS8, using default of 8\n"); 3778c2ecf20Sopenharmony_ci urb_value = BELKIN_SA_DATA_BITS(8); 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0) 3818c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set data bits error\n"); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* set the number of stop bits */ 3858c2ecf20Sopenharmony_ci if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { 3868c2ecf20Sopenharmony_ci urb_value = (cflag & CSTOPB) ? BELKIN_SA_STOP_BITS(2) 3878c2ecf20Sopenharmony_ci : BELKIN_SA_STOP_BITS(1); 3888c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_STOP_BITS_REQUEST, 3898c2ecf20Sopenharmony_ci urb_value) < 0) 3908c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set stop bits error\n"); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Set flow control */ 3948c2ecf20Sopenharmony_ci if (((iflag ^ old_iflag) & (IXOFF | IXON)) || 3958c2ecf20Sopenharmony_ci ((cflag ^ old_cflag) & CRTSCTS)) { 3968c2ecf20Sopenharmony_ci urb_value = 0; 3978c2ecf20Sopenharmony_ci if ((iflag & IXOFF) || (iflag & IXON)) 3988c2ecf20Sopenharmony_ci urb_value |= (BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON); 3998c2ecf20Sopenharmony_ci else 4008c2ecf20Sopenharmony_ci urb_value &= ~(BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (cflag & CRTSCTS) 4038c2ecf20Sopenharmony_ci urb_value |= (BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); 4048c2ecf20Sopenharmony_ci else 4058c2ecf20Sopenharmony_ci urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (bad_flow_control) 4088c2ecf20Sopenharmony_ci urb_value &= ~(BELKIN_SA_FLOW_IRTS); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0) 4118c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set flow control error\n"); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* save off the modified port settings */ 4158c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 4168c2ecf20Sopenharmony_ci priv->control_state = control_state; 4178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void belkin_sa_break_ctl(struct tty_struct *tty, int break_state) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 4238c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0) 4268c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set break_ctl %d\n", break_state); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int belkin_sa_tiocmget(struct tty_struct *tty) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 4328c2ecf20Sopenharmony_ci struct belkin_sa_private *priv = usb_get_serial_port_data(port); 4338c2ecf20Sopenharmony_ci unsigned long control_state; 4348c2ecf20Sopenharmony_ci unsigned long flags; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 4378c2ecf20Sopenharmony_ci control_state = priv->control_state; 4388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return control_state; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int belkin_sa_tiocmset(struct tty_struct *tty, 4448c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 4478c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 4488c2ecf20Sopenharmony_ci struct belkin_sa_private *priv = usb_get_serial_port_data(port); 4498c2ecf20Sopenharmony_ci unsigned long control_state; 4508c2ecf20Sopenharmony_ci unsigned long flags; 4518c2ecf20Sopenharmony_ci int retval; 4528c2ecf20Sopenharmony_ci int rts = 0; 4538c2ecf20Sopenharmony_ci int dtr = 0; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 4568c2ecf20Sopenharmony_ci control_state = priv->control_state; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (set & TIOCM_RTS) { 4598c2ecf20Sopenharmony_ci control_state |= TIOCM_RTS; 4608c2ecf20Sopenharmony_ci rts = 1; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci if (set & TIOCM_DTR) { 4638c2ecf20Sopenharmony_ci control_state |= TIOCM_DTR; 4648c2ecf20Sopenharmony_ci dtr = 1; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci if (clear & TIOCM_RTS) { 4678c2ecf20Sopenharmony_ci control_state &= ~TIOCM_RTS; 4688c2ecf20Sopenharmony_ci rts = 0; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci if (clear & TIOCM_DTR) { 4718c2ecf20Sopenharmony_ci control_state &= ~TIOCM_DTR; 4728c2ecf20Sopenharmony_ci dtr = 0; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci priv->control_state = control_state; 4768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci retval = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, rts); 4798c2ecf20Sopenharmony_ci if (retval < 0) { 4808c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set RTS error %d\n", retval); 4818c2ecf20Sopenharmony_ci goto exit; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci retval = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, dtr); 4858c2ecf20Sopenharmony_ci if (retval < 0) { 4868c2ecf20Sopenharmony_ci dev_err(&port->dev, "Set DTR error %d\n", retval); 4878c2ecf20Sopenharmony_ci goto exit; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ciexit: 4908c2ecf20Sopenharmony_ci return retval; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 4968c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 4978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 498