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