162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * usb-serial driver for Quatech USB 2 devices 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * These devices all have only 1 bulk in and 1 bulk out that is shared 862306a36Sopenharmony_ci * for all serial ports. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <asm/unaligned.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/tty.h> 1662306a36Sopenharmony_ci#include <linux/tty_driver.h> 1762306a36Sopenharmony_ci#include <linux/tty_flip.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/serial.h> 2062306a36Sopenharmony_ci#include <linux/usb.h> 2162306a36Sopenharmony_ci#include <linux/usb/serial.h> 2262306a36Sopenharmony_ci#include <linux/serial_reg.h> 2362306a36Sopenharmony_ci#include <linux/uaccess.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* default urb timeout for usb operations */ 2662306a36Sopenharmony_ci#define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define QT_OPEN_CLOSE_CHANNEL 0xca 2962306a36Sopenharmony_ci#define QT_SET_GET_DEVICE 0xc2 3062306a36Sopenharmony_ci#define QT_SET_GET_REGISTER 0xc0 3162306a36Sopenharmony_ci#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc 3262306a36Sopenharmony_ci#define QT_SET_ATF 0xcd 3362306a36Sopenharmony_ci#define QT_TRANSFER_IN 0xc0 3462306a36Sopenharmony_ci#define QT_HW_FLOW_CONTROL_MASK 0xc5 3562306a36Sopenharmony_ci#define QT_SW_FLOW_CONTROL_MASK 0xc6 3662306a36Sopenharmony_ci#define QT2_BREAK_CONTROL 0xc8 3762306a36Sopenharmony_ci#define QT2_GET_SET_UART 0xc1 3862306a36Sopenharmony_ci#define QT2_FLUSH_DEVICE 0xc4 3962306a36Sopenharmony_ci#define QT2_GET_SET_QMCR 0xe1 4062306a36Sopenharmony_ci#define QT2_QMCR_RS232 0x40 4162306a36Sopenharmony_ci#define QT2_QMCR_RS422 0x10 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* status bytes for the device */ 4862306a36Sopenharmony_ci#define QT2_CONTROL_BYTE 0x1b 4962306a36Sopenharmony_ci#define QT2_LINE_STATUS 0x00 /* following 1 byte is line status */ 5062306a36Sopenharmony_ci#define QT2_MODEM_STATUS 0x01 /* following 1 byte is modem status */ 5162306a36Sopenharmony_ci#define QT2_XMIT_HOLD 0x02 /* following 2 bytes are ?? */ 5262306a36Sopenharmony_ci#define QT2_CHANGE_PORT 0x03 /* following 1 byte is port to change to */ 5362306a36Sopenharmony_ci#define QT2_REC_FLUSH 0x04 /* no following info */ 5462306a36Sopenharmony_ci#define QT2_XMIT_FLUSH 0x05 /* no following info */ 5562306a36Sopenharmony_ci#define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define MAX_BAUD_RATE 921600 5862306a36Sopenharmony_ci#define DEFAULT_BAUD_RATE 9600 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define QT2_READ_BUFFER_SIZE 512 /* size of read buffer */ 6162306a36Sopenharmony_ci#define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */ 6262306a36Sopenharmony_ci#define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver" 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define USB_VENDOR_ID_QUATECH 0x061d 6762306a36Sopenharmony_ci#define QUATECH_SSU2_100 0xC120 /* RS232 single port */ 6862306a36Sopenharmony_ci#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */ 6962306a36Sopenharmony_ci#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */ 7062306a36Sopenharmony_ci#define QUATECH_QSU2_100 0xC160 /* RS232 four port */ 7162306a36Sopenharmony_ci#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */ 7262306a36Sopenharmony_ci#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */ 7362306a36Sopenharmony_ci#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistruct qt2_device_detail { 7662306a36Sopenharmony_ci int product_id; 7762306a36Sopenharmony_ci int num_ports; 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define QT_DETAILS(prod, ports) \ 8162306a36Sopenharmony_ci .product_id = (prod), \ 8262306a36Sopenharmony_ci .num_ports = (ports) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic const struct qt2_device_detail qt2_device_details[] = { 8562306a36Sopenharmony_ci {QT_DETAILS(QUATECH_SSU2_100, 1)}, 8662306a36Sopenharmony_ci {QT_DETAILS(QUATECH_DSU2_400, 2)}, 8762306a36Sopenharmony_ci {QT_DETAILS(QUATECH_DSU2_100, 2)}, 8862306a36Sopenharmony_ci {QT_DETAILS(QUATECH_QSU2_400, 4)}, 8962306a36Sopenharmony_ci {QT_DETAILS(QUATECH_QSU2_100, 4)}, 9062306a36Sopenharmony_ci {QT_DETAILS(QUATECH_ESU2_400, 8)}, 9162306a36Sopenharmony_ci {QT_DETAILS(QUATECH_ESU2_100, 8)}, 9262306a36Sopenharmony_ci {QT_DETAILS(0, 0)} /* Terminating entry */ 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic const struct usb_device_id id_table[] = { 9662306a36Sopenharmony_ci {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)}, 9762306a36Sopenharmony_ci {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)}, 9862306a36Sopenharmony_ci {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)}, 9962306a36Sopenharmony_ci {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)}, 10062306a36Sopenharmony_ci {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)}, 10162306a36Sopenharmony_ci {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)}, 10262306a36Sopenharmony_ci {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)}, 10362306a36Sopenharmony_ci {} /* Terminating entry */ 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistruct qt2_serial_private { 10862306a36Sopenharmony_ci unsigned char current_port; /* current port for incoming data */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci struct urb *read_urb; /* shared among all ports */ 11162306a36Sopenharmony_ci char *read_buffer; 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistruct qt2_port_private { 11562306a36Sopenharmony_ci u8 device_port; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci spinlock_t urb_lock; 11862306a36Sopenharmony_ci bool urb_in_use; 11962306a36Sopenharmony_ci struct urb *write_urb; 12062306a36Sopenharmony_ci char *write_buffer; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci spinlock_t lock; 12362306a36Sopenharmony_ci u8 shadowLSR; 12462306a36Sopenharmony_ci u8 shadowMSR; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci struct usb_serial_port *port; 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch); 13062306a36Sopenharmony_cistatic void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch); 13162306a36Sopenharmony_cistatic void qt2_write_bulk_callback(struct urb *urb); 13262306a36Sopenharmony_cistatic void qt2_read_bulk_callback(struct urb *urb); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic void qt2_release(struct usb_serial *serial) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct qt2_serial_private *serial_priv; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci serial_priv = usb_get_serial_data(serial); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci usb_kill_urb(serial_priv->read_urb); 14162306a36Sopenharmony_ci usb_free_urb(serial_priv->read_urb); 14262306a36Sopenharmony_ci kfree(serial_priv->read_buffer); 14362306a36Sopenharmony_ci kfree(serial_priv); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic inline int calc_baud_divisor(int baudrate) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci int divisor, rem; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci divisor = MAX_BAUD_RATE / baudrate; 15162306a36Sopenharmony_ci rem = MAX_BAUD_RATE % baudrate; 15262306a36Sopenharmony_ci /* Round to nearest divisor */ 15362306a36Sopenharmony_ci if (((rem * 2) >= baudrate) && (baudrate != 110)) 15462306a36Sopenharmony_ci divisor++; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return divisor; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic inline int qt2_set_port_config(struct usb_device *dev, 16062306a36Sopenharmony_ci unsigned char port_number, 16162306a36Sopenharmony_ci u16 baudrate, u16 lcr) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci int divisor = calc_baud_divisor(baudrate); 16462306a36Sopenharmony_ci u16 index = ((u16) (lcr << 8) | (u16) (port_number)); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 16762306a36Sopenharmony_ci QT2_GET_SET_UART, 0x40, 16862306a36Sopenharmony_ci divisor, index, NULL, 0, QT2_USB_TIMEOUT); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic inline int qt2_control_msg(struct usb_device *dev, 17262306a36Sopenharmony_ci u8 request, u16 data, u16 index) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 17562306a36Sopenharmony_ci request, 0x40, data, index, 17662306a36Sopenharmony_ci NULL, 0, QT2_USB_TIMEOUT); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic inline int qt2_getregister(struct usb_device *dev, 18062306a36Sopenharmony_ci u8 uart, 18162306a36Sopenharmony_ci u8 reg, 18262306a36Sopenharmony_ci u8 *data) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci int ret; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 18762306a36Sopenharmony_ci QT_SET_GET_REGISTER, 0xc0, reg, 18862306a36Sopenharmony_ci uart, data, sizeof(*data), QT2_USB_TIMEOUT); 18962306a36Sopenharmony_ci if (ret < (int)sizeof(*data)) { 19062306a36Sopenharmony_ci if (ret >= 0) 19162306a36Sopenharmony_ci ret = -EIO; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic inline int qt2_setregister(struct usb_device *dev, 19862306a36Sopenharmony_ci u8 uart, u8 reg, u16 data) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci u16 value = (data << 8) | reg; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 20362306a36Sopenharmony_ci QT_SET_GET_REGISTER, 0x40, value, uart, 20462306a36Sopenharmony_ci NULL, 0, QT2_USB_TIMEOUT); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic inline int update_mctrl(struct qt2_port_private *port_priv, 20862306a36Sopenharmony_ci unsigned int set, unsigned int clear) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct usb_serial_port *port = port_priv->port; 21162306a36Sopenharmony_ci struct usb_device *dev = port->serial->dev; 21262306a36Sopenharmony_ci unsigned urb_value; 21362306a36Sopenharmony_ci int status; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { 21662306a36Sopenharmony_ci dev_dbg(&port->dev, 21762306a36Sopenharmony_ci "update_mctrl - DTR|RTS not being set|cleared\n"); 21862306a36Sopenharmony_ci return 0; /* no change */ 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci clear &= ~set; /* 'set' takes precedence over 'clear' */ 22262306a36Sopenharmony_ci urb_value = 0; 22362306a36Sopenharmony_ci if (set & TIOCM_DTR) 22462306a36Sopenharmony_ci urb_value |= UART_MCR_DTR; 22562306a36Sopenharmony_ci if (set & TIOCM_RTS) 22662306a36Sopenharmony_ci urb_value |= UART_MCR_RTS; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci status = qt2_setregister(dev, port_priv->device_port, UART_MCR, 22962306a36Sopenharmony_ci urb_value); 23062306a36Sopenharmony_ci if (status < 0) 23162306a36Sopenharmony_ci dev_err(&port->dev, 23262306a36Sopenharmony_ci "update_mctrl - Error from MODEM_CTRL urb: %i\n", 23362306a36Sopenharmony_ci status); 23462306a36Sopenharmony_ci return status; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int qt2_calc_num_ports(struct usb_serial *serial, 23862306a36Sopenharmony_ci struct usb_serial_endpoints *epds) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct qt2_device_detail d; 24162306a36Sopenharmony_ci int i; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci for (i = 0; d = qt2_device_details[i], d.product_id != 0; i++) { 24462306a36Sopenharmony_ci if (d.product_id == le16_to_cpu(serial->dev->descriptor.idProduct)) 24562306a36Sopenharmony_ci return d.num_ports; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* we didn't recognize the device */ 24962306a36Sopenharmony_ci dev_err(&serial->dev->dev, 25062306a36Sopenharmony_ci "don't know the number of ports, assuming 1\n"); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return 1; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic void qt2_set_termios(struct tty_struct *tty, 25662306a36Sopenharmony_ci struct usb_serial_port *port, 25762306a36Sopenharmony_ci const struct ktermios *old_termios) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct usb_device *dev = port->serial->dev; 26062306a36Sopenharmony_ci struct qt2_port_private *port_priv; 26162306a36Sopenharmony_ci struct ktermios *termios = &tty->termios; 26262306a36Sopenharmony_ci u16 baud; 26362306a36Sopenharmony_ci unsigned int cflag = termios->c_cflag; 26462306a36Sopenharmony_ci u16 new_lcr = 0; 26562306a36Sopenharmony_ci int status; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (cflag & PARENB) { 27062306a36Sopenharmony_ci if (cflag & PARODD) 27162306a36Sopenharmony_ci new_lcr |= UART_LCR_PARITY; 27262306a36Sopenharmony_ci else 27362306a36Sopenharmony_ci new_lcr |= SERIAL_EVEN_PARITY; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci new_lcr |= UART_LCR_WLEN(tty_get_char_size(cflag)); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci baud = tty_get_baud_rate(tty); 27962306a36Sopenharmony_ci if (!baud) 28062306a36Sopenharmony_ci baud = 9600; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci status = qt2_set_port_config(dev, port_priv->device_port, baud, 28362306a36Sopenharmony_ci new_lcr); 28462306a36Sopenharmony_ci if (status < 0) 28562306a36Sopenharmony_ci dev_err(&port->dev, "%s - qt2_set_port_config failed: %i\n", 28662306a36Sopenharmony_ci __func__, status); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (cflag & CRTSCTS) 28962306a36Sopenharmony_ci status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, 29062306a36Sopenharmony_ci SERIAL_CRTSCTS, 29162306a36Sopenharmony_ci port_priv->device_port); 29262306a36Sopenharmony_ci else 29362306a36Sopenharmony_ci status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, 29462306a36Sopenharmony_ci 0, port_priv->device_port); 29562306a36Sopenharmony_ci if (status < 0) 29662306a36Sopenharmony_ci dev_err(&port->dev, "%s - set HW flow control failed: %i\n", 29762306a36Sopenharmony_ci __func__, status); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (I_IXOFF(tty) || I_IXON(tty)) { 30062306a36Sopenharmony_ci u16 x = ((u16) (START_CHAR(tty) << 8) | (u16) (STOP_CHAR(tty))); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, 30362306a36Sopenharmony_ci x, port_priv->device_port); 30462306a36Sopenharmony_ci } else 30562306a36Sopenharmony_ci status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, 30662306a36Sopenharmony_ci 0, port_priv->device_port); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (status < 0) 30962306a36Sopenharmony_ci dev_err(&port->dev, "%s - set SW flow control failed: %i\n", 31062306a36Sopenharmony_ci __func__, status); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct usb_serial *serial; 31762306a36Sopenharmony_ci struct qt2_port_private *port_priv; 31862306a36Sopenharmony_ci u8 *data; 31962306a36Sopenharmony_ci u16 device_port; 32062306a36Sopenharmony_ci int status; 32162306a36Sopenharmony_ci unsigned long flags; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci device_port = port->port_number; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci serial = port->serial; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* set the port to RS232 mode */ 33062306a36Sopenharmony_ci status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR, 33162306a36Sopenharmony_ci QT2_QMCR_RS232, device_port); 33262306a36Sopenharmony_ci if (status < 0) { 33362306a36Sopenharmony_ci dev_err(&port->dev, 33462306a36Sopenharmony_ci "%s failed to set RS232 mode for port %i error %i\n", 33562306a36Sopenharmony_ci __func__, device_port, status); 33662306a36Sopenharmony_ci return status; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci data = kzalloc(2, GFP_KERNEL); 34062306a36Sopenharmony_ci if (!data) 34162306a36Sopenharmony_ci return -ENOMEM; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* open the port */ 34462306a36Sopenharmony_ci status = usb_control_msg(serial->dev, 34562306a36Sopenharmony_ci usb_rcvctrlpipe(serial->dev, 0), 34662306a36Sopenharmony_ci QT_OPEN_CLOSE_CHANNEL, 34762306a36Sopenharmony_ci 0xc0, 0, 34862306a36Sopenharmony_ci device_port, data, 2, QT2_USB_TIMEOUT); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (status < 2) { 35162306a36Sopenharmony_ci dev_err(&port->dev, "%s - open port failed %i\n", __func__, 35262306a36Sopenharmony_ci status); 35362306a36Sopenharmony_ci if (status >= 0) 35462306a36Sopenharmony_ci status = -EIO; 35562306a36Sopenharmony_ci kfree(data); 35662306a36Sopenharmony_ci return status; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci spin_lock_irqsave(&port_priv->lock, flags); 36062306a36Sopenharmony_ci port_priv->shadowLSR = data[0]; 36162306a36Sopenharmony_ci port_priv->shadowMSR = data[1]; 36262306a36Sopenharmony_ci spin_unlock_irqrestore(&port_priv->lock, flags); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci kfree(data); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* set to default speed and 8bit word size */ 36762306a36Sopenharmony_ci status = qt2_set_port_config(serial->dev, device_port, 36862306a36Sopenharmony_ci DEFAULT_BAUD_RATE, UART_LCR_WLEN8); 36962306a36Sopenharmony_ci if (status < 0) { 37062306a36Sopenharmony_ci dev_err(&port->dev, "%s - initial setup failed (%i)\n", 37162306a36Sopenharmony_ci __func__, device_port); 37262306a36Sopenharmony_ci return status; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci port_priv->device_port = (u8) device_port; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (tty) 37862306a36Sopenharmony_ci qt2_set_termios(tty, port, &tty->termios); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return 0; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic void qt2_close(struct usb_serial_port *port) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct usb_serial *serial; 38762306a36Sopenharmony_ci struct qt2_port_private *port_priv; 38862306a36Sopenharmony_ci int i; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci serial = port->serial; 39162306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci usb_kill_urb(port_priv->write_urb); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* flush the port transmit buffer */ 39662306a36Sopenharmony_ci i = usb_control_msg(serial->dev, 39762306a36Sopenharmony_ci usb_sndctrlpipe(serial->dev, 0), 39862306a36Sopenharmony_ci QT2_FLUSH_DEVICE, 0x40, 1, 39962306a36Sopenharmony_ci port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (i < 0) 40262306a36Sopenharmony_ci dev_err(&port->dev, "%s - transmit buffer flush failed: %i\n", 40362306a36Sopenharmony_ci __func__, i); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* flush the port receive buffer */ 40662306a36Sopenharmony_ci i = usb_control_msg(serial->dev, 40762306a36Sopenharmony_ci usb_sndctrlpipe(serial->dev, 0), 40862306a36Sopenharmony_ci QT2_FLUSH_DEVICE, 0x40, 0, 40962306a36Sopenharmony_ci port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (i < 0) 41262306a36Sopenharmony_ci dev_err(&port->dev, "%s - receive buffer flush failed: %i\n", 41362306a36Sopenharmony_ci __func__, i); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* close the port */ 41662306a36Sopenharmony_ci i = usb_control_msg(serial->dev, 41762306a36Sopenharmony_ci usb_sndctrlpipe(serial->dev, 0), 41862306a36Sopenharmony_ci QT_OPEN_CLOSE_CHANNEL, 41962306a36Sopenharmony_ci 0x40, 0, 42062306a36Sopenharmony_ci port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (i < 0) 42362306a36Sopenharmony_ci dev_err(&port->dev, "%s - close port failed %i\n", 42462306a36Sopenharmony_ci __func__, i); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic void qt2_disconnect(struct usb_serial *serial) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct qt2_serial_private *serial_priv = usb_get_serial_data(serial); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci usb_kill_urb(serial_priv->read_urb); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci switch (*ch) { 43762306a36Sopenharmony_ci case QT2_LINE_STATUS: 43862306a36Sopenharmony_ci qt2_update_lsr(port, ch + 1); 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci case QT2_MODEM_STATUS: 44162306a36Sopenharmony_ci qt2_update_msr(port, ch + 1); 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic void qt2_process_read_urb(struct urb *urb) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct usb_serial *serial; 44962306a36Sopenharmony_ci struct qt2_serial_private *serial_priv; 45062306a36Sopenharmony_ci struct usb_serial_port *port; 45162306a36Sopenharmony_ci bool escapeflag; 45262306a36Sopenharmony_ci unsigned char *ch; 45362306a36Sopenharmony_ci int i; 45462306a36Sopenharmony_ci unsigned char newport; 45562306a36Sopenharmony_ci int len = urb->actual_length; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (!len) 45862306a36Sopenharmony_ci return; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci ch = urb->transfer_buffer; 46162306a36Sopenharmony_ci serial = urb->context; 46262306a36Sopenharmony_ci serial_priv = usb_get_serial_data(serial); 46362306a36Sopenharmony_ci port = serial->port[serial_priv->current_port]; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci for (i = 0; i < urb->actual_length; i++) { 46662306a36Sopenharmony_ci ch = (unsigned char *)urb->transfer_buffer + i; 46762306a36Sopenharmony_ci if ((i <= (len - 3)) && 46862306a36Sopenharmony_ci (*ch == QT2_CONTROL_BYTE) && 46962306a36Sopenharmony_ci (*(ch + 1) == QT2_CONTROL_BYTE)) { 47062306a36Sopenharmony_ci escapeflag = false; 47162306a36Sopenharmony_ci switch (*(ch + 2)) { 47262306a36Sopenharmony_ci case QT2_LINE_STATUS: 47362306a36Sopenharmony_ci case QT2_MODEM_STATUS: 47462306a36Sopenharmony_ci if (i > (len - 4)) { 47562306a36Sopenharmony_ci dev_warn(&port->dev, 47662306a36Sopenharmony_ci "%s - status message too short\n", 47762306a36Sopenharmony_ci __func__); 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci qt2_process_status(port, ch + 2); 48162306a36Sopenharmony_ci i += 3; 48262306a36Sopenharmony_ci escapeflag = true; 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case QT2_XMIT_HOLD: 48562306a36Sopenharmony_ci if (i > (len - 5)) { 48662306a36Sopenharmony_ci dev_warn(&port->dev, 48762306a36Sopenharmony_ci "%s - xmit_empty message too short\n", 48862306a36Sopenharmony_ci __func__); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci /* bytes_written = (ch[1] << 4) + ch[0]; */ 49262306a36Sopenharmony_ci i += 4; 49362306a36Sopenharmony_ci escapeflag = true; 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci case QT2_CHANGE_PORT: 49662306a36Sopenharmony_ci if (i > (len - 4)) { 49762306a36Sopenharmony_ci dev_warn(&port->dev, 49862306a36Sopenharmony_ci "%s - change_port message too short\n", 49962306a36Sopenharmony_ci __func__); 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci tty_flip_buffer_push(&port->port); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci newport = *(ch + 3); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (newport > serial->num_ports) { 50762306a36Sopenharmony_ci dev_err(&port->dev, 50862306a36Sopenharmony_ci "%s - port change to invalid port: %i\n", 50962306a36Sopenharmony_ci __func__, newport); 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci serial_priv->current_port = newport; 51462306a36Sopenharmony_ci port = serial->port[serial_priv->current_port]; 51562306a36Sopenharmony_ci i += 3; 51662306a36Sopenharmony_ci escapeflag = true; 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci case QT2_REC_FLUSH: 51962306a36Sopenharmony_ci case QT2_XMIT_FLUSH: 52062306a36Sopenharmony_ci i += 2; 52162306a36Sopenharmony_ci escapeflag = true; 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case QT2_CONTROL_ESCAPE: 52462306a36Sopenharmony_ci tty_insert_flip_string(&port->port, ch, 2); 52562306a36Sopenharmony_ci i += 2; 52662306a36Sopenharmony_ci escapeflag = true; 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci default: 52962306a36Sopenharmony_ci dev_warn(&port->dev, 53062306a36Sopenharmony_ci "%s - unsupported command %i\n", 53162306a36Sopenharmony_ci __func__, *(ch + 2)); 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci if (escapeflag) 53562306a36Sopenharmony_ci continue; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci tty_insert_flip_char(&port->port, *ch, TTY_NORMAL); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci tty_flip_buffer_push(&port->port); 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic void qt2_write_bulk_callback(struct urb *urb) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct usb_serial_port *port; 54762306a36Sopenharmony_ci struct qt2_port_private *port_priv; 54862306a36Sopenharmony_ci unsigned long flags; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci port = urb->context; 55162306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci spin_lock_irqsave(&port_priv->urb_lock, flags); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci port_priv->urb_in_use = false; 55662306a36Sopenharmony_ci usb_serial_port_softint(port); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci spin_unlock_irqrestore(&port_priv->urb_lock, flags); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic void qt2_read_bulk_callback(struct urb *urb) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct usb_serial *serial = urb->context; 56562306a36Sopenharmony_ci int status; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (urb->status) { 56862306a36Sopenharmony_ci dev_warn(&serial->dev->dev, 56962306a36Sopenharmony_ci "%s - non-zero urb status: %i\n", __func__, 57062306a36Sopenharmony_ci urb->status); 57162306a36Sopenharmony_ci return; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci qt2_process_read_urb(urb); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci status = usb_submit_urb(urb, GFP_ATOMIC); 57762306a36Sopenharmony_ci if (status != 0) 57862306a36Sopenharmony_ci dev_err(&serial->dev->dev, 57962306a36Sopenharmony_ci "%s - resubmit read urb failed: %i\n", 58062306a36Sopenharmony_ci __func__, status); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic int qt2_setup_urbs(struct usb_serial *serial) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct usb_serial_port *port0; 58662306a36Sopenharmony_ci struct qt2_serial_private *serial_priv; 58762306a36Sopenharmony_ci int status; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci port0 = serial->port[0]; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci serial_priv = usb_get_serial_data(serial); 59262306a36Sopenharmony_ci serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL); 59362306a36Sopenharmony_ci if (!serial_priv->read_urb) 59462306a36Sopenharmony_ci return -ENOMEM; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci usb_fill_bulk_urb(serial_priv->read_urb, serial->dev, 59762306a36Sopenharmony_ci usb_rcvbulkpipe(serial->dev, 59862306a36Sopenharmony_ci port0->bulk_in_endpointAddress), 59962306a36Sopenharmony_ci serial_priv->read_buffer, 60062306a36Sopenharmony_ci QT2_READ_BUFFER_SIZE, 60162306a36Sopenharmony_ci qt2_read_bulk_callback, serial); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL); 60462306a36Sopenharmony_ci if (status != 0) { 60562306a36Sopenharmony_ci dev_err(&serial->dev->dev, 60662306a36Sopenharmony_ci "%s - submit read urb failed %i\n", __func__, status); 60762306a36Sopenharmony_ci usb_free_urb(serial_priv->read_urb); 60862306a36Sopenharmony_ci return status; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return 0; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic int qt2_attach(struct usb_serial *serial) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci struct qt2_serial_private *serial_priv; 61762306a36Sopenharmony_ci int status; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* power on unit */ 62062306a36Sopenharmony_ci status = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 62162306a36Sopenharmony_ci 0xc2, 0x40, 0x8000, 0, NULL, 0, 62262306a36Sopenharmony_ci QT2_USB_TIMEOUT); 62362306a36Sopenharmony_ci if (status < 0) { 62462306a36Sopenharmony_ci dev_err(&serial->dev->dev, 62562306a36Sopenharmony_ci "%s - failed to power on unit: %i\n", __func__, status); 62662306a36Sopenharmony_ci return status; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); 63062306a36Sopenharmony_ci if (!serial_priv) 63162306a36Sopenharmony_ci return -ENOMEM; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL); 63462306a36Sopenharmony_ci if (!serial_priv->read_buffer) { 63562306a36Sopenharmony_ci status = -ENOMEM; 63662306a36Sopenharmony_ci goto err_buf; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci usb_set_serial_data(serial, serial_priv); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci status = qt2_setup_urbs(serial); 64262306a36Sopenharmony_ci if (status != 0) 64362306a36Sopenharmony_ci goto attach_failed; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci return 0; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ciattach_failed: 64862306a36Sopenharmony_ci kfree(serial_priv->read_buffer); 64962306a36Sopenharmony_cierr_buf: 65062306a36Sopenharmony_ci kfree(serial_priv); 65162306a36Sopenharmony_ci return status; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic int qt2_port_probe(struct usb_serial_port *port) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 65762306a36Sopenharmony_ci struct qt2_port_private *port_priv; 65862306a36Sopenharmony_ci u8 bEndpointAddress; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); 66162306a36Sopenharmony_ci if (!port_priv) 66262306a36Sopenharmony_ci return -ENOMEM; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci spin_lock_init(&port_priv->lock); 66562306a36Sopenharmony_ci spin_lock_init(&port_priv->urb_lock); 66662306a36Sopenharmony_ci port_priv->port = port; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci port_priv->write_buffer = kmalloc(QT2_WRITE_BUFFER_SIZE, GFP_KERNEL); 66962306a36Sopenharmony_ci if (!port_priv->write_buffer) 67062306a36Sopenharmony_ci goto err_buf; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL); 67362306a36Sopenharmony_ci if (!port_priv->write_urb) 67462306a36Sopenharmony_ci goto err_urb; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci bEndpointAddress = serial->port[0]->bulk_out_endpointAddress; 67762306a36Sopenharmony_ci usb_fill_bulk_urb(port_priv->write_urb, serial->dev, 67862306a36Sopenharmony_ci usb_sndbulkpipe(serial->dev, bEndpointAddress), 67962306a36Sopenharmony_ci port_priv->write_buffer, 68062306a36Sopenharmony_ci QT2_WRITE_BUFFER_SIZE, 68162306a36Sopenharmony_ci qt2_write_bulk_callback, port); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci usb_set_serial_port_data(port, port_priv); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci return 0; 68662306a36Sopenharmony_cierr_urb: 68762306a36Sopenharmony_ci kfree(port_priv->write_buffer); 68862306a36Sopenharmony_cierr_buf: 68962306a36Sopenharmony_ci kfree(port_priv); 69062306a36Sopenharmony_ci return -ENOMEM; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic void qt2_port_remove(struct usb_serial_port *port) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct qt2_port_private *port_priv; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 69862306a36Sopenharmony_ci usb_free_urb(port_priv->write_urb); 69962306a36Sopenharmony_ci kfree(port_priv->write_buffer); 70062306a36Sopenharmony_ci kfree(port_priv); 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic int qt2_tiocmget(struct tty_struct *tty) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 70662306a36Sopenharmony_ci struct usb_device *dev = port->serial->dev; 70762306a36Sopenharmony_ci struct qt2_port_private *port_priv = usb_get_serial_port_data(port); 70862306a36Sopenharmony_ci u8 *d; 70962306a36Sopenharmony_ci int r; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci d = kzalloc(2, GFP_KERNEL); 71262306a36Sopenharmony_ci if (!d) 71362306a36Sopenharmony_ci return -ENOMEM; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci r = qt2_getregister(dev, port_priv->device_port, UART_MCR, d); 71662306a36Sopenharmony_ci if (r < 0) 71762306a36Sopenharmony_ci goto mget_out; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci r = qt2_getregister(dev, port_priv->device_port, UART_MSR, d + 1); 72062306a36Sopenharmony_ci if (r < 0) 72162306a36Sopenharmony_ci goto mget_out; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) | 72462306a36Sopenharmony_ci (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) | 72562306a36Sopenharmony_ci (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) | 72662306a36Sopenharmony_ci (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) | 72762306a36Sopenharmony_ci (d[1] & UART_MSR_RI ? TIOCM_RI : 0) | 72862306a36Sopenharmony_ci (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cimget_out: 73162306a36Sopenharmony_ci kfree(d); 73262306a36Sopenharmony_ci return r; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic int qt2_tiocmset(struct tty_struct *tty, 73662306a36Sopenharmony_ci unsigned int set, unsigned int clear) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci struct qt2_port_private *port_priv; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(tty->driver_data); 74162306a36Sopenharmony_ci return update_mctrl(port_priv, set, clear); 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int qt2_break_ctl(struct tty_struct *tty, int break_state) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 74762306a36Sopenharmony_ci struct qt2_port_private *port_priv; 74862306a36Sopenharmony_ci int status; 74962306a36Sopenharmony_ci u16 val; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci val = (break_state == -1) ? 1 : 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL, 75662306a36Sopenharmony_ci val, port_priv->device_port); 75762306a36Sopenharmony_ci if (status < 0) { 75862306a36Sopenharmony_ci dev_warn(&port->dev, 75962306a36Sopenharmony_ci "%s - failed to send control message: %i\n", __func__, 76062306a36Sopenharmony_ci status); 76162306a36Sopenharmony_ci return status; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci return 0; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic void qt2_dtr_rts(struct usb_serial_port *port, int on) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct usb_device *dev = port->serial->dev; 77262306a36Sopenharmony_ci struct qt2_port_private *port_priv = usb_get_serial_port_data(port); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* Disable flow control */ 77562306a36Sopenharmony_ci if (!on) { 77662306a36Sopenharmony_ci if (qt2_setregister(dev, port_priv->device_port, 77762306a36Sopenharmony_ci UART_MCR, 0) < 0) 77862306a36Sopenharmony_ci dev_warn(&port->dev, "error from flowcontrol urb\n"); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci /* drop RTS and DTR */ 78162306a36Sopenharmony_ci if (on) 78262306a36Sopenharmony_ci update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0); 78362306a36Sopenharmony_ci else 78462306a36Sopenharmony_ci update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci struct qt2_port_private *port_priv; 79062306a36Sopenharmony_ci u8 newMSR = (u8) *ch; 79162306a36Sopenharmony_ci unsigned long flags; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* May be called from qt2_process_read_urb() for an unbound port. */ 79462306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 79562306a36Sopenharmony_ci if (!port_priv) 79662306a36Sopenharmony_ci return; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci spin_lock_irqsave(&port_priv->lock, flags); 79962306a36Sopenharmony_ci port_priv->shadowMSR = newMSR; 80062306a36Sopenharmony_ci spin_unlock_irqrestore(&port_priv->lock, flags); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (newMSR & UART_MSR_ANY_DELTA) { 80362306a36Sopenharmony_ci /* update input line counters */ 80462306a36Sopenharmony_ci if (newMSR & UART_MSR_DCTS) 80562306a36Sopenharmony_ci port->icount.cts++; 80662306a36Sopenharmony_ci if (newMSR & UART_MSR_DDSR) 80762306a36Sopenharmony_ci port->icount.dsr++; 80862306a36Sopenharmony_ci if (newMSR & UART_MSR_DDCD) 80962306a36Sopenharmony_ci port->icount.dcd++; 81062306a36Sopenharmony_ci if (newMSR & UART_MSR_TERI) 81162306a36Sopenharmony_ci port->icount.rng++; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci wake_up_interruptible(&port->port.delta_msr_wait); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct qt2_port_private *port_priv; 82062306a36Sopenharmony_ci struct async_icount *icount; 82162306a36Sopenharmony_ci unsigned long flags; 82262306a36Sopenharmony_ci u8 newLSR = (u8) *ch; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* May be called from qt2_process_read_urb() for an unbound port. */ 82562306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 82662306a36Sopenharmony_ci if (!port_priv) 82762306a36Sopenharmony_ci return; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (newLSR & UART_LSR_BI) 83062306a36Sopenharmony_ci newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci spin_lock_irqsave(&port_priv->lock, flags); 83362306a36Sopenharmony_ci port_priv->shadowLSR = newLSR; 83462306a36Sopenharmony_ci spin_unlock_irqrestore(&port_priv->lock, flags); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci icount = &port->icount; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (newLSR & UART_LSR_BRK_ERROR_BITS) { 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (newLSR & UART_LSR_BI) 84162306a36Sopenharmony_ci icount->brk++; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (newLSR & UART_LSR_OE) 84462306a36Sopenharmony_ci icount->overrun++; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (newLSR & UART_LSR_PE) 84762306a36Sopenharmony_ci icount->parity++; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (newLSR & UART_LSR_FE) 85062306a36Sopenharmony_ci icount->frame++; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic unsigned int qt2_write_room(struct tty_struct *tty) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 85862306a36Sopenharmony_ci struct qt2_port_private *port_priv; 85962306a36Sopenharmony_ci unsigned long flags; 86062306a36Sopenharmony_ci unsigned int r; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci spin_lock_irqsave(&port_priv->urb_lock, flags); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (port_priv->urb_in_use) 86762306a36Sopenharmony_ci r = 0; 86862306a36Sopenharmony_ci else 86962306a36Sopenharmony_ci r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci spin_unlock_irqrestore(&port_priv->urb_lock, flags); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci return r; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic int qt2_write(struct tty_struct *tty, 87762306a36Sopenharmony_ci struct usb_serial_port *port, 87862306a36Sopenharmony_ci const unsigned char *buf, int count) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci struct qt2_port_private *port_priv; 88162306a36Sopenharmony_ci struct urb *write_urb; 88262306a36Sopenharmony_ci unsigned char *data; 88362306a36Sopenharmony_ci unsigned long flags; 88462306a36Sopenharmony_ci int status; 88562306a36Sopenharmony_ci int bytes_out = 0; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (port_priv->write_urb == NULL) { 89062306a36Sopenharmony_ci dev_err(&port->dev, "%s - no output urb\n", __func__); 89162306a36Sopenharmony_ci return 0; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci write_urb = port_priv->write_urb; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci count = min(count, QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci data = write_urb->transfer_buffer; 89862306a36Sopenharmony_ci spin_lock_irqsave(&port_priv->urb_lock, flags); 89962306a36Sopenharmony_ci if (port_priv->urb_in_use) { 90062306a36Sopenharmony_ci dev_err(&port->dev, "qt2_write - urb is in use\n"); 90162306a36Sopenharmony_ci goto write_out; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci *data++ = QT2_CONTROL_BYTE; 90562306a36Sopenharmony_ci *data++ = QT2_CONTROL_BYTE; 90662306a36Sopenharmony_ci *data++ = port_priv->device_port; 90762306a36Sopenharmony_ci put_unaligned_le16(count, data); 90862306a36Sopenharmony_ci data += 2; 90962306a36Sopenharmony_ci memcpy(data, buf, count); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci write_urb->transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci status = usb_submit_urb(write_urb, GFP_ATOMIC); 91462306a36Sopenharmony_ci if (status == 0) { 91562306a36Sopenharmony_ci port_priv->urb_in_use = true; 91662306a36Sopenharmony_ci bytes_out += count; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ciwrite_out: 92062306a36Sopenharmony_ci spin_unlock_irqrestore(&port_priv->urb_lock, flags); 92162306a36Sopenharmony_ci return bytes_out; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic struct usb_serial_driver qt2_device = { 92662306a36Sopenharmony_ci .driver = { 92762306a36Sopenharmony_ci .owner = THIS_MODULE, 92862306a36Sopenharmony_ci .name = "quatech-serial", 92962306a36Sopenharmony_ci }, 93062306a36Sopenharmony_ci .description = DRIVER_DESC, 93162306a36Sopenharmony_ci .id_table = id_table, 93262306a36Sopenharmony_ci .open = qt2_open, 93362306a36Sopenharmony_ci .close = qt2_close, 93462306a36Sopenharmony_ci .write = qt2_write, 93562306a36Sopenharmony_ci .write_room = qt2_write_room, 93662306a36Sopenharmony_ci .calc_num_ports = qt2_calc_num_ports, 93762306a36Sopenharmony_ci .attach = qt2_attach, 93862306a36Sopenharmony_ci .release = qt2_release, 93962306a36Sopenharmony_ci .disconnect = qt2_disconnect, 94062306a36Sopenharmony_ci .port_probe = qt2_port_probe, 94162306a36Sopenharmony_ci .port_remove = qt2_port_remove, 94262306a36Sopenharmony_ci .dtr_rts = qt2_dtr_rts, 94362306a36Sopenharmony_ci .break_ctl = qt2_break_ctl, 94462306a36Sopenharmony_ci .tiocmget = qt2_tiocmget, 94562306a36Sopenharmony_ci .tiocmset = qt2_tiocmset, 94662306a36Sopenharmony_ci .tiocmiwait = usb_serial_generic_tiocmiwait, 94762306a36Sopenharmony_ci .get_icount = usb_serial_generic_get_icount, 94862306a36Sopenharmony_ci .set_termios = qt2_set_termios, 94962306a36Sopenharmony_ci}; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic struct usb_serial_driver *const serial_drivers[] = { 95262306a36Sopenharmony_ci &qt2_device, NULL 95362306a36Sopenharmony_ci}; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 95862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 959