162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TI 3410/5052 USB Serial Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004 Texas Instruments 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This driver is based on the Linux io_ti driver, which is 862306a36Sopenharmony_ci * Copyright (C) 2000-2002 Inside Out Networks 962306a36Sopenharmony_ci * Copyright (C) 2001-2002 Greg Kroah-Hartman 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * For questions or problems with this driver, contact Texas Instruments 1262306a36Sopenharmony_ci * technical support, or Al Borchers <alborchers@steinerpoint.com>, or 1362306a36Sopenharmony_ci * Peter Berger <pberger@brimson.com>. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/errno.h> 1862306a36Sopenharmony_ci#include <linux/firmware.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/tty.h> 2162306a36Sopenharmony_ci#include <linux/tty_driver.h> 2262306a36Sopenharmony_ci#include <linux/tty_flip.h> 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/spinlock.h> 2562306a36Sopenharmony_ci#include <linux/ioctl.h> 2662306a36Sopenharmony_ci#include <linux/serial.h> 2762306a36Sopenharmony_ci#include <linux/kfifo.h> 2862306a36Sopenharmony_ci#include <linux/mutex.h> 2962306a36Sopenharmony_ci#include <linux/uaccess.h> 3062306a36Sopenharmony_ci#include <linux/usb.h> 3162306a36Sopenharmony_ci#include <linux/usb/serial.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Configuration ids */ 3462306a36Sopenharmony_ci#define TI_BOOT_CONFIG 1 3562306a36Sopenharmony_ci#define TI_ACTIVE_CONFIG 2 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Vendor and product ids */ 3862306a36Sopenharmony_ci#define TI_VENDOR_ID 0x0451 3962306a36Sopenharmony_ci#define IBM_VENDOR_ID 0x04b3 4062306a36Sopenharmony_ci#define STARTECH_VENDOR_ID 0x14b0 4162306a36Sopenharmony_ci#define TI_3410_PRODUCT_ID 0x3410 4262306a36Sopenharmony_ci#define IBM_4543_PRODUCT_ID 0x4543 4362306a36Sopenharmony_ci#define IBM_454B_PRODUCT_ID 0x454b 4462306a36Sopenharmony_ci#define IBM_454C_PRODUCT_ID 0x454c 4562306a36Sopenharmony_ci#define TI_3410_EZ430_ID 0xF430 /* TI ez430 development tool */ 4662306a36Sopenharmony_ci#define TI_5052_BOOT_PRODUCT_ID 0x5052 /* no EEPROM, no firmware */ 4762306a36Sopenharmony_ci#define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ 4862306a36Sopenharmony_ci#define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ 4962306a36Sopenharmony_ci#define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */ 5062306a36Sopenharmony_ci#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* Multi-Tech vendor and product ids */ 5362306a36Sopenharmony_ci#define MTS_VENDOR_ID 0x06E0 5462306a36Sopenharmony_ci#define MTS_GSM_NO_FW_PRODUCT_ID 0xF108 5562306a36Sopenharmony_ci#define MTS_CDMA_NO_FW_PRODUCT_ID 0xF109 5662306a36Sopenharmony_ci#define MTS_CDMA_PRODUCT_ID 0xF110 5762306a36Sopenharmony_ci#define MTS_GSM_PRODUCT_ID 0xF111 5862306a36Sopenharmony_ci#define MTS_EDGE_PRODUCT_ID 0xF112 5962306a36Sopenharmony_ci#define MTS_MT9234MU_PRODUCT_ID 0xF114 6062306a36Sopenharmony_ci#define MTS_MT9234ZBA_PRODUCT_ID 0xF115 6162306a36Sopenharmony_ci#define MTS_MT9234ZBAOLD_PRODUCT_ID 0x0319 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Abbott Diabetics vendor and product ids */ 6462306a36Sopenharmony_ci#define ABBOTT_VENDOR_ID 0x1a61 6562306a36Sopenharmony_ci#define ABBOTT_STEREO_PLUG_ID 0x3410 6662306a36Sopenharmony_ci#define ABBOTT_PRODUCT_ID ABBOTT_STEREO_PLUG_ID 6762306a36Sopenharmony_ci#define ABBOTT_STRIP_PORT_ID 0x3420 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Honeywell vendor and product IDs */ 7062306a36Sopenharmony_ci#define HONEYWELL_VENDOR_ID 0x10ac 7162306a36Sopenharmony_ci#define HONEYWELL_HGI80_PRODUCT_ID 0x0102 /* Honeywell HGI80 */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* Moxa UPORT 11x0 vendor and product IDs */ 7462306a36Sopenharmony_ci#define MXU1_VENDOR_ID 0x110a 7562306a36Sopenharmony_ci#define MXU1_1110_PRODUCT_ID 0x1110 7662306a36Sopenharmony_ci#define MXU1_1130_PRODUCT_ID 0x1130 7762306a36Sopenharmony_ci#define MXU1_1150_PRODUCT_ID 0x1150 7862306a36Sopenharmony_ci#define MXU1_1151_PRODUCT_ID 0x1151 7962306a36Sopenharmony_ci#define MXU1_1131_PRODUCT_ID 0x1131 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* Commands */ 8262306a36Sopenharmony_ci#define TI_GET_VERSION 0x01 8362306a36Sopenharmony_ci#define TI_GET_PORT_STATUS 0x02 8462306a36Sopenharmony_ci#define TI_GET_PORT_DEV_INFO 0x03 8562306a36Sopenharmony_ci#define TI_GET_CONFIG 0x04 8662306a36Sopenharmony_ci#define TI_SET_CONFIG 0x05 8762306a36Sopenharmony_ci#define TI_OPEN_PORT 0x06 8862306a36Sopenharmony_ci#define TI_CLOSE_PORT 0x07 8962306a36Sopenharmony_ci#define TI_START_PORT 0x08 9062306a36Sopenharmony_ci#define TI_STOP_PORT 0x09 9162306a36Sopenharmony_ci#define TI_TEST_PORT 0x0A 9262306a36Sopenharmony_ci#define TI_PURGE_PORT 0x0B 9362306a36Sopenharmony_ci#define TI_RESET_EXT_DEVICE 0x0C 9462306a36Sopenharmony_ci#define TI_WRITE_DATA 0x80 9562306a36Sopenharmony_ci#define TI_READ_DATA 0x81 9662306a36Sopenharmony_ci#define TI_REQ_TYPE_CLASS 0x82 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* Module identifiers */ 9962306a36Sopenharmony_ci#define TI_I2C_PORT 0x01 10062306a36Sopenharmony_ci#define TI_IEEE1284_PORT 0x02 10162306a36Sopenharmony_ci#define TI_UART1_PORT 0x03 10262306a36Sopenharmony_ci#define TI_UART2_PORT 0x04 10362306a36Sopenharmony_ci#define TI_RAM_PORT 0x05 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* Modem status */ 10662306a36Sopenharmony_ci#define TI_MSR_DELTA_CTS 0x01 10762306a36Sopenharmony_ci#define TI_MSR_DELTA_DSR 0x02 10862306a36Sopenharmony_ci#define TI_MSR_DELTA_RI 0x04 10962306a36Sopenharmony_ci#define TI_MSR_DELTA_CD 0x08 11062306a36Sopenharmony_ci#define TI_MSR_CTS 0x10 11162306a36Sopenharmony_ci#define TI_MSR_DSR 0x20 11262306a36Sopenharmony_ci#define TI_MSR_RI 0x40 11362306a36Sopenharmony_ci#define TI_MSR_CD 0x80 11462306a36Sopenharmony_ci#define TI_MSR_DELTA_MASK 0x0F 11562306a36Sopenharmony_ci#define TI_MSR_MASK 0xF0 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* Line status */ 11862306a36Sopenharmony_ci#define TI_LSR_OVERRUN_ERROR 0x01 11962306a36Sopenharmony_ci#define TI_LSR_PARITY_ERROR 0x02 12062306a36Sopenharmony_ci#define TI_LSR_FRAMING_ERROR 0x04 12162306a36Sopenharmony_ci#define TI_LSR_BREAK 0x08 12262306a36Sopenharmony_ci#define TI_LSR_ERROR 0x0F 12362306a36Sopenharmony_ci#define TI_LSR_RX_FULL 0x10 12462306a36Sopenharmony_ci#define TI_LSR_TX_EMPTY 0x20 12562306a36Sopenharmony_ci#define TI_LSR_TX_EMPTY_BOTH 0x40 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* Line control */ 12862306a36Sopenharmony_ci#define TI_LCR_BREAK 0x40 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* Modem control */ 13162306a36Sopenharmony_ci#define TI_MCR_LOOP 0x04 13262306a36Sopenharmony_ci#define TI_MCR_DTR 0x10 13362306a36Sopenharmony_ci#define TI_MCR_RTS 0x20 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* Mask settings */ 13662306a36Sopenharmony_ci#define TI_UART_ENABLE_RTS_IN 0x0001 13762306a36Sopenharmony_ci#define TI_UART_DISABLE_RTS 0x0002 13862306a36Sopenharmony_ci#define TI_UART_ENABLE_PARITY_CHECKING 0x0008 13962306a36Sopenharmony_ci#define TI_UART_ENABLE_DSR_OUT 0x0010 14062306a36Sopenharmony_ci#define TI_UART_ENABLE_CTS_OUT 0x0020 14162306a36Sopenharmony_ci#define TI_UART_ENABLE_X_OUT 0x0040 14262306a36Sopenharmony_ci#define TI_UART_ENABLE_XA_OUT 0x0080 14362306a36Sopenharmony_ci#define TI_UART_ENABLE_X_IN 0x0100 14462306a36Sopenharmony_ci#define TI_UART_ENABLE_DTR_IN 0x0800 14562306a36Sopenharmony_ci#define TI_UART_DISABLE_DTR 0x1000 14662306a36Sopenharmony_ci#define TI_UART_ENABLE_MS_INTS 0x2000 14762306a36Sopenharmony_ci#define TI_UART_ENABLE_AUTO_START_DMA 0x4000 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* Parity */ 15062306a36Sopenharmony_ci#define TI_UART_NO_PARITY 0x00 15162306a36Sopenharmony_ci#define TI_UART_ODD_PARITY 0x01 15262306a36Sopenharmony_ci#define TI_UART_EVEN_PARITY 0x02 15362306a36Sopenharmony_ci#define TI_UART_MARK_PARITY 0x03 15462306a36Sopenharmony_ci#define TI_UART_SPACE_PARITY 0x04 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* Stop bits */ 15762306a36Sopenharmony_ci#define TI_UART_1_STOP_BITS 0x00 15862306a36Sopenharmony_ci#define TI_UART_1_5_STOP_BITS 0x01 15962306a36Sopenharmony_ci#define TI_UART_2_STOP_BITS 0x02 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* Bits per character */ 16262306a36Sopenharmony_ci#define TI_UART_5_DATA_BITS 0x00 16362306a36Sopenharmony_ci#define TI_UART_6_DATA_BITS 0x01 16462306a36Sopenharmony_ci#define TI_UART_7_DATA_BITS 0x02 16562306a36Sopenharmony_ci#define TI_UART_8_DATA_BITS 0x03 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 232/485 modes */ 16862306a36Sopenharmony_ci#define TI_UART_232 0x00 16962306a36Sopenharmony_ci#define TI_UART_485_RECEIVER_DISABLED 0x01 17062306a36Sopenharmony_ci#define TI_UART_485_RECEIVER_ENABLED 0x02 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* Pipe transfer mode and timeout */ 17362306a36Sopenharmony_ci#define TI_PIPE_MODE_CONTINUOUS 0x01 17462306a36Sopenharmony_ci#define TI_PIPE_MODE_MASK 0x03 17562306a36Sopenharmony_ci#define TI_PIPE_TIMEOUT_MASK 0x7C 17662306a36Sopenharmony_ci#define TI_PIPE_TIMEOUT_ENABLE 0x80 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* Config struct */ 17962306a36Sopenharmony_cistruct ti_uart_config { 18062306a36Sopenharmony_ci __be16 wBaudRate; 18162306a36Sopenharmony_ci __be16 wFlags; 18262306a36Sopenharmony_ci u8 bDataBits; 18362306a36Sopenharmony_ci u8 bParity; 18462306a36Sopenharmony_ci u8 bStopBits; 18562306a36Sopenharmony_ci char cXon; 18662306a36Sopenharmony_ci char cXoff; 18762306a36Sopenharmony_ci u8 bUartMode; 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* Get port status */ 19162306a36Sopenharmony_cistruct ti_port_status { 19262306a36Sopenharmony_ci u8 bCmdCode; 19362306a36Sopenharmony_ci u8 bModuleId; 19462306a36Sopenharmony_ci u8 bErrorCode; 19562306a36Sopenharmony_ci u8 bMSR; 19662306a36Sopenharmony_ci u8 bLSR; 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* Purge modes */ 20062306a36Sopenharmony_ci#define TI_PURGE_OUTPUT 0x00 20162306a36Sopenharmony_ci#define TI_PURGE_INPUT 0x80 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* Read/Write data */ 20462306a36Sopenharmony_ci#define TI_RW_DATA_ADDR_SFR 0x10 20562306a36Sopenharmony_ci#define TI_RW_DATA_ADDR_IDATA 0x20 20662306a36Sopenharmony_ci#define TI_RW_DATA_ADDR_XDATA 0x30 20762306a36Sopenharmony_ci#define TI_RW_DATA_ADDR_CODE 0x40 20862306a36Sopenharmony_ci#define TI_RW_DATA_ADDR_GPIO 0x50 20962306a36Sopenharmony_ci#define TI_RW_DATA_ADDR_I2C 0x60 21062306a36Sopenharmony_ci#define TI_RW_DATA_ADDR_FLASH 0x70 21162306a36Sopenharmony_ci#define TI_RW_DATA_ADDR_DSP 0x80 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci#define TI_RW_DATA_UNSPECIFIED 0x00 21462306a36Sopenharmony_ci#define TI_RW_DATA_BYTE 0x01 21562306a36Sopenharmony_ci#define TI_RW_DATA_WORD 0x02 21662306a36Sopenharmony_ci#define TI_RW_DATA_DOUBLE_WORD 0x04 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistruct ti_write_data_bytes { 21962306a36Sopenharmony_ci u8 bAddrType; 22062306a36Sopenharmony_ci u8 bDataType; 22162306a36Sopenharmony_ci u8 bDataCounter; 22262306a36Sopenharmony_ci __be16 wBaseAddrHi; 22362306a36Sopenharmony_ci __be16 wBaseAddrLo; 22462306a36Sopenharmony_ci u8 bData[]; 22562306a36Sopenharmony_ci} __packed; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistruct ti_read_data_request { 22862306a36Sopenharmony_ci u8 bAddrType; 22962306a36Sopenharmony_ci u8 bDataType; 23062306a36Sopenharmony_ci u8 bDataCounter; 23162306a36Sopenharmony_ci __be16 wBaseAddrHi; 23262306a36Sopenharmony_ci __be16 wBaseAddrLo; 23362306a36Sopenharmony_ci} __packed; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistruct ti_read_data_bytes { 23662306a36Sopenharmony_ci u8 bCmdCode; 23762306a36Sopenharmony_ci u8 bModuleId; 23862306a36Sopenharmony_ci u8 bErrorCode; 23962306a36Sopenharmony_ci u8 bData[]; 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* Interrupt struct */ 24362306a36Sopenharmony_cistruct ti_interrupt { 24462306a36Sopenharmony_ci u8 bICode; 24562306a36Sopenharmony_ci u8 bIInfo; 24662306a36Sopenharmony_ci}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/* Interrupt codes */ 24962306a36Sopenharmony_ci#define TI_CODE_HARDWARE_ERROR 0xFF 25062306a36Sopenharmony_ci#define TI_CODE_DATA_ERROR 0x03 25162306a36Sopenharmony_ci#define TI_CODE_MODEM_STATUS 0x04 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/* Download firmware max packet size */ 25462306a36Sopenharmony_ci#define TI_DOWNLOAD_MAX_PACKET_SIZE 64 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* Firmware image header */ 25762306a36Sopenharmony_cistruct ti_firmware_header { 25862306a36Sopenharmony_ci __le16 wLength; 25962306a36Sopenharmony_ci u8 bCheckSum; 26062306a36Sopenharmony_ci} __packed; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* UART addresses */ 26362306a36Sopenharmony_ci#define TI_UART1_BASE_ADDR 0xFFA0 /* UART 1 base address */ 26462306a36Sopenharmony_ci#define TI_UART2_BASE_ADDR 0xFFB0 /* UART 2 base address */ 26562306a36Sopenharmony_ci#define TI_UART_OFFSET_LCR 0x0002 /* UART MCR register offset */ 26662306a36Sopenharmony_ci#define TI_UART_OFFSET_MCR 0x0004 /* UART MCR register offset */ 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci#define TI_DRIVER_AUTHOR "Al Borchers <alborchers@steinerpoint.com>" 26962306a36Sopenharmony_ci#define TI_DRIVER_DESC "TI USB 3410/5052 Serial Driver" 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci#define TI_FIRMWARE_BUF_SIZE 16284 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci#define TI_TRANSFER_TIMEOUT 2 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* read urb states */ 27662306a36Sopenharmony_ci#define TI_READ_URB_RUNNING 0 27762306a36Sopenharmony_ci#define TI_READ_URB_STOPPING 1 27862306a36Sopenharmony_ci#define TI_READ_URB_STOPPED 2 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci#define TI_EXTRA_VID_PID_COUNT 5 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistruct ti_port { 28362306a36Sopenharmony_ci int tp_is_open; 28462306a36Sopenharmony_ci u8 tp_msr; 28562306a36Sopenharmony_ci u8 tp_shadow_mcr; 28662306a36Sopenharmony_ci u8 tp_uart_mode; /* 232 or 485 modes */ 28762306a36Sopenharmony_ci unsigned int tp_uart_base_addr; 28862306a36Sopenharmony_ci struct ti_device *tp_tdev; 28962306a36Sopenharmony_ci struct usb_serial_port *tp_port; 29062306a36Sopenharmony_ci spinlock_t tp_lock; 29162306a36Sopenharmony_ci int tp_read_urb_state; 29262306a36Sopenharmony_ci int tp_write_urb_in_use; 29362306a36Sopenharmony_ci}; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistruct ti_device { 29662306a36Sopenharmony_ci struct mutex td_open_close_lock; 29762306a36Sopenharmony_ci int td_open_port_count; 29862306a36Sopenharmony_ci struct usb_serial *td_serial; 29962306a36Sopenharmony_ci int td_is_3410; 30062306a36Sopenharmony_ci bool td_rs485_only; 30162306a36Sopenharmony_ci}; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int ti_startup(struct usb_serial *serial); 30462306a36Sopenharmony_cistatic void ti_release(struct usb_serial *serial); 30562306a36Sopenharmony_cistatic int ti_port_probe(struct usb_serial_port *port); 30662306a36Sopenharmony_cistatic void ti_port_remove(struct usb_serial_port *port); 30762306a36Sopenharmony_cistatic int ti_open(struct tty_struct *tty, struct usb_serial_port *port); 30862306a36Sopenharmony_cistatic void ti_close(struct usb_serial_port *port); 30962306a36Sopenharmony_cistatic int ti_write(struct tty_struct *tty, struct usb_serial_port *port, 31062306a36Sopenharmony_ci const unsigned char *data, int count); 31162306a36Sopenharmony_cistatic unsigned int ti_write_room(struct tty_struct *tty); 31262306a36Sopenharmony_cistatic unsigned int ti_chars_in_buffer(struct tty_struct *tty); 31362306a36Sopenharmony_cistatic bool ti_tx_empty(struct usb_serial_port *port); 31462306a36Sopenharmony_cistatic void ti_throttle(struct tty_struct *tty); 31562306a36Sopenharmony_cistatic void ti_unthrottle(struct tty_struct *tty); 31662306a36Sopenharmony_cistatic void ti_set_termios(struct tty_struct *tty, 31762306a36Sopenharmony_ci struct usb_serial_port *port, 31862306a36Sopenharmony_ci const struct ktermios *old_termios); 31962306a36Sopenharmony_cistatic int ti_tiocmget(struct tty_struct *tty); 32062306a36Sopenharmony_cistatic int ti_tiocmset(struct tty_struct *tty, 32162306a36Sopenharmony_ci unsigned int set, unsigned int clear); 32262306a36Sopenharmony_cistatic int ti_break(struct tty_struct *tty, int break_state); 32362306a36Sopenharmony_cistatic void ti_interrupt_callback(struct urb *urb); 32462306a36Sopenharmony_cistatic void ti_bulk_in_callback(struct urb *urb); 32562306a36Sopenharmony_cistatic void ti_bulk_out_callback(struct urb *urb); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void ti_recv(struct usb_serial_port *port, unsigned char *data, 32862306a36Sopenharmony_ci int length); 32962306a36Sopenharmony_cistatic void ti_send(struct ti_port *tport); 33062306a36Sopenharmony_cistatic int ti_set_mcr(struct ti_port *tport, unsigned int mcr); 33162306a36Sopenharmony_cistatic int ti_get_lsr(struct ti_port *tport, u8 *lsr); 33262306a36Sopenharmony_cistatic void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss); 33362306a36Sopenharmony_cistatic void ti_handle_new_msr(struct ti_port *tport, u8 msr); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); 33662306a36Sopenharmony_cistatic int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int ti_command_out_sync(struct usb_device *udev, u8 command, 33962306a36Sopenharmony_ci u16 moduleid, u16 value, void *data, int size); 34062306a36Sopenharmony_cistatic int ti_command_in_sync(struct usb_device *udev, u8 command, 34162306a36Sopenharmony_ci u16 moduleid, u16 value, void *data, int size); 34262306a36Sopenharmony_cistatic int ti_port_cmd_out(struct usb_serial_port *port, u8 command, 34362306a36Sopenharmony_ci u16 value, void *data, int size); 34462306a36Sopenharmony_cistatic int ti_port_cmd_in(struct usb_serial_port *port, u8 command, 34562306a36Sopenharmony_ci u16 value, void *data, int size); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, 34862306a36Sopenharmony_ci unsigned long addr, u8 mask, u8 byte); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic int ti_download_firmware(struct ti_device *tdev); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic const struct usb_device_id ti_id_table_3410[] = { 35362306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, 35462306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, 35562306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, 35662306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_NO_FW_PRODUCT_ID) }, 35762306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, 35862306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, 35962306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, 36062306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234MU_PRODUCT_ID) }, 36162306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBA_PRODUCT_ID) }, 36262306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBAOLD_PRODUCT_ID) }, 36362306a36Sopenharmony_ci { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, 36462306a36Sopenharmony_ci { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, 36562306a36Sopenharmony_ci { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, 36662306a36Sopenharmony_ci { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) }, 36762306a36Sopenharmony_ci { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, 36862306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, 36962306a36Sopenharmony_ci { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) }, 37062306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) }, 37162306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) }, 37262306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) }, 37362306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) }, 37462306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) }, 37562306a36Sopenharmony_ci { USB_DEVICE(STARTECH_VENDOR_ID, TI_3410_PRODUCT_ID) }, 37662306a36Sopenharmony_ci { } /* terminator */ 37762306a36Sopenharmony_ci}; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic const struct usb_device_id ti_id_table_5052[] = { 38062306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, 38162306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, 38262306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, 38362306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, 38462306a36Sopenharmony_ci { } 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic const struct usb_device_id ti_id_table_combined[] = { 38862306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, 38962306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, 39062306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, 39162306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_NO_FW_PRODUCT_ID) }, 39262306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, 39362306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, 39462306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, 39562306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234MU_PRODUCT_ID) }, 39662306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBA_PRODUCT_ID) }, 39762306a36Sopenharmony_ci { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBAOLD_PRODUCT_ID) }, 39862306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, 39962306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, 40062306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, 40162306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, 40262306a36Sopenharmony_ci { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, 40362306a36Sopenharmony_ci { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, 40462306a36Sopenharmony_ci { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, 40562306a36Sopenharmony_ci { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, 40662306a36Sopenharmony_ci { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, 40762306a36Sopenharmony_ci { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, 40862306a36Sopenharmony_ci { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) }, 40962306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) }, 41062306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) }, 41162306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) }, 41262306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) }, 41362306a36Sopenharmony_ci { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) }, 41462306a36Sopenharmony_ci { USB_DEVICE(STARTECH_VENDOR_ID, TI_3410_PRODUCT_ID) }, 41562306a36Sopenharmony_ci { } /* terminator */ 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic struct usb_serial_driver ti_1port_device = { 41962306a36Sopenharmony_ci .driver = { 42062306a36Sopenharmony_ci .owner = THIS_MODULE, 42162306a36Sopenharmony_ci .name = "ti_usb_3410_5052_1", 42262306a36Sopenharmony_ci }, 42362306a36Sopenharmony_ci .description = "TI USB 3410 1 port adapter", 42462306a36Sopenharmony_ci .id_table = ti_id_table_3410, 42562306a36Sopenharmony_ci .num_ports = 1, 42662306a36Sopenharmony_ci .num_bulk_out = 1, 42762306a36Sopenharmony_ci .attach = ti_startup, 42862306a36Sopenharmony_ci .release = ti_release, 42962306a36Sopenharmony_ci .port_probe = ti_port_probe, 43062306a36Sopenharmony_ci .port_remove = ti_port_remove, 43162306a36Sopenharmony_ci .open = ti_open, 43262306a36Sopenharmony_ci .close = ti_close, 43362306a36Sopenharmony_ci .write = ti_write, 43462306a36Sopenharmony_ci .write_room = ti_write_room, 43562306a36Sopenharmony_ci .chars_in_buffer = ti_chars_in_buffer, 43662306a36Sopenharmony_ci .tx_empty = ti_tx_empty, 43762306a36Sopenharmony_ci .throttle = ti_throttle, 43862306a36Sopenharmony_ci .unthrottle = ti_unthrottle, 43962306a36Sopenharmony_ci .get_serial = ti_get_serial_info, 44062306a36Sopenharmony_ci .set_termios = ti_set_termios, 44162306a36Sopenharmony_ci .tiocmget = ti_tiocmget, 44262306a36Sopenharmony_ci .tiocmset = ti_tiocmset, 44362306a36Sopenharmony_ci .tiocmiwait = usb_serial_generic_tiocmiwait, 44462306a36Sopenharmony_ci .get_icount = usb_serial_generic_get_icount, 44562306a36Sopenharmony_ci .break_ctl = ti_break, 44662306a36Sopenharmony_ci .read_int_callback = ti_interrupt_callback, 44762306a36Sopenharmony_ci .read_bulk_callback = ti_bulk_in_callback, 44862306a36Sopenharmony_ci .write_bulk_callback = ti_bulk_out_callback, 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic struct usb_serial_driver ti_2port_device = { 45262306a36Sopenharmony_ci .driver = { 45362306a36Sopenharmony_ci .owner = THIS_MODULE, 45462306a36Sopenharmony_ci .name = "ti_usb_3410_5052_2", 45562306a36Sopenharmony_ci }, 45662306a36Sopenharmony_ci .description = "TI USB 5052 2 port adapter", 45762306a36Sopenharmony_ci .id_table = ti_id_table_5052, 45862306a36Sopenharmony_ci .num_ports = 2, 45962306a36Sopenharmony_ci .num_bulk_out = 1, 46062306a36Sopenharmony_ci .attach = ti_startup, 46162306a36Sopenharmony_ci .release = ti_release, 46262306a36Sopenharmony_ci .port_probe = ti_port_probe, 46362306a36Sopenharmony_ci .port_remove = ti_port_remove, 46462306a36Sopenharmony_ci .open = ti_open, 46562306a36Sopenharmony_ci .close = ti_close, 46662306a36Sopenharmony_ci .write = ti_write, 46762306a36Sopenharmony_ci .write_room = ti_write_room, 46862306a36Sopenharmony_ci .chars_in_buffer = ti_chars_in_buffer, 46962306a36Sopenharmony_ci .tx_empty = ti_tx_empty, 47062306a36Sopenharmony_ci .throttle = ti_throttle, 47162306a36Sopenharmony_ci .unthrottle = ti_unthrottle, 47262306a36Sopenharmony_ci .get_serial = ti_get_serial_info, 47362306a36Sopenharmony_ci .set_termios = ti_set_termios, 47462306a36Sopenharmony_ci .tiocmget = ti_tiocmget, 47562306a36Sopenharmony_ci .tiocmset = ti_tiocmset, 47662306a36Sopenharmony_ci .tiocmiwait = usb_serial_generic_tiocmiwait, 47762306a36Sopenharmony_ci .get_icount = usb_serial_generic_get_icount, 47862306a36Sopenharmony_ci .break_ctl = ti_break, 47962306a36Sopenharmony_ci .read_int_callback = ti_interrupt_callback, 48062306a36Sopenharmony_ci .read_bulk_callback = ti_bulk_in_callback, 48162306a36Sopenharmony_ci .write_bulk_callback = ti_bulk_out_callback, 48262306a36Sopenharmony_ci}; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 48562306a36Sopenharmony_ci &ti_1port_device, &ti_2port_device, NULL 48662306a36Sopenharmony_ci}; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ciMODULE_AUTHOR(TI_DRIVER_AUTHOR); 48962306a36Sopenharmony_ciMODULE_DESCRIPTION(TI_DRIVER_DESC); 49062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ciMODULE_FIRMWARE("ti_3410.fw"); 49362306a36Sopenharmony_ciMODULE_FIRMWARE("ti_5052.fw"); 49462306a36Sopenharmony_ciMODULE_FIRMWARE("mts_cdma.fw"); 49562306a36Sopenharmony_ciMODULE_FIRMWARE("mts_gsm.fw"); 49662306a36Sopenharmony_ciMODULE_FIRMWARE("mts_edge.fw"); 49762306a36Sopenharmony_ciMODULE_FIRMWARE("mts_mt9234mu.fw"); 49862306a36Sopenharmony_ciMODULE_FIRMWARE("mts_mt9234zba.fw"); 49962306a36Sopenharmony_ciMODULE_FIRMWARE("moxa/moxa-1110.fw"); 50062306a36Sopenharmony_ciMODULE_FIRMWARE("moxa/moxa-1130.fw"); 50162306a36Sopenharmony_ciMODULE_FIRMWARE("moxa/moxa-1131.fw"); 50262306a36Sopenharmony_ciMODULE_FIRMWARE("moxa/moxa-1150.fw"); 50362306a36Sopenharmony_ciMODULE_FIRMWARE("moxa/moxa-1151.fw"); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, ti_id_table_combined); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, ti_id_table_combined); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int ti_startup(struct usb_serial *serial) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct ti_device *tdev; 51262306a36Sopenharmony_ci struct usb_device *dev = serial->dev; 51362306a36Sopenharmony_ci struct usb_host_interface *cur_altsetting; 51462306a36Sopenharmony_ci int num_endpoints; 51562306a36Sopenharmony_ci u16 vid, pid; 51662306a36Sopenharmony_ci int status; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci dev_dbg(&dev->dev, 51962306a36Sopenharmony_ci "%s - product 0x%4X, num configurations %d, configuration value %d\n", 52062306a36Sopenharmony_ci __func__, le16_to_cpu(dev->descriptor.idProduct), 52162306a36Sopenharmony_ci dev->descriptor.bNumConfigurations, 52262306a36Sopenharmony_ci dev->actconfig->desc.bConfigurationValue); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL); 52562306a36Sopenharmony_ci if (!tdev) 52662306a36Sopenharmony_ci return -ENOMEM; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mutex_init(&tdev->td_open_close_lock); 52962306a36Sopenharmony_ci tdev->td_serial = serial; 53062306a36Sopenharmony_ci usb_set_serial_data(serial, tdev); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* determine device type */ 53362306a36Sopenharmony_ci if (serial->type == &ti_1port_device) 53462306a36Sopenharmony_ci tdev->td_is_3410 = 1; 53562306a36Sopenharmony_ci dev_dbg(&dev->dev, "%s - device type is %s\n", __func__, 53662306a36Sopenharmony_ci tdev->td_is_3410 ? "3410" : "5052"); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci vid = le16_to_cpu(dev->descriptor.idVendor); 53962306a36Sopenharmony_ci pid = le16_to_cpu(dev->descriptor.idProduct); 54062306a36Sopenharmony_ci if (vid == MXU1_VENDOR_ID) { 54162306a36Sopenharmony_ci switch (pid) { 54262306a36Sopenharmony_ci case MXU1_1130_PRODUCT_ID: 54362306a36Sopenharmony_ci case MXU1_1131_PRODUCT_ID: 54462306a36Sopenharmony_ci tdev->td_rs485_only = true; 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci cur_altsetting = serial->interface->cur_altsetting; 55062306a36Sopenharmony_ci num_endpoints = cur_altsetting->desc.bNumEndpoints; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* if we have only 1 configuration and 1 endpoint, download firmware */ 55362306a36Sopenharmony_ci if (dev->descriptor.bNumConfigurations == 1 && num_endpoints == 1) { 55462306a36Sopenharmony_ci status = ti_download_firmware(tdev); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (status != 0) 55762306a36Sopenharmony_ci goto free_tdev; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* 3410 must be reset, 5052 resets itself */ 56062306a36Sopenharmony_ci if (tdev->td_is_3410) { 56162306a36Sopenharmony_ci msleep_interruptible(100); 56262306a36Sopenharmony_ci usb_reset_device(dev); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci status = -ENODEV; 56662306a36Sopenharmony_ci goto free_tdev; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* the second configuration must be set */ 57062306a36Sopenharmony_ci if (dev->actconfig->desc.bConfigurationValue == TI_BOOT_CONFIG) { 57162306a36Sopenharmony_ci status = usb_driver_set_configuration(dev, TI_ACTIVE_CONFIG); 57262306a36Sopenharmony_ci status = status ? status : -ENODEV; 57362306a36Sopenharmony_ci goto free_tdev; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (serial->num_bulk_in < serial->num_ports || 57762306a36Sopenharmony_ci serial->num_bulk_out < serial->num_ports) { 57862306a36Sopenharmony_ci dev_err(&serial->interface->dev, "missing endpoints\n"); 57962306a36Sopenharmony_ci status = -ENODEV; 58062306a36Sopenharmony_ci goto free_tdev; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cifree_tdev: 58662306a36Sopenharmony_ci kfree(tdev); 58762306a36Sopenharmony_ci usb_set_serial_data(serial, NULL); 58862306a36Sopenharmony_ci return status; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic void ti_release(struct usb_serial *serial) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct ti_device *tdev = usb_get_serial_data(serial); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci kfree(tdev); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int ti_port_probe(struct usb_serial_port *port) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct ti_port *tport; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci tport = kzalloc(sizeof(*tport), GFP_KERNEL); 60462306a36Sopenharmony_ci if (!tport) 60562306a36Sopenharmony_ci return -ENOMEM; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci spin_lock_init(&tport->tp_lock); 60862306a36Sopenharmony_ci if (port == port->serial->port[0]) 60962306a36Sopenharmony_ci tport->tp_uart_base_addr = TI_UART1_BASE_ADDR; 61062306a36Sopenharmony_ci else 61162306a36Sopenharmony_ci tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; 61262306a36Sopenharmony_ci tport->tp_port = port; 61362306a36Sopenharmony_ci tport->tp_tdev = usb_get_serial_data(port->serial); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (tport->tp_tdev->td_rs485_only) 61662306a36Sopenharmony_ci tport->tp_uart_mode = TI_UART_485_RECEIVER_DISABLED; 61762306a36Sopenharmony_ci else 61862306a36Sopenharmony_ci tport->tp_uart_mode = TI_UART_232; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci usb_set_serial_port_data(port, tport); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* 62362306a36Sopenharmony_ci * The TUSB5052 LSR does not tell when the transmitter shift register 62462306a36Sopenharmony_ci * has emptied so add a one-character drain delay. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci if (!tport->tp_tdev->td_is_3410) 62762306a36Sopenharmony_ci port->port.drain_delay = 1; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return 0; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic void ti_port_remove(struct usb_serial_port *port) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct ti_port *tport; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci tport = usb_get_serial_port_data(port); 63762306a36Sopenharmony_ci kfree(tport); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int ti_open(struct tty_struct *tty, struct usb_serial_port *port) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 64362306a36Sopenharmony_ci struct ti_device *tdev; 64462306a36Sopenharmony_ci struct usb_device *dev; 64562306a36Sopenharmony_ci struct urb *urb; 64662306a36Sopenharmony_ci int status; 64762306a36Sopenharmony_ci u16 open_settings; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci open_settings = (TI_PIPE_MODE_CONTINUOUS | 65062306a36Sopenharmony_ci TI_PIPE_TIMEOUT_ENABLE | 65162306a36Sopenharmony_ci (TI_TRANSFER_TIMEOUT << 2)); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci dev = port->serial->dev; 65462306a36Sopenharmony_ci tdev = tport->tp_tdev; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* only one open on any port on a device at a time */ 65762306a36Sopenharmony_ci if (mutex_lock_interruptible(&tdev->td_open_close_lock)) 65862306a36Sopenharmony_ci return -ERESTARTSYS; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci tport->tp_msr = 0; 66162306a36Sopenharmony_ci tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* start interrupt urb the first time a port is opened on this device */ 66462306a36Sopenharmony_ci if (tdev->td_open_port_count == 0) { 66562306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - start interrupt in urb\n", __func__); 66662306a36Sopenharmony_ci urb = tdev->td_serial->port[0]->interrupt_in_urb; 66762306a36Sopenharmony_ci if (!urb) { 66862306a36Sopenharmony_ci dev_err(&port->dev, "%s - no interrupt urb\n", __func__); 66962306a36Sopenharmony_ci status = -EINVAL; 67062306a36Sopenharmony_ci goto release_lock; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci urb->context = tdev; 67362306a36Sopenharmony_ci status = usb_submit_urb(urb, GFP_KERNEL); 67462306a36Sopenharmony_ci if (status) { 67562306a36Sopenharmony_ci dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __func__, status); 67662306a36Sopenharmony_ci goto release_lock; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (tty) 68162306a36Sopenharmony_ci ti_set_termios(tty, port, &tty->termios); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci status = ti_port_cmd_out(port, TI_OPEN_PORT, open_settings, NULL, 0); 68462306a36Sopenharmony_ci if (status) { 68562306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot send open command, %d\n", 68662306a36Sopenharmony_ci __func__, status); 68762306a36Sopenharmony_ci goto unlink_int_urb; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci status = ti_port_cmd_out(port, TI_START_PORT, 0, NULL, 0); 69162306a36Sopenharmony_ci if (status) { 69262306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot send start command, %d\n", 69362306a36Sopenharmony_ci __func__, status); 69462306a36Sopenharmony_ci goto unlink_int_urb; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci status = ti_port_cmd_out(port, TI_PURGE_PORT, TI_PURGE_INPUT, NULL, 0); 69862306a36Sopenharmony_ci if (status) { 69962306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot clear input buffers, %d\n", 70062306a36Sopenharmony_ci __func__, status); 70162306a36Sopenharmony_ci goto unlink_int_urb; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci status = ti_port_cmd_out(port, TI_PURGE_PORT, TI_PURGE_OUTPUT, NULL, 0); 70462306a36Sopenharmony_ci if (status) { 70562306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot clear output buffers, %d\n", 70662306a36Sopenharmony_ci __func__, status); 70762306a36Sopenharmony_ci goto unlink_int_urb; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* reset the data toggle on the bulk endpoints to work around bug in 71162306a36Sopenharmony_ci * host controllers where things get out of sync some times */ 71262306a36Sopenharmony_ci usb_clear_halt(dev, port->write_urb->pipe); 71362306a36Sopenharmony_ci usb_clear_halt(dev, port->read_urb->pipe); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (tty) 71662306a36Sopenharmony_ci ti_set_termios(tty, port, &tty->termios); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci status = ti_port_cmd_out(port, TI_OPEN_PORT, open_settings, NULL, 0); 71962306a36Sopenharmony_ci if (status) { 72062306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot send open command (2), %d\n", 72162306a36Sopenharmony_ci __func__, status); 72262306a36Sopenharmony_ci goto unlink_int_urb; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci status = ti_port_cmd_out(port, TI_START_PORT, 0, NULL, 0); 72662306a36Sopenharmony_ci if (status) { 72762306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot send start command (2), %d\n", 72862306a36Sopenharmony_ci __func__, status); 72962306a36Sopenharmony_ci goto unlink_int_urb; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* start read urb */ 73362306a36Sopenharmony_ci urb = port->read_urb; 73462306a36Sopenharmony_ci if (!urb) { 73562306a36Sopenharmony_ci dev_err(&port->dev, "%s - no read urb\n", __func__); 73662306a36Sopenharmony_ci status = -EINVAL; 73762306a36Sopenharmony_ci goto unlink_int_urb; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci tport->tp_read_urb_state = TI_READ_URB_RUNNING; 74062306a36Sopenharmony_ci urb->context = tport; 74162306a36Sopenharmony_ci status = usb_submit_urb(urb, GFP_KERNEL); 74262306a36Sopenharmony_ci if (status) { 74362306a36Sopenharmony_ci dev_err(&port->dev, "%s - submit read urb failed, %d\n", 74462306a36Sopenharmony_ci __func__, status); 74562306a36Sopenharmony_ci goto unlink_int_urb; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci tport->tp_is_open = 1; 74962306a36Sopenharmony_ci ++tdev->td_open_port_count; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci goto release_lock; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ciunlink_int_urb: 75462306a36Sopenharmony_ci if (tdev->td_open_port_count == 0) 75562306a36Sopenharmony_ci usb_kill_urb(port->serial->port[0]->interrupt_in_urb); 75662306a36Sopenharmony_cirelease_lock: 75762306a36Sopenharmony_ci mutex_unlock(&tdev->td_open_close_lock); 75862306a36Sopenharmony_ci return status; 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic void ti_close(struct usb_serial_port *port) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci struct ti_device *tdev; 76562306a36Sopenharmony_ci struct ti_port *tport; 76662306a36Sopenharmony_ci int status; 76762306a36Sopenharmony_ci unsigned long flags; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci tdev = usb_get_serial_data(port->serial); 77062306a36Sopenharmony_ci tport = usb_get_serial_port_data(port); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci tport->tp_is_open = 0; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci usb_kill_urb(port->read_urb); 77562306a36Sopenharmony_ci usb_kill_urb(port->write_urb); 77662306a36Sopenharmony_ci tport->tp_write_urb_in_use = 0; 77762306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 77862306a36Sopenharmony_ci kfifo_reset_out(&port->write_fifo); 77962306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci status = ti_port_cmd_out(port, TI_CLOSE_PORT, 0, NULL, 0); 78262306a36Sopenharmony_ci if (status) 78362306a36Sopenharmony_ci dev_err(&port->dev, 78462306a36Sopenharmony_ci "%s - cannot send close port command, %d\n" 78562306a36Sopenharmony_ci , __func__, status); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci mutex_lock(&tdev->td_open_close_lock); 78862306a36Sopenharmony_ci --tdev->td_open_port_count; 78962306a36Sopenharmony_ci if (tdev->td_open_port_count == 0) { 79062306a36Sopenharmony_ci /* last port is closed, shut down interrupt urb */ 79162306a36Sopenharmony_ci usb_kill_urb(port->serial->port[0]->interrupt_in_urb); 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci mutex_unlock(&tdev->td_open_close_lock); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic int ti_write(struct tty_struct *tty, struct usb_serial_port *port, 79862306a36Sopenharmony_ci const unsigned char *data, int count) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (count == 0) { 80362306a36Sopenharmony_ci return 0; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (!tport->tp_is_open) 80762306a36Sopenharmony_ci return -ENODEV; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci count = kfifo_in_locked(&port->write_fifo, data, count, 81062306a36Sopenharmony_ci &tport->tp_lock); 81162306a36Sopenharmony_ci ti_send(tport); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return count; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic unsigned int ti_write_room(struct tty_struct *tty) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 82062306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 82162306a36Sopenharmony_ci unsigned int room; 82262306a36Sopenharmony_ci unsigned long flags; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 82562306a36Sopenharmony_ci room = kfifo_avail(&port->write_fifo); 82662306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - returns %u\n", __func__, room); 82962306a36Sopenharmony_ci return room; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic unsigned int ti_chars_in_buffer(struct tty_struct *tty) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 83662306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 83762306a36Sopenharmony_ci unsigned int chars; 83862306a36Sopenharmony_ci unsigned long flags; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 84162306a36Sopenharmony_ci chars = kfifo_len(&port->write_fifo); 84262306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars); 84562306a36Sopenharmony_ci return chars; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic bool ti_tx_empty(struct usb_serial_port *port) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 85162306a36Sopenharmony_ci u8 lsr, mask; 85262306a36Sopenharmony_ci int ret; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* 85562306a36Sopenharmony_ci * TUSB5052 does not have the TEMT bit to tell if the shift register 85662306a36Sopenharmony_ci * is empty. 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_ci if (tport->tp_tdev->td_is_3410) 85962306a36Sopenharmony_ci mask = TI_LSR_TX_EMPTY_BOTH; 86062306a36Sopenharmony_ci else 86162306a36Sopenharmony_ci mask = TI_LSR_TX_EMPTY; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci ret = ti_get_lsr(tport, &lsr); 86462306a36Sopenharmony_ci if (!ret && !(lsr & mask)) 86562306a36Sopenharmony_ci return false; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci return true; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic void ti_throttle(struct tty_struct *tty) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 87362306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (I_IXOFF(tty) || C_CRTSCTS(tty)) 87662306a36Sopenharmony_ci ti_stop_read(tport, tty); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic void ti_unthrottle(struct tty_struct *tty) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 88462306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 88562306a36Sopenharmony_ci int status; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (I_IXOFF(tty) || C_CRTSCTS(tty)) { 88862306a36Sopenharmony_ci status = ti_restart_read(tport, tty); 88962306a36Sopenharmony_ci if (status) 89062306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot restart read, %d\n", 89162306a36Sopenharmony_ci __func__, status); 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic void ti_set_termios(struct tty_struct *tty, 89662306a36Sopenharmony_ci struct usb_serial_port *port, 89762306a36Sopenharmony_ci const struct ktermios *old_termios) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 90062306a36Sopenharmony_ci struct ti_uart_config *config; 90162306a36Sopenharmony_ci int baud; 90262306a36Sopenharmony_ci int status; 90362306a36Sopenharmony_ci unsigned int mcr; 90462306a36Sopenharmony_ci u16 wbaudrate; 90562306a36Sopenharmony_ci u16 wflags = 0; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci config = kmalloc(sizeof(*config), GFP_KERNEL); 90862306a36Sopenharmony_ci if (!config) 90962306a36Sopenharmony_ci return; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* these flags must be set */ 91262306a36Sopenharmony_ci wflags |= TI_UART_ENABLE_MS_INTS; 91362306a36Sopenharmony_ci wflags |= TI_UART_ENABLE_AUTO_START_DMA; 91462306a36Sopenharmony_ci config->bUartMode = tport->tp_uart_mode; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci switch (C_CSIZE(tty)) { 91762306a36Sopenharmony_ci case CS5: 91862306a36Sopenharmony_ci config->bDataBits = TI_UART_5_DATA_BITS; 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci case CS6: 92162306a36Sopenharmony_ci config->bDataBits = TI_UART_6_DATA_BITS; 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci case CS7: 92462306a36Sopenharmony_ci config->bDataBits = TI_UART_7_DATA_BITS; 92562306a36Sopenharmony_ci break; 92662306a36Sopenharmony_ci default: 92762306a36Sopenharmony_ci case CS8: 92862306a36Sopenharmony_ci config->bDataBits = TI_UART_8_DATA_BITS; 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci /* CMSPAR isn't supported by this driver */ 93362306a36Sopenharmony_ci tty->termios.c_cflag &= ~CMSPAR; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (C_PARENB(tty)) { 93662306a36Sopenharmony_ci if (C_PARODD(tty)) { 93762306a36Sopenharmony_ci wflags |= TI_UART_ENABLE_PARITY_CHECKING; 93862306a36Sopenharmony_ci config->bParity = TI_UART_ODD_PARITY; 93962306a36Sopenharmony_ci } else { 94062306a36Sopenharmony_ci wflags |= TI_UART_ENABLE_PARITY_CHECKING; 94162306a36Sopenharmony_ci config->bParity = TI_UART_EVEN_PARITY; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci } else { 94462306a36Sopenharmony_ci wflags &= ~TI_UART_ENABLE_PARITY_CHECKING; 94562306a36Sopenharmony_ci config->bParity = TI_UART_NO_PARITY; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (C_CSTOPB(tty)) 94962306a36Sopenharmony_ci config->bStopBits = TI_UART_2_STOP_BITS; 95062306a36Sopenharmony_ci else 95162306a36Sopenharmony_ci config->bStopBits = TI_UART_1_STOP_BITS; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (C_CRTSCTS(tty)) { 95462306a36Sopenharmony_ci /* RTS flow control must be off to drop RTS for baud rate B0 */ 95562306a36Sopenharmony_ci if ((C_BAUD(tty)) != B0) 95662306a36Sopenharmony_ci wflags |= TI_UART_ENABLE_RTS_IN; 95762306a36Sopenharmony_ci wflags |= TI_UART_ENABLE_CTS_OUT; 95862306a36Sopenharmony_ci } else { 95962306a36Sopenharmony_ci ti_restart_read(tport, tty); 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (I_IXOFF(tty) || I_IXON(tty)) { 96362306a36Sopenharmony_ci config->cXon = START_CHAR(tty); 96462306a36Sopenharmony_ci config->cXoff = STOP_CHAR(tty); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (I_IXOFF(tty)) 96762306a36Sopenharmony_ci wflags |= TI_UART_ENABLE_X_IN; 96862306a36Sopenharmony_ci else 96962306a36Sopenharmony_ci ti_restart_read(tport, tty); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (I_IXON(tty)) 97262306a36Sopenharmony_ci wflags |= TI_UART_ENABLE_X_OUT; 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci baud = tty_get_baud_rate(tty); 97662306a36Sopenharmony_ci if (!baud) 97762306a36Sopenharmony_ci baud = 9600; 97862306a36Sopenharmony_ci if (tport->tp_tdev->td_is_3410) 97962306a36Sopenharmony_ci wbaudrate = (923077 + baud/2) / baud; 98062306a36Sopenharmony_ci else 98162306a36Sopenharmony_ci wbaudrate = (461538 + baud/2) / baud; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* FIXME: Should calculate resulting baud here and report it back */ 98462306a36Sopenharmony_ci if ((C_BAUD(tty)) != B0) 98562306a36Sopenharmony_ci tty_encode_baud_rate(tty, baud, baud); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci dev_dbg(&port->dev, 98862306a36Sopenharmony_ci "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n", 98962306a36Sopenharmony_ci __func__, baud, wbaudrate, wflags, 99062306a36Sopenharmony_ci config->bDataBits, config->bParity, config->bStopBits, 99162306a36Sopenharmony_ci config->cXon, config->cXoff, config->bUartMode); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci config->wBaudRate = cpu_to_be16(wbaudrate); 99462306a36Sopenharmony_ci config->wFlags = cpu_to_be16(wflags); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci status = ti_port_cmd_out(port, TI_SET_CONFIG, 0, config, 99762306a36Sopenharmony_ci sizeof(*config)); 99862306a36Sopenharmony_ci if (status) 99962306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot set config on port %d, %d\n", 100062306a36Sopenharmony_ci __func__, port->port_number, status); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci /* SET_CONFIG asserts RTS and DTR, reset them correctly */ 100362306a36Sopenharmony_ci mcr = tport->tp_shadow_mcr; 100462306a36Sopenharmony_ci /* if baud rate is B0, clear RTS and DTR */ 100562306a36Sopenharmony_ci if (C_BAUD(tty) == B0) 100662306a36Sopenharmony_ci mcr &= ~(TI_MCR_DTR | TI_MCR_RTS); 100762306a36Sopenharmony_ci status = ti_set_mcr(tport, mcr); 100862306a36Sopenharmony_ci if (status) 100962306a36Sopenharmony_ci dev_err(&port->dev, "%s - cannot set modem control on port %d, %d\n", 101062306a36Sopenharmony_ci __func__, port->port_number, status); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci kfree(config); 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic int ti_tiocmget(struct tty_struct *tty) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 101962306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 102062306a36Sopenharmony_ci unsigned int result; 102162306a36Sopenharmony_ci unsigned int msr; 102262306a36Sopenharmony_ci unsigned int mcr; 102362306a36Sopenharmony_ci unsigned long flags; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 102662306a36Sopenharmony_ci msr = tport->tp_msr; 102762306a36Sopenharmony_ci mcr = tport->tp_shadow_mcr; 102862306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci result = ((mcr & TI_MCR_DTR) ? TIOCM_DTR : 0) 103162306a36Sopenharmony_ci | ((mcr & TI_MCR_RTS) ? TIOCM_RTS : 0) 103262306a36Sopenharmony_ci | ((mcr & TI_MCR_LOOP) ? TIOCM_LOOP : 0) 103362306a36Sopenharmony_ci | ((msr & TI_MSR_CTS) ? TIOCM_CTS : 0) 103462306a36Sopenharmony_ci | ((msr & TI_MSR_CD) ? TIOCM_CAR : 0) 103562306a36Sopenharmony_ci | ((msr & TI_MSR_RI) ? TIOCM_RI : 0) 103662306a36Sopenharmony_ci | ((msr & TI_MSR_DSR) ? TIOCM_DSR : 0); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci return result; 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistatic int ti_tiocmset(struct tty_struct *tty, 104562306a36Sopenharmony_ci unsigned int set, unsigned int clear) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 104862306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 104962306a36Sopenharmony_ci unsigned int mcr; 105062306a36Sopenharmony_ci unsigned long flags; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 105362306a36Sopenharmony_ci mcr = tport->tp_shadow_mcr; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (set & TIOCM_RTS) 105662306a36Sopenharmony_ci mcr |= TI_MCR_RTS; 105762306a36Sopenharmony_ci if (set & TIOCM_DTR) 105862306a36Sopenharmony_ci mcr |= TI_MCR_DTR; 105962306a36Sopenharmony_ci if (set & TIOCM_LOOP) 106062306a36Sopenharmony_ci mcr |= TI_MCR_LOOP; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (clear & TIOCM_RTS) 106362306a36Sopenharmony_ci mcr &= ~TI_MCR_RTS; 106462306a36Sopenharmony_ci if (clear & TIOCM_DTR) 106562306a36Sopenharmony_ci mcr &= ~TI_MCR_DTR; 106662306a36Sopenharmony_ci if (clear & TIOCM_LOOP) 106762306a36Sopenharmony_ci mcr &= ~TI_MCR_LOOP; 106862306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci return ti_set_mcr(tport, mcr); 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic int ti_break(struct tty_struct *tty, int break_state) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 107762306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 107862306a36Sopenharmony_ci int status; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - state = %d\n", __func__, break_state); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci status = ti_write_byte(port, tport->tp_tdev, 108362306a36Sopenharmony_ci tport->tp_uart_base_addr + TI_UART_OFFSET_LCR, 108462306a36Sopenharmony_ci TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (status) { 108762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - error setting break, %d\n", __func__, status); 108862306a36Sopenharmony_ci return status; 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci return 0; 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistatic int ti_get_port_from_code(unsigned char code) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci return (code >> 6) & 0x01; 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic int ti_get_func_from_code(unsigned char code) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci return code & 0x0f; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic void ti_interrupt_callback(struct urb *urb) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci struct ti_device *tdev = urb->context; 110762306a36Sopenharmony_ci struct usb_serial_port *port; 110862306a36Sopenharmony_ci struct usb_serial *serial = tdev->td_serial; 110962306a36Sopenharmony_ci struct ti_port *tport; 111062306a36Sopenharmony_ci struct device *dev = &urb->dev->dev; 111162306a36Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 111262306a36Sopenharmony_ci int length = urb->actual_length; 111362306a36Sopenharmony_ci int port_number; 111462306a36Sopenharmony_ci int function; 111562306a36Sopenharmony_ci int status = urb->status; 111662306a36Sopenharmony_ci int retval; 111762306a36Sopenharmony_ci u8 msr; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci switch (status) { 112062306a36Sopenharmony_ci case 0: 112162306a36Sopenharmony_ci break; 112262306a36Sopenharmony_ci case -ECONNRESET: 112362306a36Sopenharmony_ci case -ENOENT: 112462306a36Sopenharmony_ci case -ESHUTDOWN: 112562306a36Sopenharmony_ci dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); 112662306a36Sopenharmony_ci return; 112762306a36Sopenharmony_ci default: 112862306a36Sopenharmony_ci dev_err(dev, "%s - nonzero urb status, %d\n", __func__, status); 112962306a36Sopenharmony_ci goto exit; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (length != 2) { 113362306a36Sopenharmony_ci dev_dbg(dev, "%s - bad packet size, %d\n", __func__, length); 113462306a36Sopenharmony_ci goto exit; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (data[0] == TI_CODE_HARDWARE_ERROR) { 113862306a36Sopenharmony_ci dev_err(dev, "%s - hardware error, %d\n", __func__, data[1]); 113962306a36Sopenharmony_ci goto exit; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci port_number = ti_get_port_from_code(data[0]); 114362306a36Sopenharmony_ci function = ti_get_func_from_code(data[0]); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci dev_dbg(dev, "%s - port_number %d, function %d, data 0x%02X\n", 114662306a36Sopenharmony_ci __func__, port_number, function, data[1]); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (port_number >= serial->num_ports) { 114962306a36Sopenharmony_ci dev_err(dev, "%s - bad port number, %d\n", 115062306a36Sopenharmony_ci __func__, port_number); 115162306a36Sopenharmony_ci goto exit; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci port = serial->port[port_number]; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci tport = usb_get_serial_port_data(port); 115762306a36Sopenharmony_ci if (!tport) 115862306a36Sopenharmony_ci goto exit; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci switch (function) { 116162306a36Sopenharmony_ci case TI_CODE_DATA_ERROR: 116262306a36Sopenharmony_ci dev_err(dev, "%s - DATA ERROR, port %d, data 0x%02X\n", 116362306a36Sopenharmony_ci __func__, port_number, data[1]); 116462306a36Sopenharmony_ci break; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci case TI_CODE_MODEM_STATUS: 116762306a36Sopenharmony_ci msr = data[1]; 116862306a36Sopenharmony_ci dev_dbg(dev, "%s - port %d, msr 0x%02X\n", __func__, port_number, msr); 116962306a36Sopenharmony_ci ti_handle_new_msr(tport, msr); 117062306a36Sopenharmony_ci break; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci default: 117362306a36Sopenharmony_ci dev_err(dev, "%s - unknown interrupt code, 0x%02X\n", 117462306a36Sopenharmony_ci __func__, data[1]); 117562306a36Sopenharmony_ci break; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ciexit: 117962306a36Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 118062306a36Sopenharmony_ci if (retval) 118162306a36Sopenharmony_ci dev_err(dev, "%s - resubmit interrupt urb failed, %d\n", 118262306a36Sopenharmony_ci __func__, retval); 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_cistatic void ti_bulk_in_callback(struct urb *urb) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci struct ti_port *tport = urb->context; 118962306a36Sopenharmony_ci struct usb_serial_port *port = tport->tp_port; 119062306a36Sopenharmony_ci struct device *dev = &urb->dev->dev; 119162306a36Sopenharmony_ci int status = urb->status; 119262306a36Sopenharmony_ci unsigned long flags; 119362306a36Sopenharmony_ci int retval = 0; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci switch (status) { 119662306a36Sopenharmony_ci case 0: 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci case -ECONNRESET: 119962306a36Sopenharmony_ci case -ENOENT: 120062306a36Sopenharmony_ci case -ESHUTDOWN: 120162306a36Sopenharmony_ci dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); 120262306a36Sopenharmony_ci return; 120362306a36Sopenharmony_ci default: 120462306a36Sopenharmony_ci dev_err(dev, "%s - nonzero urb status, %d\n", 120562306a36Sopenharmony_ci __func__, status); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (status == -EPIPE) 120962306a36Sopenharmony_ci goto exit; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (status) { 121262306a36Sopenharmony_ci dev_err(dev, "%s - stopping read!\n", __func__); 121362306a36Sopenharmony_ci return; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (urb->actual_length) { 121762306a36Sopenharmony_ci usb_serial_debug_data(dev, __func__, urb->actual_length, 121862306a36Sopenharmony_ci urb->transfer_buffer); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (!tport->tp_is_open) 122162306a36Sopenharmony_ci dev_dbg(dev, "%s - port closed, dropping data\n", 122262306a36Sopenharmony_ci __func__); 122362306a36Sopenharmony_ci else 122462306a36Sopenharmony_ci ti_recv(port, urb->transfer_buffer, urb->actual_length); 122562306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 122662306a36Sopenharmony_ci port->icount.rx += urb->actual_length; 122762306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ciexit: 123162306a36Sopenharmony_ci /* continue to read unless stopping */ 123262306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 123362306a36Sopenharmony_ci if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) 123462306a36Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 123562306a36Sopenharmony_ci else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) 123662306a36Sopenharmony_ci tport->tp_read_urb_state = TI_READ_URB_STOPPED; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 123962306a36Sopenharmony_ci if (retval) 124062306a36Sopenharmony_ci dev_err(dev, "%s - resubmit read urb failed, %d\n", 124162306a36Sopenharmony_ci __func__, retval); 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_cistatic void ti_bulk_out_callback(struct urb *urb) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci struct ti_port *tport = urb->context; 124862306a36Sopenharmony_ci struct usb_serial_port *port = tport->tp_port; 124962306a36Sopenharmony_ci int status = urb->status; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci tport->tp_write_urb_in_use = 0; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci switch (status) { 125462306a36Sopenharmony_ci case 0: 125562306a36Sopenharmony_ci break; 125662306a36Sopenharmony_ci case -ECONNRESET: 125762306a36Sopenharmony_ci case -ENOENT: 125862306a36Sopenharmony_ci case -ESHUTDOWN: 125962306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status); 126062306a36Sopenharmony_ci return; 126162306a36Sopenharmony_ci default: 126262306a36Sopenharmony_ci dev_err_console(port, "%s - nonzero urb status, %d\n", 126362306a36Sopenharmony_ci __func__, status); 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* send any buffered data */ 126762306a36Sopenharmony_ci ti_send(tport); 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_cistatic void ti_recv(struct usb_serial_port *port, unsigned char *data, 127262306a36Sopenharmony_ci int length) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci int cnt; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci do { 127762306a36Sopenharmony_ci cnt = tty_insert_flip_string(&port->port, data, length); 127862306a36Sopenharmony_ci if (cnt < length) { 127962306a36Sopenharmony_ci dev_err(&port->dev, "%s - dropping data, %d bytes lost\n", 128062306a36Sopenharmony_ci __func__, length - cnt); 128162306a36Sopenharmony_ci if (cnt == 0) 128262306a36Sopenharmony_ci break; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci tty_flip_buffer_push(&port->port); 128562306a36Sopenharmony_ci data += cnt; 128662306a36Sopenharmony_ci length -= cnt; 128762306a36Sopenharmony_ci } while (length > 0); 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_cistatic void ti_send(struct ti_port *tport) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci int count, result; 129462306a36Sopenharmony_ci struct usb_serial_port *port = tport->tp_port; 129562306a36Sopenharmony_ci unsigned long flags; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci if (tport->tp_write_urb_in_use) 130062306a36Sopenharmony_ci goto unlock; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci count = kfifo_out(&port->write_fifo, 130362306a36Sopenharmony_ci port->write_urb->transfer_buffer, 130462306a36Sopenharmony_ci port->bulk_out_size); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (count == 0) 130762306a36Sopenharmony_ci goto unlock; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci tport->tp_write_urb_in_use = 1; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, count, 131462306a36Sopenharmony_ci port->write_urb->transfer_buffer); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urb, port->serial->dev, 131762306a36Sopenharmony_ci usb_sndbulkpipe(port->serial->dev, 131862306a36Sopenharmony_ci port->bulk_out_endpointAddress), 131962306a36Sopenharmony_ci port->write_urb->transfer_buffer, count, 132062306a36Sopenharmony_ci ti_bulk_out_callback, tport); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 132362306a36Sopenharmony_ci if (result) { 132462306a36Sopenharmony_ci dev_err_console(port, "%s - submit write urb failed, %d\n", 132562306a36Sopenharmony_ci __func__, result); 132662306a36Sopenharmony_ci tport->tp_write_urb_in_use = 0; 132762306a36Sopenharmony_ci /* TODO: reschedule ti_send */ 132862306a36Sopenharmony_ci } else { 132962306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 133062306a36Sopenharmony_ci port->icount.tx += count; 133162306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci /* more room in the buffer for new writes, wakeup */ 133562306a36Sopenharmony_ci tty_port_tty_wakeup(&port->port); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci return; 133862306a36Sopenharmony_ciunlock: 133962306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 134062306a36Sopenharmony_ci return; 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic int ti_set_mcr(struct ti_port *tport, unsigned int mcr) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci unsigned long flags; 134762306a36Sopenharmony_ci int status; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci status = ti_write_byte(tport->tp_port, tport->tp_tdev, 135062306a36Sopenharmony_ci tport->tp_uart_base_addr + TI_UART_OFFSET_MCR, 135162306a36Sopenharmony_ci TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 135462306a36Sopenharmony_ci if (!status) 135562306a36Sopenharmony_ci tport->tp_shadow_mcr = mcr; 135662306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci return status; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_cistatic int ti_get_lsr(struct ti_port *tport, u8 *lsr) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci int size, status; 136562306a36Sopenharmony_ci struct usb_serial_port *port = tport->tp_port; 136662306a36Sopenharmony_ci struct ti_port_status *data; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci size = sizeof(struct ti_port_status); 136962306a36Sopenharmony_ci data = kmalloc(size, GFP_KERNEL); 137062306a36Sopenharmony_ci if (!data) 137162306a36Sopenharmony_ci return -ENOMEM; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci status = ti_port_cmd_in(port, TI_GET_PORT_STATUS, 0, data, size); 137462306a36Sopenharmony_ci if (status) { 137562306a36Sopenharmony_ci dev_err(&port->dev, 137662306a36Sopenharmony_ci "%s - get port status command failed, %d\n", 137762306a36Sopenharmony_ci __func__, status); 137862306a36Sopenharmony_ci goto free_data; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - lsr 0x%02X\n", __func__, data->bLSR); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci *lsr = data->bLSR; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cifree_data: 138662306a36Sopenharmony_ci kfree(data); 138762306a36Sopenharmony_ci return status; 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 139462306a36Sopenharmony_ci struct ti_port *tport = usb_get_serial_port_data(port); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic void ti_handle_new_msr(struct ti_port *tport, u8 msr) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct async_icount *icount; 140362306a36Sopenharmony_ci struct tty_struct *tty; 140462306a36Sopenharmony_ci unsigned long flags; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci dev_dbg(&tport->tp_port->dev, "%s - msr 0x%02X\n", __func__, msr); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (msr & TI_MSR_DELTA_MASK) { 140962306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 141062306a36Sopenharmony_ci icount = &tport->tp_port->icount; 141162306a36Sopenharmony_ci if (msr & TI_MSR_DELTA_CTS) 141262306a36Sopenharmony_ci icount->cts++; 141362306a36Sopenharmony_ci if (msr & TI_MSR_DELTA_DSR) 141462306a36Sopenharmony_ci icount->dsr++; 141562306a36Sopenharmony_ci if (msr & TI_MSR_DELTA_CD) 141662306a36Sopenharmony_ci icount->dcd++; 141762306a36Sopenharmony_ci if (msr & TI_MSR_DELTA_RI) 141862306a36Sopenharmony_ci icount->rng++; 141962306a36Sopenharmony_ci wake_up_interruptible(&tport->tp_port->port.delta_msr_wait); 142062306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci tport->tp_msr = msr & TI_MSR_MASK; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci /* handle CTS flow control */ 142662306a36Sopenharmony_ci tty = tty_port_tty_get(&tport->tp_port->port); 142762306a36Sopenharmony_ci if (tty && C_CRTSCTS(tty)) { 142862306a36Sopenharmony_ci if (msr & TI_MSR_CTS) 142962306a36Sopenharmony_ci tty_wakeup(tty); 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci tty_kref_put(tty); 143262306a36Sopenharmony_ci} 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic void ti_stop_read(struct ti_port *tport, struct tty_struct *tty) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci unsigned long flags; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) 144262306a36Sopenharmony_ci tport->tp_read_urb_state = TI_READ_URB_STOPPING; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_cistatic int ti_restart_read(struct ti_port *tport, struct tty_struct *tty) 144962306a36Sopenharmony_ci{ 145062306a36Sopenharmony_ci struct urb *urb; 145162306a36Sopenharmony_ci int status = 0; 145262306a36Sopenharmony_ci unsigned long flags; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci spin_lock_irqsave(&tport->tp_lock, flags); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (tport->tp_read_urb_state == TI_READ_URB_STOPPED) { 145762306a36Sopenharmony_ci tport->tp_read_urb_state = TI_READ_URB_RUNNING; 145862306a36Sopenharmony_ci urb = tport->tp_port->read_urb; 145962306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 146062306a36Sopenharmony_ci urb->context = tport; 146162306a36Sopenharmony_ci status = usb_submit_urb(urb, GFP_KERNEL); 146262306a36Sopenharmony_ci } else { 146362306a36Sopenharmony_ci tport->tp_read_urb_state = TI_READ_URB_RUNNING; 146462306a36Sopenharmony_ci spin_unlock_irqrestore(&tport->tp_lock, flags); 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci return status; 146862306a36Sopenharmony_ci} 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_cistatic int ti_command_out_sync(struct usb_device *udev, u8 command, 147162306a36Sopenharmony_ci u16 moduleid, u16 value, void *data, int size) 147262306a36Sopenharmony_ci{ 147362306a36Sopenharmony_ci int status; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), command, 147662306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 147762306a36Sopenharmony_ci value, moduleid, data, size, 1000); 147862306a36Sopenharmony_ci if (status < 0) 147962306a36Sopenharmony_ci return status; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci return 0; 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_cistatic int ti_command_in_sync(struct usb_device *udev, u8 command, 148562306a36Sopenharmony_ci u16 moduleid, u16 value, void *data, int size) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci int status; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), command, 149062306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 149162306a36Sopenharmony_ci value, moduleid, data, size, 1000); 149262306a36Sopenharmony_ci if (status == size) 149362306a36Sopenharmony_ci status = 0; 149462306a36Sopenharmony_ci else if (status >= 0) 149562306a36Sopenharmony_ci status = -ECOMM; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci return status; 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cistatic int ti_port_cmd_out(struct usb_serial_port *port, u8 command, 150162306a36Sopenharmony_ci u16 value, void *data, int size) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci return ti_command_out_sync(port->serial->dev, command, 150462306a36Sopenharmony_ci TI_UART1_PORT + port->port_number, 150562306a36Sopenharmony_ci value, data, size); 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistatic int ti_port_cmd_in(struct usb_serial_port *port, u8 command, 150962306a36Sopenharmony_ci u16 value, void *data, int size) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci return ti_command_in_sync(port->serial->dev, command, 151262306a36Sopenharmony_ci TI_UART1_PORT + port->port_number, 151362306a36Sopenharmony_ci value, data, size); 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cistatic int ti_write_byte(struct usb_serial_port *port, 151762306a36Sopenharmony_ci struct ti_device *tdev, unsigned long addr, 151862306a36Sopenharmony_ci u8 mask, u8 byte) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci int status; 152162306a36Sopenharmony_ci unsigned int size; 152262306a36Sopenharmony_ci struct ti_write_data_bytes *data; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X\n", __func__, 152562306a36Sopenharmony_ci addr, mask, byte); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci size = sizeof(struct ti_write_data_bytes) + 2; 152862306a36Sopenharmony_ci data = kmalloc(size, GFP_KERNEL); 152962306a36Sopenharmony_ci if (!data) 153062306a36Sopenharmony_ci return -ENOMEM; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci data->bAddrType = TI_RW_DATA_ADDR_XDATA; 153362306a36Sopenharmony_ci data->bDataType = TI_RW_DATA_BYTE; 153462306a36Sopenharmony_ci data->bDataCounter = 1; 153562306a36Sopenharmony_ci data->wBaseAddrHi = cpu_to_be16(addr>>16); 153662306a36Sopenharmony_ci data->wBaseAddrLo = cpu_to_be16(addr); 153762306a36Sopenharmony_ci data->bData[0] = mask; 153862306a36Sopenharmony_ci data->bData[1] = byte; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci status = ti_command_out_sync(port->serial->dev, TI_WRITE_DATA, 154162306a36Sopenharmony_ci TI_RAM_PORT, 0, data, size); 154262306a36Sopenharmony_ci if (status < 0) 154362306a36Sopenharmony_ci dev_err(&port->dev, "%s - failed, %d\n", __func__, status); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci kfree(data); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci return status; 154862306a36Sopenharmony_ci} 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_cistatic int ti_do_download(struct usb_device *dev, int pipe, 155162306a36Sopenharmony_ci u8 *buffer, int size) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci int pos; 155462306a36Sopenharmony_ci u8 cs = 0; 155562306a36Sopenharmony_ci int done; 155662306a36Sopenharmony_ci struct ti_firmware_header *header; 155762306a36Sopenharmony_ci int status = 0; 155862306a36Sopenharmony_ci int len; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci for (pos = sizeof(struct ti_firmware_header); pos < size; pos++) 156162306a36Sopenharmony_ci cs = (u8)(cs + buffer[pos]); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci header = (struct ti_firmware_header *)buffer; 156462306a36Sopenharmony_ci header->wLength = cpu_to_le16(size - sizeof(*header)); 156562306a36Sopenharmony_ci header->bCheckSum = cs; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__); 156862306a36Sopenharmony_ci for (pos = 0; pos < size; pos += done) { 156962306a36Sopenharmony_ci len = min(size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE); 157062306a36Sopenharmony_ci status = usb_bulk_msg(dev, pipe, buffer + pos, len, 157162306a36Sopenharmony_ci &done, 1000); 157262306a36Sopenharmony_ci if (status) 157362306a36Sopenharmony_ci break; 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci return status; 157662306a36Sopenharmony_ci} 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_cistatic int ti_download_firmware(struct ti_device *tdev) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci int status; 158162306a36Sopenharmony_ci int buffer_size; 158262306a36Sopenharmony_ci u8 *buffer; 158362306a36Sopenharmony_ci struct usb_device *dev = tdev->td_serial->dev; 158462306a36Sopenharmony_ci unsigned int pipe = usb_sndbulkpipe(dev, 158562306a36Sopenharmony_ci tdev->td_serial->port[0]->bulk_out_endpointAddress); 158662306a36Sopenharmony_ci const struct firmware *fw_p; 158762306a36Sopenharmony_ci char buf[32]; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci if (le16_to_cpu(dev->descriptor.idVendor) == MXU1_VENDOR_ID) { 159062306a36Sopenharmony_ci snprintf(buf, 159162306a36Sopenharmony_ci sizeof(buf), 159262306a36Sopenharmony_ci "moxa/moxa-%04x.fw", 159362306a36Sopenharmony_ci le16_to_cpu(dev->descriptor.idProduct)); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci status = request_firmware(&fw_p, buf, &dev->dev); 159662306a36Sopenharmony_ci goto check_firmware; 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci /* try ID specific firmware first, then try generic firmware */ 160062306a36Sopenharmony_ci sprintf(buf, "ti_usb-v%04x-p%04x.fw", 160162306a36Sopenharmony_ci le16_to_cpu(dev->descriptor.idVendor), 160262306a36Sopenharmony_ci le16_to_cpu(dev->descriptor.idProduct)); 160362306a36Sopenharmony_ci status = request_firmware(&fw_p, buf, &dev->dev); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci if (status != 0) { 160662306a36Sopenharmony_ci buf[0] = '\0'; 160762306a36Sopenharmony_ci if (le16_to_cpu(dev->descriptor.idVendor) == MTS_VENDOR_ID) { 160862306a36Sopenharmony_ci switch (le16_to_cpu(dev->descriptor.idProduct)) { 160962306a36Sopenharmony_ci case MTS_CDMA_PRODUCT_ID: 161062306a36Sopenharmony_ci strcpy(buf, "mts_cdma.fw"); 161162306a36Sopenharmony_ci break; 161262306a36Sopenharmony_ci case MTS_GSM_PRODUCT_ID: 161362306a36Sopenharmony_ci strcpy(buf, "mts_gsm.fw"); 161462306a36Sopenharmony_ci break; 161562306a36Sopenharmony_ci case MTS_EDGE_PRODUCT_ID: 161662306a36Sopenharmony_ci strcpy(buf, "mts_edge.fw"); 161762306a36Sopenharmony_ci break; 161862306a36Sopenharmony_ci case MTS_MT9234MU_PRODUCT_ID: 161962306a36Sopenharmony_ci strcpy(buf, "mts_mt9234mu.fw"); 162062306a36Sopenharmony_ci break; 162162306a36Sopenharmony_ci case MTS_MT9234ZBA_PRODUCT_ID: 162262306a36Sopenharmony_ci strcpy(buf, "mts_mt9234zba.fw"); 162362306a36Sopenharmony_ci break; 162462306a36Sopenharmony_ci case MTS_MT9234ZBAOLD_PRODUCT_ID: 162562306a36Sopenharmony_ci strcpy(buf, "mts_mt9234zba.fw"); 162662306a36Sopenharmony_ci break; } 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci if (buf[0] == '\0') { 162962306a36Sopenharmony_ci if (tdev->td_is_3410) 163062306a36Sopenharmony_ci strcpy(buf, "ti_3410.fw"); 163162306a36Sopenharmony_ci else 163262306a36Sopenharmony_ci strcpy(buf, "ti_5052.fw"); 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci status = request_firmware(&fw_p, buf, &dev->dev); 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_cicheck_firmware: 163862306a36Sopenharmony_ci if (status) { 163962306a36Sopenharmony_ci dev_err(&dev->dev, "%s - firmware not found\n", __func__); 164062306a36Sopenharmony_ci return -ENOENT; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci if (fw_p->size > TI_FIRMWARE_BUF_SIZE) { 164362306a36Sopenharmony_ci dev_err(&dev->dev, "%s - firmware too large %zu\n", __func__, fw_p->size); 164462306a36Sopenharmony_ci release_firmware(fw_p); 164562306a36Sopenharmony_ci return -ENOENT; 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci buffer_size = TI_FIRMWARE_BUF_SIZE + sizeof(struct ti_firmware_header); 164962306a36Sopenharmony_ci buffer = kmalloc(buffer_size, GFP_KERNEL); 165062306a36Sopenharmony_ci if (buffer) { 165162306a36Sopenharmony_ci memcpy(buffer, fw_p->data, fw_p->size); 165262306a36Sopenharmony_ci memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size); 165362306a36Sopenharmony_ci status = ti_do_download(dev, pipe, buffer, fw_p->size); 165462306a36Sopenharmony_ci kfree(buffer); 165562306a36Sopenharmony_ci } else { 165662306a36Sopenharmony_ci status = -ENOMEM; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci release_firmware(fw_p); 165962306a36Sopenharmony_ci if (status) { 166062306a36Sopenharmony_ci dev_err(&dev->dev, "%s - error downloading firmware, %d\n", 166162306a36Sopenharmony_ci __func__, status); 166262306a36Sopenharmony_ci return status; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci dev_dbg(&dev->dev, "%s - download successful\n", __func__); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci return 0; 166862306a36Sopenharmony_ci} 1669