This driver is for Fintek F81532/F81534 USB to Serial Ports IC.

Features:
1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC
2. Support Baudrate from B50 to B1500000 (excluding B1000000).
3. The RTS signal can be transformed their behavior with configuration
   for transceiver (for RS232/RS485/RS422) (/sys/class/ttyUSBx/uart_mode)
4. There are 4x3 output-only GPIOs to control transceiver mode. It's
   can be controlled via sysfs (/sys/class/ttyUSBx/gpio)

Changelog from v1:
1. v1 version submit to staging tree, but Greg KH advised me to cleanup
   source code & re-submit it to correct subsystem
2. Remove all custom ioctl commands

If had any question, Please send email to
hpeter+linux_ker...@gmail.com
peter_h...@fintek.com.tw

Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com>
---
 drivers/usb/serial/Kconfig  |   10 +
 drivers/usb/serial/Makefile |    1 +
 drivers/usb/serial/f81534.c | 3162 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 3173 insertions(+)
 create mode 100644 drivers/usb/serial/f81534.c

diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index b7cf198..4bf3011 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -255,6 +255,16 @@ config USB_SERIAL_F81232
          To compile this driver as a module, choose M here: the
          module will be called f81232.
 
+config USB_SERIAL_F8153X
+       tristate "USB Fintek F81532/534 Multi-Ports Serial Driver"
+       help
+         Say Y here if you want to use the Fintek F81532/534 Multi-Ports
+         usb to serial adapter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called f81534.
+
+
 config USB_SERIAL_GARMIN
        tristate "USB Garmin GPS driver"
        help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 349d9df..9e43b7b 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT)             += io_edgeport.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)           += io_ti.o
 obj-$(CONFIG_USB_SERIAL_EMPEG)                 += empeg.o
 obj-$(CONFIG_USB_SERIAL_F81232)                        += f81232.o
+obj-$(CONFIG_USB_SERIAL_F8153X)                        += f81534.o
 obj-$(CONFIG_USB_SERIAL_FTDI_SIO)              += ftdi_sio.o
 obj-$(CONFIG_USB_SERIAL_GARMIN)                        += garmin_gps.o
 obj-$(CONFIG_USB_SERIAL_IPAQ)                  += ipaq.o
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
new file mode 100644
index 0000000..8c817ee
--- /dev/null
+++ b/drivers/usb/serial/f81534.c
@@ -0,0 +1,3162 @@
+/*
+ * F81532/F81534 USB to Serial Ports Bridge
+ *
+ * F81532 => 2 Serial Ports
+ * F81534 => 4 Serial Ports
+ *
+ * Copyright (C) 2014 Tom Tsai (tom_t...@fintek.com.tw)
+ *
+ */
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+
+/* Serial Port register Address */
+#define SERIAL_BASE_ADDRESS            0x1200
+#define RECEIVE_BUFFER_REGISTER                (0x00 + SERIAL_BASE_ADDRESS)
+#define TRANSMIT_HOLDING_REGISTER      (0x00 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_ENABLE_REGISTER      (0x01 + SERIAL_BASE_ADDRESS)
+#define INTERRUPT_IDENT_REGISTER       (0x02 + SERIAL_BASE_ADDRESS)
+#define FIFO_CONTROL_REGISTER          (0x02 + SERIAL_BASE_ADDRESS)
+#define LINE_CONTROL_REGISTER          (0x03 + SERIAL_BASE_ADDRESS)
+#define MODEM_CONTROL_REGISTER         (0x04 + SERIAL_BASE_ADDRESS)
+#define LINE_STATUS_REGISTER           (0x05 + SERIAL_BASE_ADDRESS)
+#define MODEM_STATUS_REGISTER          (0x06 + SERIAL_BASE_ADDRESS)
+#define CLK_SEL_REGISTER               (0x08 + SERIAL_BASE_ADDRESS)
+#define CONFIG1_REGISTER               (0x09 + SERIAL_BASE_ADDRESS)
+#define SADDRESS_REGISTER              (0x0a + SERIAL_BASE_ADDRESS)
+#define SADEN_REGISTER                 (0x0b + SERIAL_BASE_ADDRESS)
+#define DIVISOR_LATCH_LSB              (0x00 + SERIAL_BASE_ADDRESS)
+#define DIVISOR_LATCH_MSB              (0x01 + SERIAL_BASE_ADDRESS)
+#define SCRATCH_PAD_REGISTER           (0x07 + SERIAL_BASE_ADDRESS)
+
+#define F81534_RESERVE_ADDRESS_START   0x3000
+#define F81534_RESERVE_SIZE            8
+
+#define F81534_CUSTOM_ADDRESS_START    0x4000
+#define F81534_CUSTOM_TOTAL_SIZE       0x1000
+
+#define F81534_CUSTOM_DATA_SIZE        0x10
+#define F81534_CUSTOM_MAX_IDX \
+               (F81534_CUSTOM_TOTAL_SIZE/F81534_CUSTOM_DATA_SIZE)
+#define F81534_CUSTOM_NO_CUSTOM_DATA   (-1)
+
+#define F81534_MAX_DATA_BLOCK          64
+#define F81534_BUSY_STATUS     0x03
+#define F81534_MAX_BUS_RETRY           2000
+
+/* default urb timeout for usb operations */
+#define F81534_USB_MAX_RETRY   5
+#define F81534_USB_TIMEOUT     1000
+#define F81534_CONTROL_BYTE    0x1B
+#define F81534_SET_GET_REGISTER        0xA0
+
+#define F81534_NUM_PORT        4
+#define F81534_UNUSED_PORT     0xff
+#define F81534_DEFAULT_BAUD_RATE       9600
+#define F81534_WRITE_BUFFER_SIZE       (512L)  /* size of write buffer */
+#define F81534_READ_BUFFER_SIZE                (512L)
+#define IC_NAME                        "f81534"
+#define DRIVER_DESC \
+       "Fintek USB to Serial Ports Driver (F81532/F81534-Evaluation Board)"
+#define FINTEK_VENDOR_ID       0x1934
+#define FINTEK_DEVICE_ID       0x1202  /* RS232 four port */
+#define F81534_MAX_TX_SIZE     124L
+#define F81534_FIFO_SIZE       128L
+
+#define MULTIDROP_ENABLE
+#define HIGHBAUDRATE_ENABLE
+
+#ifdef HIGHBAUDRATE_ENABLE
+#define F81534_MAX_BAUDRATE    1500000
+#else
+#define F81534_MAX_BAUDRATE    115200
+#endif
+
+struct internal_data {
+       unsigned int address;
+       unsigned int size;
+       unsigned char buf[F81534_MAX_DATA_BLOCK];
+};
+
+#define F81534_RS232_FLAG      0x00
+#define F81534_RS485_FLAG      0x03
+#define F81534_RS485_1_FLAG    0x01
+
+static int m_F81534_MAX_TX_SIZE = F81534_MAX_TX_SIZE;
+
+enum eUartMode {
+       eModeRS422,
+       eModeRS232,
+       eModeRS485,
+       eModeRS485_1,
+       eModeRS422_term,
+       eModeRS232_coexist,
+       eModeRS485_1_term,
+       eModeShutdown,
+
+       eModeInvalid,
+};
+
+struct f81534_pin_config_data {
+       char dev_path[32];
+       char dev_name[32];
+       enum eUartMode eForceUartMode;
+       enum eUartMode eGPIOMode;
+       u8 port_invisable;
+       int address[9];
+       int offset[9];
+};
+
+struct reg_value {
+       int reg_address;
+       int reg_offset;
+       int reg_bit;
+};
+
+struct pin_data {
+       struct reg_value port_mode_1;
+       struct reg_value port_mode_0;
+       struct reg_value port_io;
+};
+
+struct out_pin {
+       struct pin_data m1;
+       struct pin_data m2;
+       struct pin_data sd;
+};
+
+struct io_map_value {
+       int product_id;
+       int max_port;
+       enum eUartMode mode;
+       struct out_pin port[MAX_NUM_PORTS + 1];
+};
+
+static struct io_map_value f81534_rs232_control = {
+       FINTEK_DEVICE_ID, F81534_NUM_PORT, eModeRS232,
+
+       {
+        /* please reference f81439 io port */
+        {
+         {{0x2ad5, 4, 0}, {0x2ad4, 4, 1}, {0x2a90, 4, 0},},
+         {{0x2ad5, 5, 0}, {0x2ad4, 5, 1}, {0x2a90, 5, 0},},
+         {{0x2add, 7, 0}, {0x2adc, 7, 1}, {0x2ae8, 7, 1},},
+         },
+        {
+         {{0x2add, 3, 0}, {0x2adc, 3, 1}, {0x2ae8, 3, 0},},
+         {{0x2add, 0, 0}, {0x2adc, 0, 1}, {0x2ae8, 0, 0},},
+         {{0x2add, 6, 0}, {0x2adc, 6, 1}, {0x2ae8, 6, 1},},
+         },
+        {
+         {{0x2ad3, 6, 0}, {0x2ad2, 6, 1}, {0x2a80, 6, 0},},
+         {{0x2add, 2, 0}, {0x2adc, 2, 1}, {0x2ae8, 2, 0},},
+         {{0x2ad5, 0, 0}, {0x2ad4, 0, 1}, {0x2a90, 0, 1},},
+         },
+        {
+         {{0x2ad5, 1, 0}, {0x2ad4, 1, 1}, {0x2a90, 1, 0},},
+         {{0x2ad5, 2, 0}, {0x2ad4, 2, 1}, {0x2a90, 2, 0},},
+         {{0x2ad5, 3, 0}, {0x2ad4, 3, 1}, {0x2a90, 3, 1},},
+         },
+        },
+};
+
+static struct io_map_value f81534_rs485_control = {
+       FINTEK_DEVICE_ID, F81534_NUM_PORT, eModeRS485,
+
+       {
+        /* please reference f81439 io port */
+        {
+         {{0x2ad5, 4, 0}, {0x2ad4, 4, 1}, {0x2a90, 4, 0},},
+         {{0x2ad5, 5, 0}, {0x2ad4, 5, 1}, {0x2a90, 5, 1},},
+         {{0x2add, 7, 0}, {0x2adc, 7, 1}, {0x2ae8, 7, 0},},
+         },
+        {
+         {{0x2add, 3, 0}, {0x2adc, 3, 1}, {0x2ae8, 3, 0},},
+         {{0x2add, 0, 0}, {0x2adc, 0, 1}, {0x2ae8, 0, 1},},
+         {{0x2add, 6, 0}, {0x2adc, 6, 1}, {0x2ae8, 6, 0},},
+         },
+        {
+         {{0x2ad3, 6, 0}, {0x2ad2, 6, 1}, {0x2a80, 6, 0},},
+         {{0x2add, 2, 0}, {0x2adc, 2, 1}, {0x2ae8, 2, 1},},
+         {{0x2ad5, 0, 0}, {0x2ad4, 0, 1}, {0x2a90, 0, 0},},
+         },
+        {
+         {{0x2ad5, 1, 0}, {0x2ad4, 1, 1}, {0x2a90, 1, 0},},
+         {{0x2ad5, 2, 0}, {0x2ad4, 2, 1}, {0x2a90, 2, 1},},
+         {{0x2ad5, 3, 0}, {0x2ad4, 3, 1}, {0x2a90, 3, 0},},
+         },
+        },
+};
+
+static struct io_map_value f81534_rs485_1_control = {
+       FINTEK_DEVICE_ID, F81534_NUM_PORT, eModeRS485_1,
+
+       {
+        /* please reference f81439 io port */
+        {
+         {{0x2ad5, 4, 0}, {0x2ad4, 4, 1}, {0x2a90, 4, 0},},
+         {{0x2ad5, 5, 0}, {0x2ad4, 5, 1}, {0x2a90, 5, 1},},
+         {{0x2add, 7, 0}, {0x2adc, 7, 1}, {0x2ae8, 7, 1},},
+         },
+        {
+         {{0x2add, 3, 0}, {0x2adc, 3, 1}, {0x2ae8, 3, 0},},
+         {{0x2add, 0, 0}, {0x2adc, 0, 1}, {0x2ae8, 0, 1},},
+         {{0x2add, 6, 0}, {0x2adc, 6, 1}, {0x2ae8, 6, 1},},
+         },
+        {
+         {{0x2ad3, 6, 0}, {0x2ad2, 6, 1}, {0x2a80, 6, 0},},
+         {{0x2add, 2, 0}, {0x2adc, 2, 1}, {0x2ae8, 2, 1},},
+         {{0x2ad5, 0, 0}, {0x2ad4, 0, 1}, {0x2a90, 0, 1},},
+         },
+        {
+         {{0x2ad5, 1, 0}, {0x2ad4, 1, 1}, {0x2a90, 1, 0},},
+         {{0x2ad5, 2, 0}, {0x2ad4, 2, 1}, {0x2a90, 2, 1},},
+         {{0x2ad5, 3, 0}, {0x2ad4, 3, 1}, {0x2a90, 3, 1},},
+         },
+        },
+};
+
+static struct io_map_value f81534_rs422_control = {
+       FINTEK_DEVICE_ID, F81534_NUM_PORT, eModeRS422,
+
+       {
+        /* please reference f81439 io port */
+        {
+         {{0x2ad5, 4, 0}, {0x2ad4, 4, 1}, {0x2a90, 4, 0},},
+         {{0x2ad5, 5, 0}, {0x2ad4, 5, 1}, {0x2a90, 5, 0},},
+         {{0x2add, 7, 0}, {0x2adc, 7, 1}, {0x2ae8, 7, 0},},
+         },
+        {
+         {{0x2add, 3, 0}, {0x2adc, 3, 1}, {0x2ae8, 3, 0},},
+         {{0x2add, 0, 0}, {0x2adc, 0, 1}, {0x2ae8, 0, 0},},
+         {{0x2add, 6, 0}, {0x2adc, 6, 1}, {0x2ae8, 6, 0},},
+         },
+        {
+         {{0x2ad3, 6, 0}, {0x2ad2, 6, 1}, {0x2a80, 6, 0},},
+         {{0x2add, 2, 0}, {0x2adc, 2, 1}, {0x2ae8, 2, 0},},
+         {{0x2ad5, 0, 0}, {0x2ad4, 0, 1}, {0x2a90, 0, 0},},
+         },
+        {
+         {{0x2ad5, 1, 0}, {0x2ad4, 1, 1}, {0x2a90, 1, 0},},
+         {{0x2ad5, 2, 0}, {0x2ad4, 2, 1}, {0x2a90, 2, 0},},
+         {{0x2ad5, 3, 0}, {0x2ad4, 3, 1}, {0x2a90, 3, 0},},
+         },
+        },
+};
+
+static struct io_map_value f81534_shutdown_control = {
+       FINTEK_DEVICE_ID, F81534_NUM_PORT, eModeShutdown,
+
+       {
+        /* please reference f81439 io port */
+        {
+         {{0x2ad5, 4, 0}, {0x2ad4, 4, 1}, {0x2a90, 4, 1},},
+         {{0x2ad5, 5, 0}, {0x2ad4, 5, 1}, {0x2a90, 5, 1},},
+         {{0x2add, 7, 0}, {0x2adc, 7, 1}, {0x2ae8, 7, 1},},
+         },
+        {
+         {{0x2add, 3, 0}, {0x2adc, 3, 1}, {0x2ae8, 3, 1},},
+         {{0x2add, 0, 0}, {0x2adc, 0, 1}, {0x2ae8, 0, 1},},
+         {{0x2add, 6, 0}, {0x2adc, 6, 1}, {0x2ae8, 6, 1},},
+         },
+        {
+         {{0x2ad3, 6, 0}, {0x2ad2, 6, 1}, {0x2a80, 6, 1},},
+         {{0x2add, 2, 0}, {0x2adc, 2, 1}, {0x2ae8, 2, 1},},
+         {{0x2ad5, 0, 0}, {0x2ad4, 0, 1}, {0x2a90, 0, 1},},
+         },
+        {
+         {{0x2ad5, 1, 0}, {0x2ad4, 1, 1}, {0x2a90, 1, 1},},
+         {{0x2ad5, 2, 0}, {0x2ad4, 2, 1}, {0x2a90, 2, 1},},
+         {{0x2ad5, 3, 0}, {0x2ad4, 3, 1}, {0x2a90, 3, 1},},
+         },
+        },
+};
+
+static struct io_map_value f81534_rs422_term_control = {
+       FINTEK_DEVICE_ID, F81534_NUM_PORT, eModeShutdown,
+
+       {
+        /* please reference f81439 io port */
+        {
+         {{0x2ad5, 4, 0}, {0x2ad4, 4, 1}, {0x2a90, 4, 1},},
+         {{0x2ad5, 5, 0}, {0x2ad4, 5, 1}, {0x2a90, 5, 0},},
+         {{0x2add, 7, 0}, {0x2adc, 7, 1}, {0x2ae8, 7, 0},},
+         },
+        {
+         {{0x2add, 3, 0}, {0x2adc, 3, 1}, {0x2ae8, 3, 1},},
+         {{0x2add, 0, 0}, {0x2adc, 0, 1}, {0x2ae8, 0, 0},},
+         {{0x2add, 6, 0}, {0x2adc, 6, 1}, {0x2ae8, 6, 0},},
+         },
+        {
+         {{0x2ad3, 6, 0}, {0x2ad2, 6, 1}, {0x2a80, 6, 1},},
+         {{0x2add, 2, 0}, {0x2adc, 2, 1}, {0x2ae8, 2, 0},},
+         {{0x2ad5, 0, 0}, {0x2ad4, 0, 1}, {0x2a90, 0, 0},},
+         },
+        {
+         {{0x2ad5, 1, 0}, {0x2ad4, 1, 1}, {0x2a90, 1, 1},},
+         {{0x2ad5, 2, 0}, {0x2ad4, 2, 1}, {0x2a90, 2, 0},},
+         {{0x2ad5, 3, 0}, {0x2ad4, 3, 1}, {0x2a90, 3, 0},},
+         },
+        },
+};
+
+static struct io_map_value f81534_rs232_coexist_control = {
+       FINTEK_DEVICE_ID, F81534_NUM_PORT, eModeShutdown,
+
+       {
+        /* please reference f81439 io port */
+        {
+         {{0x2ad5, 4, 0}, {0x2ad4, 4, 1}, {0x2a90, 4, 1},},
+         {{0x2ad5, 5, 0}, {0x2ad4, 5, 1}, {0x2a90, 5, 0},},
+         {{0x2add, 7, 0}, {0x2adc, 7, 1}, {0x2ae8, 7, 1},},
+         },
+        {
+         {{0x2add, 3, 0}, {0x2adc, 3, 1}, {0x2ae8, 3, 1},},
+         {{0x2add, 0, 0}, {0x2adc, 0, 1}, {0x2ae8, 0, 0},},
+         {{0x2add, 6, 0}, {0x2adc, 6, 1}, {0x2ae8, 6, 1},},
+         },
+        {
+         {{0x2ad3, 6, 0}, {0x2ad2, 6, 1}, {0x2a80, 6, 1},},
+         {{0x2add, 2, 0}, {0x2adc, 2, 1}, {0x2ae8, 2, 0},},
+         {{0x2ad5, 0, 0}, {0x2ad4, 0, 1}, {0x2a90, 0, 1},},
+         },
+        {
+         {{0x2ad5, 1, 0}, {0x2ad4, 1, 1}, {0x2a90, 1, 1},},
+         {{0x2ad5, 2, 0}, {0x2ad4, 2, 1}, {0x2a90, 2, 0},},
+         {{0x2ad5, 3, 0}, {0x2ad4, 3, 1}, {0x2a90, 3, 1},},
+         },
+        },
+};
+
+static struct io_map_value f81534_rs485_1_term_control = {
+       FINTEK_DEVICE_ID, F81534_NUM_PORT, eModeShutdown,
+
+       {
+        /* please reference f81439 io port */
+        {
+         {{0x2ad5, 4, 0}, {0x2ad4, 4, 1}, {0x2a90, 4, 1},},
+         {{0x2ad5, 5, 0}, {0x2ad4, 5, 1}, {0x2a90, 5, 1},},
+         {{0x2add, 7, 0}, {0x2adc, 7, 1}, {0x2ae8, 7, 0},},
+         },
+        {
+         {{0x2add, 3, 0}, {0x2adc, 3, 1}, {0x2ae8, 3, 1},},
+         {{0x2add, 0, 0}, {0x2adc, 0, 1}, {0x2ae8, 0, 1},},
+         {{0x2add, 6, 0}, {0x2adc, 6, 1}, {0x2ae8, 6, 0},},
+         },
+        {
+         {{0x2ad3, 6, 0}, {0x2ad2, 6, 1}, {0x2a80, 6, 1},},
+         {{0x2add, 2, 0}, {0x2adc, 2, 1}, {0x2ae8, 2, 1},},
+         {{0x2ad5, 0, 0}, {0x2ad4, 0, 1}, {0x2a90, 0, 0},},
+         },
+        {
+         {{0x2ad5, 1, 0}, {0x2ad4, 1, 1}, {0x2a90, 1, 1},},
+         {{0x2ad5, 2, 0}, {0x2ad4, 2, 1}, {0x2a90, 2, 1},},
+         {{0x2ad5, 3, 0}, {0x2ad4, 3, 1}, {0x2a90, 3, 0},},
+         },
+        },
+};
+
+static struct io_map_value *f81534_mode_control[eModeInvalid] = {
+       &f81534_rs422_control,
+       &f81534_rs232_control,
+       &f81534_rs485_control,
+       &f81534_rs485_1_control,
+       &f81534_rs422_term_control,
+       &f81534_rs232_coexist_control,
+       &f81534_rs485_1_term_control,
+       &f81534_shutdown_control,
+};
+
+static const struct usb_device_id id_table[] = {
+       {USB_DEVICE(FINTEK_VENDOR_ID, FINTEK_DEVICE_ID)},
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+enum eIC_Type {
+       eIC_F81530,
+       eIC_F81531,
+       eIC_F81532,
+       eIC_F81533,
+       eIC_F81534,
+};
+
+static const char * const m_ic_name[] = {
+       "F81530",
+       "F81531",
+       "F81532",
+       "F81533",
+       "F81534",
+};
+
+struct f81534_serial_private {
+       enum eIC_Type ic_type;
+       struct usb_serial *serial;
+       struct urb *read_urb[F81534_NUM_PORT];
+       char read_buffer[F81534_NUM_PORT][F81534_READ_BUFFER_SIZE];
+       bool phy_port_in_use[F81534_NUM_PORT];
+       bool write_urb_in_use[F81534_NUM_PORT];
+       struct urb *write_urb[F81534_NUM_PORT];
+       char write_buffer[F81534_NUM_PORT][F81534_WRITE_BUFFER_SIZE];
+       spinlock_t write_urb_lock;
+       spinlock_t msr_lock;
+       u8 shadowMSR[F81534_NUM_PORT];
+       unsigned long msr_time[F81534_NUM_PORT];
+       struct mutex msr_mutex;
+       u8 port_mapping[F81534_NUM_PORT];
+       struct mutex updating_mutex;
+       u8 reserve_data[F81534_RESERVE_SIZE];
+       u32 custom_idx;
+};
+
+struct f81534_port_private {
+       spinlock_t lock;
+       u8 shadowLSR;
+       u8 shadowMCR;
+       u8 shadowLCR;
+       struct usb_serial_port *port;
+       u32 tx, rx;
+       u32 currentLine;
+       u32 currentBaudRate;
+
+       struct f81534_pin_config_data port_pin_data;
+};
+
+static void f81534_update_lsr(struct usb_serial_port *port,
+               unsigned char *ch);
+static void f81534_update_msr(struct usb_serial_port *port,
+               unsigned char *ch);
+static void f81534_write_bulk_callback(struct urb *urb);
+static void f81534_read_bulk_callback(struct urb *urb);
+static int f81534_setup_urbs(struct usb_serial *serial);
+
+static int f81534_set_normal_register(struct usb_device *dev,
+                       u16 reg, u8 data);
+
+static int f81534_get_normal_register(struct usb_device *dev,
+                       u16 reg, u8 *data);
+
+static int f81534_getregister(struct usb_device *dev,
+                       u8 uart, u16 reg, u8 *data);
+
+static void f81534_dtr_rts(struct usb_serial_port *port, int on);
+static int f81534_set_port_mode(struct usb_serial_port *port,
+                       enum eUartMode eMode);
+static int f81534_free_urbs(struct usb_serial *serial);
+static int f81534_save_configure_data(struct usb_serial_port *port);
+
+static int f81534_logic_to_phy_port(struct usb_serial *usbserial, int logic)
+{
+       int index;
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(usbserial);
+
+       for (index = 0; index < F81534_NUM_PORT; ++index, --logic) {
+               if ((serial_priv->port_mapping[index] != F81534_UNUSED_PORT)
+                   && !logic)
+                       return serial_priv->port_mapping[index];
+       }
+
+       dev_err(&usbserial->dev->dev, "%s could found mapping: logic: %x\n",
+               __func__, logic);
+       return F81534_UNUSED_PORT;
+}
+
+static int f81534_phy_to_logic_port(struct usb_serial *usbserial, int phy)
+{
+       int index;
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(usbserial);
+
+       for (index = 0; index < F81534_NUM_PORT; ++index)
+               if (serial_priv->port_mapping[index] == phy)
+                       return index;
+
+       dev_err(&usbserial->dev->dev, "%s could found mapping: phy: %x\n",
+               __func__, phy);
+       return F81534_UNUSED_PORT;
+}
+
+static int f81534_port_to_phy_index(struct usb_serial_port *port)
+{
+       return f81534_logic_to_phy_port(port->serial, port->port_number);
+}
+
+static int f81534_port_index(struct usb_serial_port *port)
+{
+       return port->port_number;       /* no conversion, just return */
+}
+
+static int f81534_command_delay(struct usb_serial *usbserial)
+{
+       unsigned int count = F81534_MAX_BUS_RETRY;
+       unsigned char tmp;
+       int status;
+       struct usb_device *dev = usbserial->dev;
+
+       do {
+               status = f81534_get_normal_register(dev,
+                                       0x1003, &tmp);
+               if (status) {
+                       dev_err(&dev->dev,
+                                       "%s: failed, %d\n",
+                                       __func__, __LINE__);
+                       return status;
+               }
+
+               if (tmp & 0x03)
+                       continue;
+
+               if (tmp & 0x04)
+                       break;
+
+       } while (--count);
+
+       if (!count) {
+               dev_err(&usbserial->dev->dev, "%s: max retry exceed !!!\n",
+                       __func__);
+               return -EIO;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1003, tmp & ~0x04);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       return 0;
+}
+
+static int f81534_read_data(struct usb_serial *usbserial, int address, int 
size,
+                           unsigned char *buf)
+{
+       unsigned int count = 0;
+       unsigned int read_size = 0;
+       unsigned int block = 0;
+       unsigned char *tmp_buf;
+       int status;
+       int offset;
+       struct usb_device *dev = usbserial->dev;
+
+       tmp_buf = kzalloc(F81534_MAX_DATA_BLOCK, GFP_KERNEL);
+       if (!tmp_buf)
+               return -ENOMEM;
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n",
+                               __func__, __LINE__);
+               goto error;
+       }
+
+       status = f81534_set_normal_register(dev,
+                               0x1002, 0x03);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n",
+                               __func__, __LINE__);
+               goto error;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n",
+                               __func__, __LINE__);
+               goto error;
+       }
+
+       status = f81534_set_normal_register(dev,
+                               0x1002, (address >> 16) & 0xff);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n",
+                               __func__, __LINE__);
+               goto error;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n",
+                               __func__, __LINE__);
+               goto error;
+       }
+
+       status = f81534_set_normal_register(dev,
+                               0x1002, (address >> 8) & 0xff);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n",
+                               __func__, __LINE__);
+               goto error;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n",
+                               __func__, __LINE__);
+               goto error;
+       }
+
+       status = f81534_set_normal_register(dev,
+                               0x1002, (address >> 0) & 0xff);
+       if (status) {
+               dev_err(&dev->dev, "%s: failed, %d\n",
+                               __func__, __LINE__);
+               goto error;
+       }
+
+       /* continuous read mode */
+       do {
+               read_size = min(F81534_MAX_DATA_BLOCK, size);
+
+               for (count = 0; count < read_size; ++count) {
+
+                       status = f81534_command_delay(usbserial);
+                       if (status) {
+                               dev_err(&dev->dev,
+                                               "%s: failed, %d\n",
+                                               __func__, __LINE__);
+                               goto error;
+                       }
+
+                       if ((size <= F81534_MAX_DATA_BLOCK) &&
+                                       (read_size == (count + 1))) {
+                               status = f81534_set_normal_register(dev,
+                                               0x1001, 0xf1);
+                               if (status) {
+                                       dev_err(&dev->dev,
+                                                       "%s: failed, %d\n",
+                                                       __func__, __LINE__);
+                                       goto error;
+                               }
+                       } else {
+                               status = f81534_set_normal_register(dev,
+                                               0x1002, 0xf1);
+                               if (status) {
+                                       dev_err(&dev->dev,
+                                               "%s: failed, %d\n",
+                                               __func__, __LINE__);
+                                       goto error;
+                               }
+                       }
+
+                       status = f81534_command_delay(usbserial);
+                       if (status) {
+                               dev_err(&dev->dev,
+                                               "%s: failed, %d\n",
+                                               __func__, __LINE__);
+                               goto error;
+                       }
+
+                       status = f81534_get_normal_register(dev,
+                                       0x1004, &tmp_buf[count]);
+                       if (status) {
+                               dev_err(&dev->dev,
+                                               "%s: failed, %d\n",
+                                               __func__, __LINE__);
+                               goto error;
+                       }
+
+                       status = f81534_command_delay(usbserial);
+                       if (status) {
+                               dev_err(&dev->dev,
+                                               "%s: failed, %d\n",
+                                               __func__, __LINE__);
+                               goto error;
+                       }
+
+                       offset = count + (block * F81534_MAX_DATA_BLOCK);
+                       buf[offset] = tmp_buf[count];
+               }
+
+               size -= read_size;
+               block += 1;
+       } while (size);
+
+       kfree(tmp_buf);
+       return 0;
+
+error:
+       kfree(tmp_buf);
+       return status;
+
+}
+
+static int f81534_write_data(struct usb_serial *usbserial, int address,
+                            int size, unsigned char *buf)
+{
+       unsigned int count = 0;
+       unsigned int write_size = 0;
+       unsigned int block = 0;
+       int offset;
+       int status;
+       struct usb_device *dev = usbserial->dev;
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1001, 0x06);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1002, 0x02);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1002,
+                               (address >> 16) & 0xff);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1002,
+                               (address >> 8) & 0xff);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1002,
+                                                   (address >> 0) & 0xff);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       do {
+               write_size = min(F81534_MAX_DATA_BLOCK, size);
+
+               for (count = 0; count < write_size; ++count) {
+
+                       status = f81534_command_delay(usbserial);
+                       if (status) {
+                               dev_err(&dev->dev,
+                                               "%s: failed, %d\n",
+                                               __func__, __LINE__);
+                               return status;
+                       }
+
+                       offset = count + block * F81534_MAX_DATA_BLOCK;
+
+                       if ((size <= F81534_MAX_DATA_BLOCK)
+                                       && (write_size == (count + 1))) {
+
+                               status = f81534_set_normal_register(dev, 0x1001,
+                                                       buf[offset]);
+                               if (status) {
+                                       dev_err(&dev->dev,
+                                                       "%s: failed, %d\n",
+                                                       __func__, __LINE__);
+                                       return status;
+                               }
+
+                       } else {
+                               status = f81534_set_normal_register(dev, 0x1002,
+                                                       buf[offset]);
+                               if (status) {
+                                       dev_err(&dev->dev,
+                                                       "%s: failed, %d\n",
+                                                       __func__, __LINE__);
+                                       return status;
+                               }
+                       }
+               }
+
+               size -= write_size;
+               block += 1;
+       } while (size);
+
+       return 0;
+}
+
+static int f81534_erase_sector(struct usb_serial *usbserial, int address)
+{
+       u8 current_status = 0;
+       int status;
+       unsigned int count = F81534_MAX_BUS_RETRY;
+       struct usb_device *dev = usbserial->dev;
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1001, 0x06);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1002, 0x20);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1002,
+                                                   (address >> 16) & 0xff);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1002,
+                                                   (address >> 8) & 0xff);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_command_delay(usbserial);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       status = f81534_set_normal_register(dev, 0x1001,
+                                                   (address >> 0) & 0xff);
+       if (status) {
+               dev_err(&dev->dev,
+                               "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       /* getting status */
+
+       while (--count) {
+               status = f81534_command_delay(usbserial);
+               if (status) {
+                       dev_err(&dev->dev,
+                                       "%s: failed, %d\n", __func__, __LINE__);
+                       return status;
+               }
+
+               status = f81534_set_normal_register(dev, 0x1002, 0x05);
+               if (status) {
+                       dev_err(&dev->dev,
+                                       "%s: failed, %d\n", __func__, __LINE__);
+                       return status;
+               }
+
+               status = f81534_command_delay(usbserial);
+               if (status) {
+                       dev_err(&dev->dev,
+                                       "%s: failed, %d\n", __func__, __LINE__);
+                       return status;
+               }
+
+               status = f81534_set_normal_register(dev, 0x1001, 0xff);
+               if (status) {
+                       dev_err(&dev->dev,
+                                       "%s: failed, %d\n", __func__, __LINE__);
+                       return status;
+               }
+
+               status = f81534_command_delay(usbserial);
+               if (status) {
+                       dev_err(&dev->dev,
+                                       "%s: failed, %d\n", __func__, __LINE__);
+                       return status;
+               }
+
+               status = f81534_get_normal_register(dev, 0x1004,
+                                                           &current_status);
+               if (status) {
+                       dev_err(&dev->dev,
+                                       "%s: failed, %d\n", __func__, __LINE__);
+                       return status;
+               }
+
+               if (!(F81534_BUSY_STATUS & current_status)) {
+                       dev_info(&usbserial->dev->dev,
+                                "%s: data:%x, count:%d, ok\n", __func__,
+                                current_status, count);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static void f81534_wakeup_all_port(struct usb_serial *serial)
+{
+       int i;
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               if (serial->port[i])
+                       usb_serial_port_softint(serial->port[i]);
+       }
+}
+
+static int f81534_calc_baud_divisor(u32 baudrate, u32 clockrate, u32 *remain)
+{
+       u32 divisor, rem;
+
+       if (!baudrate)
+               return 0;
+
+       divisor = clockrate / baudrate;
+       rem = clockrate % baudrate;
+
+       if (remain)
+               *remain = rem;
+
+       /* Round to nearest divisor */
+       divisor = DIV_ROUND_CLOSEST(clockrate, baudrate);
+
+       return divisor;
+}
+
+static int f81534_get_normal_register(struct usb_device *dev,
+                                            u16 reg, u8 *data)
+{
+       int count = F81534_USB_MAX_RETRY;
+       int status;
+
+       while (count--) {
+               status = usb_control_msg(dev,
+                                        usb_rcvctrlpipe(dev, 0),
+                                        F81534_SET_GET_REGISTER,
+                                        0xc0,
+                                        reg,
+                                        0, data, sizeof(*data),
+                                        F81534_USB_TIMEOUT);
+               if (status <= 0) {
+                       if (status == 0)
+                               status = -EIO;
+               } else {
+                       break;
+               }
+       }
+
+       if ((count <= 0) && status) {
+               dev_err(&dev->dev,
+                       "%s ERROR reg:%x status:%i failed\n",
+                       __func__, reg, status);
+               return status;
+       }
+
+       return 0;
+}
+
+static int f81534_set_normal_register(struct usb_device *dev,
+                                            u16 reg, u8 data)
+{
+       int count = F81534_USB_MAX_RETRY;
+       int status = 0;
+
+       while (count--) {
+               status = usb_control_msg(dev,
+                                        usb_sndctrlpipe(dev, 0),
+                                        F81534_SET_GET_REGISTER,
+                                        0x40, reg, 0, &data, 1,
+                                        F81534_USB_TIMEOUT);
+               if (status <= 0) {
+                       if (status == 0)
+                               status = -EIO;
+               } else {
+                       break;
+               }
+       }
+
+       if ((count <= 0) && status) {
+               dev_err(&dev->dev,
+                       "%s ERROR reg:%x data:0x%x status:%i failed\n",
+                       __func__, reg, data, status);
+               return status;
+       }
+
+       return 0;
+}
+
+static int f81534_setregister(struct usb_device *dev,
+                                    u8 uart, u16 reg, u8 data)
+{
+       /* Our device maybe not reply when heavily loading,
+        * We'll retry for F81534_USB_MAX_RETRY times
+        */
+
+       int count = F81534_USB_MAX_RETRY;
+       int status;
+
+       while (count--) {
+               status = usb_control_msg(dev,
+                                        usb_sndctrlpipe(dev, 0),
+                                        F81534_SET_GET_REGISTER,
+                                        0x40,
+                                        reg + uart * 0x10,
+                                        0, &data, 1, F81534_USB_TIMEOUT);
+               if (status <= 0) {
+                       if (status == 0)
+                               status = -EIO;
+               } else {
+                       break;
+               }
+       }
+
+       if ((count <= 0) && status) {
+               dev_err(&dev->dev,
+                       "%s ERROR port_number:%d reg:%x data:0x%x status:%i 
failed\n",
+                       __func__, uart, reg + uart * 0x10, data, status);
+               return status;
+       }
+
+       return 0;
+}
+
+static int f81534_set_port_config(struct usb_device *dev,
+                                        unsigned char port_number,
+                                        struct usb_serial_port *port,
+                                        u32 baudrate, u16 lcr)
+{
+       struct usb_serial *serial = port->serial;
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+       u16 device_port = f81534_port_to_phy_index(port);
+       u32 divisor[3] = {0, 0, 0};
+       u32 rem[3] = {0, 0, 0};
+       u8 dll = 0;
+       u8 dlm = 0;
+       int val = 0x80;
+       int status;
+       u8 value;
+       bool is485Mode = false;
+       bool needInvert = false;
+
+       switch (port_priv->port_pin_data.eForceUartMode) {
+       case eModeRS232:
+       case eModeShutdown:
+       case eModeRS232_coexist:
+       case eModeInvalid:
+               break;
+
+       case eModeRS485:
+               needInvert = true;
+       default:
+               is485Mode = true;
+               break;
+
+       }
+
+       if (baudrate <= 115200) {
+               value = 0x01;   /* 1.846m fixed */
+               divisor[0] = f81534_calc_baud_divisor(baudrate, 115200, NULL);
+       } else {
+#ifdef HIGHBAUDRATE_ENABLE
+               int count;
+               u32 tmpIdx = 0xffffffff;
+               u32 minRem = 0xffffffff;
+               u32 baudrate_table[3] = { 921600, 1152000, 1500000 };
+               u8 clock_table[3] = { 0x07, 0x03, 0x05 };
+
+               for (count = 0; count < 3; ++count)
+                       divisor[count] = f81534_calc_baud_divisor(baudrate,
+                                                                 baudrate_table
+                                                                 [count],
+                                                                 &rem[count]);
+
+               for (count = 2; count >= 0; --count) {
+                       if (!rem[count] && divisor[count])
+                               break;  /* best clock */
+
+                       if (divisor[count] && (minRem >= rem[count])) {
+                               minRem = rem[count];
+                               tmpIdx = count;
+                       }
+               }
+
+               if (count != -1) {
+                       tmpIdx = count;
+                       dev_dbg(&dev->dev, "Best Index: %d, clock: %d\n",
+                               tmpIdx, baudrate_table[tmpIdx] * 16);
+               } else {
+                       dev_dbg(&dev->dev,
+                               "Subsititude Index: %d, minRem:%d, clock:%d\n",
+                               tmpIdx, minRem, baudrate_table[tmpIdx] * 16);
+               }
+
+               dev_dbg(&dev->dev, "\n");
+
+               for (count = 0; count < 3; ++count)
+                       dev_dbg(&dev->dev, "Index: %d, divisor:%d, rem:%d\n",
+                               count, divisor[count], rem[count]);
+
+               dev_dbg(&dev->dev, "\n");
+
+               divisor[0] = divisor[tmpIdx];
+               value = clock_table[tmpIdx];
+#else
+               dev_err(&dev->dev, "%s: baud rate error, max is:%d, 
current:%d\n",
+                               __func__, F81534_MAX_BAUDRATE, baudrate);
+#endif
+       }
+
+       value &= 0xcf;          /* remove bit4 & 5 */
+       value |= is485Mode << 4;        /* rs485/422 mode */
+       value |= needInvert << 5;       /* invert mode */
+
+
+       status = f81534_setregister(serial->dev,
+                                       device_port, CLK_SEL_REGISTER, value);
+       if (status) {
+               dev_err(&port->dev,
+                       "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       if (baudrate <= 1200)
+               value = 0xc3;   /* 128 fifo & TL: 1x */
+       else
+               value = 0xcf;   /* 128 fifo & TL: 8x */
+
+
+       status = f81534_setregister(serial->dev, device_port,
+                                           CONFIG1_REGISTER, value);
+       if (status) {
+               dev_err(&port->dev, "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       if (baudrate <= 1200)
+               value = 0x01;   /* TL: 1 */
+       else if (baudrate >= 1152000)
+               value = 0x81;   /* TL: 8 */
+       else
+               value = 0xc1;   /* TL: 14 */
+
+       status = f81534_setregister(serial->dev, device_port,
+                                           FIFO_CONTROL_REGISTER, value);
+       if (status) {
+               dev_err(&port->dev, "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       F81534_SET_GET_REGISTER,
+                       0x40,
+                       LINE_CONTROL_REGISTER + port_number * 0x10,
+                       0, &val, 1, F81534_USB_TIMEOUT);
+
+       dll = divisor[0] & 0xFF;
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       F81534_SET_GET_REGISTER,
+                       0x40,
+                       DIVISOR_LATCH_LSB + port_number * 0x10,
+                       0, &dll, 1, F81534_USB_TIMEOUT);
+
+       dlm = (divisor[0] >> 8) & 0xFF;
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       F81534_SET_GET_REGISTER,
+                       0x40,
+                       DIVISOR_LATCH_MSB + port_number * 0x10,
+                       0, &dlm, 1, F81534_USB_TIMEOUT);
+
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       F81534_SET_GET_REGISTER,
+                       0x40,
+                       LINE_CONTROL_REGISTER + port_number * 0x10,
+                       0, &lcr, 1, F81534_USB_TIMEOUT);
+
+       /* Enable all interrupts */
+       value = 0x0F;
+
+
+       status = f81534_setregister(dev, port_number,
+                                       INTERRUPT_ENABLE_REGISTER,
+                                       value);
+       if (status) {
+               dev_err(&port->dev, "%s: failed, %d\n", __func__, __LINE__);
+               return status;
+       }
+
+
+       return 0;
+}
+
+static int f81534_getregister(struct usb_device *dev,
+                                    u8 uart, u16 reg, u8 *data)
+{
+       int count = F81534_USB_MAX_RETRY;
+       int status;
+
+       while (count--) {
+               status = usb_control_msg(dev,
+                                        usb_rcvctrlpipe(dev, 0),
+                                        F81534_SET_GET_REGISTER,
+                                        0xc0,
+                                        reg + uart * 0x10,
+                                        0, data, sizeof(*data),
+                                        F81534_USB_TIMEOUT);
+               if (status <= 0) {
+                       if (status == 0)
+                               status = -EIO;
+               } else {
+                       break;
+               }
+       }
+
+       if ((count <= 0) && status) {
+               dev_err(&dev->dev,
+                       "%s ERROR port_number:%d reg:%x status:%i failed\n",
+                       __func__, uart, reg + uart * 0x10, status);
+               return status;
+       }
+
+       return 0;
+}
+
+static int f81534_update_mctrl(struct usb_serial_port *port,
+                                     unsigned int set, unsigned int clear)
+{
+       struct usb_device *dev = port->serial->dev;
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+       u8 urb_value;
+       int status;
+
+       mutex_lock(&serial_priv->msr_mutex);
+
+       if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
+               dev_dbg(&dev->dev, "%s -DTR|RTS not being set|cleared\n",
+                       __func__);
+               mutex_unlock(&serial_priv->msr_mutex);
+               return 0;       /* no change */
+       }
+
+       clear &= ~set;          /* 'set' takes precedence over 'clear' */
+       urb_value = 8 | port_priv->shadowMCR;
+
+       if (clear & TIOCM_DTR) {
+               urb_value &= ~UART_MCR_DTR;
+               dev_dbg(&dev->dev, "%s: port:%d clear DTR\n", __func__,
+                       f81534_port_to_phy_index(port));
+       }
+
+       if (clear & TIOCM_RTS) {
+               urb_value &= ~UART_MCR_RTS;
+               dev_dbg(&dev->dev, "%s: port:%d clear RTS\n", __func__,
+                       f81534_port_to_phy_index(port));
+
+       }
+
+       if (set & TIOCM_DTR) {
+               urb_value |= UART_MCR_DTR;
+               dev_dbg(&dev->dev, "%s: port:%d set DTR\n", __func__,
+                       f81534_port_to_phy_index(port));
+
+       }
+
+       if (set & TIOCM_RTS) {
+               urb_value |= UART_MCR_RTS;
+               dev_dbg(&dev->dev, "%s: port:%d set RTS\n", __func__,
+                       f81534_port_to_phy_index(port));
+       }
+
+       status = f81534_setregister(dev, f81534_port_to_phy_index(port),
+                                   MODEM_CONTROL_REGISTER, urb_value);
+       if (status < 0) {
+               dev_err(&port->dev,
+                       "%s- Error from MODEM_CTRL urb: %i\n",
+                       __func__, status);
+
+               mutex_unlock(&serial_priv->msr_mutex);
+               return status;
+       }
+
+       port_priv->shadowMCR = urb_value;
+       mutex_unlock(&serial_priv->msr_mutex);
+
+       return 0;
+}
+
+static int f81534_calc_custom_idx(struct usb_serial *serial, u32 *index)
+{
+       int idx, status;
+       u8 custom_data;
+       int offset;
+
+       for (idx = F81534_CUSTOM_MAX_IDX - 1; idx >= 0; --idx) {
+               offset = F81534_CUSTOM_ADDRESS_START +
+                                    F81534_CUSTOM_DATA_SIZE * idx;
+               status =
+                   f81534_read_data(serial, offset, 1,
+                               &custom_data);
+               if (status) {
+                       dev_err(&serial->dev->dev,
+                               "%s: read error, idx:%d, status:%d\n", __func__,
+                               idx, status);
+                       return status;
+               }
+
+               /* need improve to bsearch */
+
+               /* if had custom setting, override
+                * 1st byte is a indicater, 0xff is empty, 0x0f is had data
+                */
+
+               if (custom_data != 0xff)        /* found */
+                       break;
+       }
+
+       *index = idx;
+       return 0;
+}
+
+static int f81534_calc_num_ports(struct usb_serial *serial)
+{
+       struct f81534_serial_private *serial_priv = NULL;
+       int index;
+       u8 num_port = 0;
+       int status;
+       unsigned char reserve[F81534_CUSTOM_DATA_SIZE + 1];
+
+       serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
+       if (!serial_priv)
+               return 0;
+
+       usb_set_serial_data(serial, serial_priv);
+
+       /* oddy case for recovery bad usb */
+       if ((le16_to_cpu(serial->dev->descriptor.idProduct) == 0xffff) ||
+           (le16_to_cpu(serial->dev->descriptor.idVendor) == 0xffff))
+               return 4;
+
+       /* check had custom setting */
+       status = f81534_calc_custom_idx(serial, &serial_priv->custom_idx);
+       if (status) {
+               dev_err(&serial->dev->dev,
+                       "%s: f81534_calc_custom_idx read failed!!\n", __func__);
+               return 0;
+       }
+
+       /* read default board setting */
+       status = f81534_read_data(serial, F81534_RESERVE_ADDRESS_START,
+                                 F81534_NUM_PORT, reserve);
+       if (status) {
+               dev_err(&serial->dev->dev,
+                       "%s: f81534_read_data read failed!!\n", __func__);
+               return 0;
+       }
+
+       /* if had custom setting, override
+        * 1st byte is a indicater, 0xff is empty, 0x0f is had data
+        * skip with 1st data
+        */
+
+       if (serial_priv->custom_idx != F81534_CUSTOM_NO_CUSTOM_DATA) {
+               status = f81534_read_data(serial,
+                                         F81534_CUSTOM_ADDRESS_START +
+                                         F81534_CUSTOM_DATA_SIZE *
+                                         serial_priv->custom_idx + 1,
+                                         sizeof(reserve), reserve);
+               if (status) {
+                       dev_err(&serial->dev->dev,
+                               "%s: get custom data failed!!\n", __func__);
+                       return 0;
+               }
+
+               dev_info(&serial->dev->dev,
+                        "%s: read configure from block:%d\n", __func__,
+                        serial_priv->custom_idx);
+       } else
+               dev_info(&serial->dev->dev, "%s: read configure default\n",
+                        __func__);
+
+       for (index = 0; index < F81534_NUM_PORT; ++index) {
+               switch (reserve[index]) {
+               case 0x37:
+               case 0x38:
+               case 0x39:
+                       num_port += 1;
+                       break;
+               }
+       }
+
+       /* old style */
+       if (num_port) {
+               dev_dbg(&serial->dev->dev, "%s: old style wtih %d ports",
+                       __func__, num_port);
+               return num_port;
+       }
+
+       /*new style, find all possible ports */
+       num_port = 0;
+       for (index = 0; index < F81534_NUM_PORT; ++index) {
+               if (reserve[index] & BIT(7))
+                       continue;
+
+               num_port += 1;
+       }
+
+       if (num_port)
+               return num_port;
+
+       dev_err(&serial->dev->dev, "Read Failed!!, default 4 ports\n");
+       return 4;               /* nothing found */
+}
+
+static void f81534_set_termios(struct tty_struct *tty,
+                              struct usb_serial_port *port,
+                              struct ktermios *old_termios)
+{
+       struct usb_device *dev = port->serial->dev;
+       struct f81534_port_private *port_priv;
+       u32 baud = 0;
+       u16 new_lcr = 0;
+       int status = 0;
+
+       port_priv = usb_get_serial_port_data(port);
+
+       if (C_BAUD(tty) == B0)
+               f81534_update_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
+       else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+               f81534_update_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0);
+
+       if (C_PARENB(tty)) {
+               new_lcr |= UART_LCR_PARITY;
+
+               if (!C_PARODD(tty))
+                       new_lcr |= UART_LCR_EPAR;
+
+               if (C_CMSPAR(tty))
+                       new_lcr |= UART_LCR_SPAR;
+       }
+
+       if (C_CSTOPB(tty))
+               new_lcr |= UART_LCR_STOP;
+
+       switch (C_CSIZE(tty)) {
+       case CS5:
+               new_lcr |= UART_LCR_WLEN5;
+               break;
+       case CS6:
+               new_lcr |= UART_LCR_WLEN6;
+               break;
+       case CS7:
+               new_lcr |= UART_LCR_WLEN7;
+               break;
+       default:
+       case CS8:
+               new_lcr |= UART_LCR_WLEN8;
+               break;
+       }
+
+       baud = tty_get_baud_rate(tty);
+
+       if (baud) {
+               if ((baud == 1000000) || (baud > F81534_MAX_BAUDRATE)) {
+                       if (old_termios)
+                               baud = old_termios->c_ospeed;
+                       else
+                               baud = F81534_DEFAULT_BAUD_RATE;
+               }
+
+               dev_dbg(&dev->dev, "%s-baud: %d\n", __func__, baud);
+               tty_encode_baud_rate(tty, baud, baud);
+
+               port_priv->currentBaudRate = baud;
+       }
+
+       if (C_CRTSCTS(tty) && baud) {
+               dev_dbg(&dev->dev, "%s: port:%d CRTSCTS\n", __func__,
+                       f81534_port_to_phy_index(port));
+               f81534_update_mctrl(port, TIOCM_RTS, 0);
+       }
+
+       port_priv->shadowLCR = new_lcr;
+       status =
+           f81534_set_port_config(dev, f81534_port_to_phy_index(port), port,
+                                  port_priv->currentBaudRate, new_lcr);
+       if (status < 0)
+               dev_err(&port->dev, "%s - f81534_set_port_config failed: %i\n",
+                       __func__, status);
+
+}
+
+static int f81534_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+       if (tty)
+               f81534_set_termios(tty, port, &tty->termios);
+
+       return 0;
+}
+
+static void f81534_close(struct usb_serial_port *port)
+{
+       /* nothing to do, a placeholder */
+}
+
+static void f81534_disconnect(struct usb_serial *serial)
+{
+       struct f81534_serial_private *serial_priv = usb_get_serial_data(serial);
+
+       dev_dbg(&serial->dev->dev, "%s\n", __func__);
+       f81534_free_urbs(serial);
+       kfree(serial_priv);
+}
+
+static void f81534_release(struct usb_serial *serial)
+{
+       dev_dbg(&serial->dev->dev, "%s\n", __func__);
+}
+
+static int f81534_get_serial_info(struct usb_serial_port *port,
+                                 struct serial_struct __user *retinfo)
+{
+       struct serial_struct tmp;
+
+       if (!retinfo)
+               return -EFAULT;
+
+       memset(&tmp, 0, sizeof(tmp));
+
+       tmp.type = PORT_16550A;
+       tmp.line = port->minor;
+       tmp.port = port->port_number;
+       tmp.baud_base = 115200;
+
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+
+       return 0;
+}
+
+#define READ_AND_SET_NORMAL(dev, register, mask, value) \
+       ({      \
+               int status_tmp = 0 ; \
+               do {    \
+                       char *err_str = "%s - error: %x, status: %d\n"; \
+                       u8 urb_value_tmp = 0;   \
+                       status_tmp = f81534_get_normal_register(dev, \
+                                       register, &urb_value_tmp); \
+                       if (status_tmp < 0) {   \
+                               dev_err(&dev->dev, \
+                                               err_str, \
+                                               __func__,  \
+                                               register, \
+                                               status_tmp); \
+                               break; \
+                       }; \
+                       \
+                       if ((value) != 0) \
+                               urb_value_tmp |= \
+                                               ((1L << mask) & (value)) ; \
+                       else \
+                               urb_value_tmp &=  \
+                                               ~(1L << mask); \
+                       \
+                       status_tmp = f81534_set_normal_register(dev, \
+                                       register, \
+                                       urb_value_tmp); \
+                       \
+                       if (status_tmp < 0) {   \
+                               dev_err(&dev->dev, \
+                                               err_str, \
+                                               __func__, \
+                                               register, status_tmp); \
+                               break; \
+                       }; \
+               } while (0); \
+               status_tmp; \
+       })
+
+static int f81534_switch_gpio_mode(struct usb_serial_port
+                                  *serial_port, int mode)
+{
+       int x = f81534_port_to_phy_index(serial_port);
+       int y = 0;
+       int status;
+       struct usb_device *dev = serial_port->serial->dev;
+       struct io_map_value *request_mode =
+           f81534_mode_control[(mode >= eModeInvalid) ? eModeRS232 : mode];
+
+       struct pin_data *m1 = &request_mode->port[x].m1;
+       struct pin_data *m2 = &request_mode->port[x].m2;
+       struct pin_data *sd = &request_mode->port[x].sd;
+
+       struct pin_data *pins[3] = { m1, m2, sd };
+
+       if (mode >= 8)
+               return -EINVAL;
+
+       for (y = 0; y < 3; ++y) {
+               status = READ_AND_SET_NORMAL(dev,
+                                       pins[y]->port_io.reg_address,
+                                       pins[y]->port_io.reg_offset,
+                                       pins[y]->port_io.reg_bit ? 0xff : 0x00);
+               if (status) {
+                       dev_err(&serial_port->dev,
+                                       "%s: failed, %d\n",
+                                       __func__, __LINE__);
+                       return status;
+               }
+       }
+
+       return 0;
+}
+
+#define READ_AND_SET(dev, port_num, register, mask, value) \
+       ({      \
+               int status_tmp = 0 ; \
+               do {    \
+                       char *err_str = "%s:reg:%x, status:%d failed\n"; \
+                       u8 urb_value_tmp = 0;   \
+                       status_tmp = f81534_getregister(dev, port_num \
+                                       , register, &urb_value_tmp); \
+                       if (status_tmp < 0) {   \
+                               dev_err(&dev->dev, \
+                                               err_str, \
+                                               __func__, \
+                                               register, status_tmp); \
+                               break; \
+                       }; \
+                       \
+                       if (value != 0) \
+                               urb_value_tmp |= (u8) (mask & value) ; \
+                       else \
+                               urb_value_tmp &= (u8) ~(mask); \
+                       \
+                       status_tmp = f81534_setregister(dev, port_num, \
+                                       register, urb_value_tmp); \
+                       \
+                       if (status_tmp < 0) {   \
+                               dev_err(&dev->dev, \
+                                               err_str, \
+                                               __func__, \
+                                               register, status_tmp); \
+                               break; \
+                       }; \
+               } while (0); \
+               status_tmp; \
+       })
+
+
+static int f81534_set_port_mode(struct usb_serial_port *port,
+               enum eUartMode eMode)
+{
+       int status = 0;
+       u8 urb_value = 0;
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+
+       if (eMode > eModeInvalid)
+               return -1;
+
+       if (eMode != eModeInvalid) {
+               int data = 1;
+
+               status = f81534_getregister(port->serial->dev,
+                                       f81534_port_to_phy_index(port),
+                                       CLK_SEL_REGISTER,
+                                       &urb_value);
+               if (status) {
+                       dev_err(&port->dev,
+                                       "%s: failed, %d\n", __func__, __LINE__);
+                       return status;
+               }
+
+               urb_value &= ~(data << 4);
+               urb_value &= ~(data << 5);
+
+               switch (port_priv->port_pin_data.eForceUartMode) {
+               case eModeRS232:
+               case eModeShutdown:
+               case eModeRS232_coexist:
+                       break;
+
+               case eModeRS485:
+                       urb_value |= (data << 4);
+                       urb_value |= (data << 5);
+                       dev_dbg(&port->dev, "%s: eModeRS485 urb:%x\n", __func__,
+                               urb_value);
+                       break;
+
+               default:
+                       urb_value |= (data << 4);
+                       dev_dbg(&port->dev, "%s others urb:%x\n", __func__,
+                               urb_value);
+                       break;
+
+               }
+
+               status = f81534_setregister(port->serial->dev,
+                                       f81534_port_to_phy_index(port),
+                                       CLK_SEL_REGISTER,
+                                       urb_value);
+               if (status) {
+                       dev_err(&port->dev,
+                                       "%s: failed, %d\n", __func__, __LINE__);
+                       return status;
+               }
+
+       }
+
+       port_priv->port_pin_data.eForceUartMode = eMode;
+       return 0;
+}
+
+static int f81534_ioctl_set_rs485(struct usb_serial_port *port,
+                          struct serial_rs485 __user *arg)
+{
+
+       struct serial_rs485 data;
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+       struct usb_device *usb_dev = port->serial->dev;
+       u16 device_port = f81534_port_to_phy_index(port);
+       int status;
+
+       status = mutex_lock_interruptible(&serial_priv->updating_mutex);
+       if (status) {
+               dev_info(&port->dev, "%s: interrupted!\n", __func__);
+               return status;
+       }
+
+       status = copy_from_user(&data, (struct serial_rs485 __user *)arg,
+                               sizeof(data));
+       if (status) {
+               status = -EFAULT;
+               goto finish;
+       }
+
+       if (data.flags & SER_RS485_ENABLED) {
+               if (data.flags & SER_RS485_RTS_ON_SEND) {
+                       dev_dbg(&port->dev, "%s: eModeRS485_1\n", __func__);
+                       port_priv->port_pin_data.eForceUartMode = eModeRS485_1;
+               } else {
+                       dev_dbg(&port->dev, "%s: eModeRS485\n", __func__);
+                       port_priv->port_pin_data.eForceUartMode = eModeRS485;
+               }
+       } else {
+               dev_dbg(&port->dev, "%s: eModeRS232\n", __func__);
+               port_priv->port_pin_data.eForceUartMode = eModeRS232;
+       }
+
+       status = f81534_set_port_config(usb_dev, device_port, port,
+                                       port_priv->currentBaudRate,
+                                       port_priv->shadowLCR);
+       if (status) {
+               dev_err(&usb_dev->dev, "%s: set port error!!\n", __func__);
+               goto finish;
+       }
+
+       status = f81534_save_configure_data(port);
+
+finish:
+       mutex_unlock(&serial_priv->updating_mutex);
+       f81534_wakeup_all_port(port->serial);
+
+       return status;
+}
+
+static int f81534_ioctl_get_rs485(struct usb_serial_port *port,
+                          struct serial_rs485 __user *arg)
+{
+       int status = 0;
+       struct serial_rs485 data;
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+
+       status = mutex_lock_interruptible(&serial_priv->updating_mutex);
+       if (status) {
+               dev_info(&port->dev, "%s: interrupted!\n", __func__);
+               return status;
+       }
+
+       memset(&data, 0, sizeof(data));
+
+       switch (port_priv->port_pin_data.eForceUartMode) {
+       case eModeRS485:
+               dev_dbg(&port->dev, "%s: eModeRS485\n", __func__);
+               data.flags = SER_RS485_ENABLED;
+               break;
+       case eModeRS485_1:
+               dev_dbg(&port->dev, "%s: eModeRS485_1\n", __func__);
+               data.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
+               break;
+       default:
+               dev_dbg(&port->dev, "%s: eModeRS232\n", __func__);
+               break;
+       }
+
+       if (copy_to_user((struct serial_rs485 *)arg,
+                        &data, sizeof(struct serial_rs485)))
+               status = -EFAULT;
+
+       mutex_unlock(&serial_priv->updating_mutex);
+       f81534_wakeup_all_port(port->serial);
+
+       return status;
+}
+
+static int f81534_ioctl(struct tty_struct *tty, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct usb_serial_port *port = tty->driver_data;
+
+       switch (cmd) {
+       case TIOCGRS485:
+               return f81534_ioctl_get_rs485(port,
+                                             (struct serial_rs485 __user *)
+                                             arg);
+
+       case TIOCSRS485:
+               return f81534_ioctl_set_rs485(port,
+                                             (struct serial_rs485 __user *)
+                                             arg);
+
+       case TIOCGSERIAL:
+               return f81534_get_serial_info(port,
+                                             (struct serial_struct __user *)
+                                             arg);
+
+       default:
+               break;
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static void f81534_process_read_urb(struct urb *urb)
+{
+       struct usb_serial *serial;
+       struct f81534_serial_private *serial_priv;
+       struct usb_serial_port *port = NULL;
+       struct f81534_port_private *port_priv = NULL;
+       unsigned char *ch;
+       u8 lsr = 0;
+       int i, j;
+       int len = urb->actual_length;
+       int datalen = 0;
+       int tty_port_num = 0;
+       int phy_port_num = 0;
+       int status;
+       bool msr_avail;
+       u8 *msr;
+       struct tty_struct *tty;
+
+       if (!len)
+               return;
+
+       ch = urb->transfer_buffer;
+       serial = urb->context;
+       serial_priv = usb_get_serial_data(serial);
+
+       for (i = 0; i < urb->actual_length; i++) {
+               ch = (unsigned char *)urb->transfer_buffer + i;
+               j = i / 128;
+               if (i == (1 + j * 128)) {
+                       msr_avail = true;
+                       msr = (unsigned char *)(ch + 2);
+
+                       if (*ch == 0x03) {      /* tx empty */
+                               spin_lock(&serial_priv->write_urb_lock);
+                               serial_priv->phy_port_in_use[phy_port_num] =
+                                   false;
+                               spin_unlock(&serial_priv->write_urb_lock);
+
+                               usb_serial_port_softint(port);
+                               i = i + 126;
+
+                       } else if (*ch == 0x01) {       /* 0x01 read */
+                               tty = tty_port_tty_get(&port->port);
+                               if (tty)
+                                       tty_kref_put(tty);
+                               else
+                                       i += 126;       /*skip packet */
+
+                       } else if (*ch == 0x04) {       /*  msr changed */
+                               i += 126;       /* direct drop this packet */
+
+                               dev_dbg(&port->dev,
+                                       "%s- MSR Change (token: 0x04), 
current:%02x, changed to: %02x\n",
+                                       __func__,
+                                       serial_priv->shadowMSR[phy_port_num],
+                                       *msr);
+                       } else {
+                               i += 126;       /* direct drop this packet */
+                               dev_err(&port->dev, "%s %d known cmd\n",
+                                       __func__, __LINE__);
+                               msr_avail = false;
+                       }
+
+                       if (msr_avail) {
+                               u8 oldmsr = 0;
+
+                               spin_lock(&serial_priv->msr_lock);
+                               oldmsr = serial_priv->shadowMSR[phy_port_num];
+                               serial_priv->shadowMSR[phy_port_num] = *msr;
+                               serial_priv->msr_time[phy_port_num] = jiffies;
+                               spin_unlock(&serial_priv->msr_lock);
+
+                               if (((oldmsr & 0xf0) ^ (*msr & 0xf0)) &
+                                       UART_MSR_DCD) {
+
+                                       tty = tty_port_tty_get(&port->port);
+                                       if (tty) {
+                                               usb_serial_handle_dcd_change
+                                                   (port, port->port.tty,
+                                                    (*msr) & UART_MSR_DCD);
+                                               tty_kref_put(tty);
+                                       }
+
+                                       dev_dbg(&port->dev,
+                                               "%s: DCD Changed: port %d from 
%x to %x, tty state: %d\n",
+                                               __func__, phy_port_num, oldmsr,
+                                               *msr, port->port.tty ? 1 : 0);
+                               }
+
+                               f81534_update_msr(port, msr);
+                       }
+
+                       continue;
+               }
+
+               if (i == (j * 128)) {
+                       phy_port_num = *ch;
+                       tty_port_num =
+                           f81534_phy_to_logic_port(serial, phy_port_num);
+                       port = serial->port[tty_port_num];
+                       port_priv = usb_get_serial_port_data(port);
+                       lsr = 0;
+                       continue;
+               }
+
+               if (i == (2 + j * 128)) {
+                       datalen = *ch / 2;
+                       continue;
+               }
+
+               if (i < (4 + j * 128))
+                       continue;
+
+               if (((i % 2) == 1) && (i > (4 + j * 128))) {
+                       lsr |= *ch;
+                       continue;
+               }
+
+               if (datalen == 0) {
+                       i = (j + 1) * 128 - 1;
+
+                       tty = tty_port_tty_get(&port->port);
+
+                       if (!tty)
+                               continue;
+
+                       if (UART_LSR_OE & lsr)
+                               tty_insert_flip_char(&port->port, 0,
+                                                    TTY_OVERRUN);
+
+                       tty_flip_buffer_push(&port->port);
+
+                       if ((i + 1) == urb->actual_length)
+                               i++;
+
+                       if (port_priv && (lsr & UART_LSR_BRK_ERROR_BITS)) {
+                               dev_info(&port->dev, "phy_port_num: %d, lsr: 
%x\n",
+                                      phy_port_num, lsr);
+                               f81534_update_lsr(port, &lsr);
+                       }
+
+                       tty_kref_put(tty);
+
+                       continue;
+               }
+
+               tty_buffer_request_room(&port->port, 1);
+               tty_insert_flip_string(&port->port, ch, 1);
+               datalen--;
+       }
+
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status != 0) {
+               dev_err(&serial->dev->dev,
+                       "%s - resubmit read urb failed: %i\n",
+                       __func__, status);
+       }
+
+}
+
+static void f81534_write_bulk_callback(struct urb *urb)
+{
+}
+
+static void f81534_read_bulk_callback(struct urb *urb)
+{
+       struct usb_serial *serial = urb->context;
+       struct f81534_serial_private *serial_priv;
+
+       serial_priv = usb_get_serial_data(serial);
+
+       if (urb->status)
+               return;
+
+       f81534_process_read_urb(urb);
+}
+
+static int f81534_free_urbs(struct usb_serial *serial)
+{
+       struct f81534_serial_private *serial_priv = usb_get_serial_data(serial);
+       int i;
+
+       for (i = 0; i < F81534_NUM_PORT; ++i) {
+               if (serial_priv->read_urb[i]) {
+                       usb_kill_urb(serial_priv->read_urb[i]);
+                       usb_free_urb(serial_priv->read_urb[i]);
+                       serial_priv->read_urb[i] = NULL;
+               }
+       }
+
+       for (i = 0; i < F81534_NUM_PORT; ++i) {
+               if (serial_priv->write_urb[i]) {
+                       usb_kill_urb(serial_priv->write_urb[i]);
+                       usb_free_urb(serial_priv->write_urb[i]);
+                       serial_priv->write_urb[i] = NULL;
+               }
+       }
+
+       return 0;
+}
+
+static int f81534_setup_urbs(struct usb_serial *serial)
+{
+       struct usb_serial_port *port0;
+       struct f81534_serial_private *serial_priv;
+       int status;
+       int i = 0;
+       u8 ep0_in_address;
+       void *buf = NULL;
+
+       port0 = serial->port[0];
+       serial_priv = usb_get_serial_data(serial);
+       ep0_in_address = port0->bulk_in_endpointAddress;
+
+       for (i = 0; i < F81534_NUM_PORT; ++i) {
+               serial_priv->read_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+               if (!serial_priv->read_urb[i]) {
+                       dev_err(&serial->dev->dev, "No free urbs available\n");
+                       status = -ENOMEM;
+                       goto failed;
+               }
+
+               buf = serial_priv->read_buffer[i];
+
+               usb_fill_bulk_urb(serial_priv->read_urb[i], serial->dev,
+                                 usb_rcvbulkpipe(serial->dev,
+                                                 ep0_in_address),
+                                 buf, sizeof(serial_priv->read_buffer[i]),
+                                 f81534_read_bulk_callback, serial);
+       }
+
+       for (i = 0; i < F81534_NUM_PORT; ++i) {
+               status = usb_submit_urb(serial_priv->read_urb[i], GFP_KERNEL);
+               if (status != 0)
+                       goto failed;
+       }
+
+       for (i = 0; i < F81534_NUM_PORT; ++i) {
+               serial_priv->write_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+               if (!serial_priv->write_urb[i]) {
+                       status = -ENOMEM;
+                       goto failed;
+               }
+
+               buf = serial_priv->write_buffer[i];
+
+               usb_fill_bulk_urb(serial_priv->write_urb[i], serial->dev,
+                                 usb_sndbulkpipe(serial->dev,
+                                                 port0->
+                                                 bulk_out_endpointAddress),
+                                 buf, sizeof(serial_priv->write_buffer[i]),
+                                 f81534_write_bulk_callback, serial);
+       }
+
+       return 0;
+
+failed:
+
+       for (i = 0; i < F81534_NUM_PORT; ++i) {
+               if (serial_priv->read_urb[i]) {
+                       usb_kill_urb(serial_priv->read_urb[i]);
+                       usb_free_urb(serial_priv->read_urb[i]);
+               }
+       }
+
+       for (i = 0; i < F81534_NUM_PORT; ++i)
+               usb_free_urb(serial_priv->write_urb[i]);
+
+       return status;
+}
+
+static int f81534_save_configure_data(struct usb_serial_port *port)
+{
+       int status;
+       int count;
+       int phy;
+       int gpio_address, uart_address;
+       int offset;
+       bool reConfigure = false;
+       u8 uart_mode, gpio_mode;
+       u8 data[F81534_RESERVE_SIZE + 1];
+       u8 tmp[F81534_RESERVE_SIZE];
+
+       struct usb_serial *serial = port->serial;
+       struct f81534_port_private *port_priv;
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+
+       /* compare mem with ic data */
+       for (count = 0; count < serial->num_ports; ++count) {
+               port_priv = usb_get_serial_port_data(serial->port[count]);
+               phy = f81534_logic_to_phy_port(serial, count);
+
+               if (!port_priv) {
+                       dev_info(&port->dev,
+                                "%s: port_priv:0 something problem here 
phy:%d!!\n",
+                                __func__, phy);
+                       continue;
+               }
+
+               if (serial_priv->custom_idx == F81534_CUSTOM_NO_CUSTOM_DATA) {
+                       uart_address = F81534_RESERVE_ADDRESS_START + phy;
+                       gpio_address = F81534_RESERVE_ADDRESS_START + phy + 4;
+               } else {
+                       /* if had custom setting, override
+                        * 1st byte is a indicater, 0xff is empty,
+                        * 0x0f is had data. Skip with 1st data
+                        */
+
+                       uart_address = F81534_CUSTOM_ADDRESS_START +
+                           serial_priv->custom_idx * F81534_CUSTOM_DATA_SIZE+
+                           phy + 1;
+
+                       gpio_address = F81534_CUSTOM_ADDRESS_START +
+                           serial_priv->custom_idx * F81534_CUSTOM_DATA_SIZE +
+                           phy + 4 + 1;
+               }
+
+               status = f81534_read_data(port->serial, uart_address,
+                                         1, &uart_mode);
+               if (status) {
+                       dev_err(&port->dev,
+                               "%s: read uart configure data failed: index:%x, 
status:%d\n",
+                               __func__, uart_address, status);
+                       return status;
+               }
+
+               status = f81534_read_data(port->serial, gpio_address,
+                                         1, &gpio_mode);
+               if (status) {
+                       dev_err(&port->dev,
+                               "%s: read gpio configure data failed: index:%x, 
status:%d\n",
+                               __func__, gpio_address, status);
+                       return status;
+               }
+
+               if (port_priv->port_pin_data.eGPIOMode != gpio_mode)
+                       reConfigure = true;
+
+               /* check uart flag */
+               if (port_priv->port_pin_data.eForceUartMode == eModeRS232) {
+                       if ((uart_mode & 0x03) != F81534_RS232_FLAG)
+                               reConfigure = true;
+               } else if (port_priv->port_pin_data.eForceUartMode ==
+                          eModeRS485_1) {
+                       if ((uart_mode & 0x03) != F81534_RS485_1_FLAG)
+                               reConfigure = true;
+               } else if (port_priv->port_pin_data.eForceUartMode ==
+                          eModeRS485) {
+                       if ((uart_mode & 0x03) != F81534_RS485_FLAG)
+                               reConfigure = true;
+               } else
+                       reConfigure = true;
+
+               if (reConfigure)
+                       break;
+       }
+
+       if (!reConfigure) {
+               dev_info(&serial->dev->dev, "%s: update-to-date\n", __func__);
+               return 0;
+       }
+
+       dev_info(&serial->dev->dev, "%s: updating\n", __func__);
+
+       /* next setting block */
+       serial_priv->custom_idx =
+           (serial_priv->custom_idx + 1) % F81534_CUSTOM_MAX_IDX;
+       dev_info(&serial->dev->dev, "%s: saving to block index:%d\n", __func__,
+                serial_priv->custom_idx);
+
+       /* erase when start block is 0 */
+       if (!serial_priv->custom_idx) {
+               dev_dbg(&serial->dev->dev, "%s: need erase\n", __func__);
+
+               /* erase */
+               status = f81534_erase_sector(serial,
+                               F81534_CUSTOM_ADDRESS_START);
+               if (status) {
+                       dev_err(&port->dev,
+                               "%s: f81534_erase_sector failed!! status:%d\n",
+                               __func__, status);
+                       return status;
+               }
+       } else {
+               dev_dbg(&serial->dev->dev, "%s: dont need erase\n", __func__);
+       }
+
+       /* reprogram */
+
+       for (count = 0; count < serial->num_ports; ++count) {
+               port_priv = usb_get_serial_port_data(serial->port[count]);
+               phy = f81534_logic_to_phy_port(serial, count);
+
+               gpio_mode = port_priv->port_pin_data.eGPIOMode;
+               serial_priv->reserve_data[phy + 4] = gpio_mode;
+               serial_priv->reserve_data[phy + 0] &= ~(0x03);
+
+               /* check uart flag */
+               if (port_priv->port_pin_data.eForceUartMode == eModeRS232) {
+                       serial_priv->reserve_data[phy + 0] |=
+                                       F81534_RS232_FLAG;
+               } else if (port_priv->port_pin_data.eForceUartMode ==
+                          eModeRS485_1) {
+                       serial_priv->reserve_data[phy + 0] |=
+                                       F81534_RS485_1_FLAG;
+               } else if (port_priv->port_pin_data.eForceUartMode ==
+                          eModeRS485) {
+                       serial_priv->reserve_data[phy + 0] |=
+                                       F81534_RS485_FLAG;
+               } else {
+                       dev_err(&serial->dev->dev,
+                               "%s: write configure error!! 
eForceUartMode:%d\n",
+                               __func__,
+                               port_priv->port_pin_data.eForceUartMode);
+               }
+
+               dev_info(&serial->dev->dev,
+                        "%s: port:%d uart_mode:%x, gpio_mode:%x\n", __func__,
+                        count, serial_priv->reserve_data[phy + 0], gpio_mode);
+       }
+
+       /* 1st byte is a indicater, 0xff is empty, 0x0f is had data
+        * only write 8 bytes of total 4 port uart & gpio mode
+        * so we need write 1+8 data
+        */
+
+       data[0] = 0x0f;
+       memcpy(&data[1], serial_priv->reserve_data,
+                       F81534_RESERVE_SIZE);
+
+       offset = F81534_CUSTOM_ADDRESS_START +
+                       F81534_CUSTOM_DATA_SIZE * serial_priv->custom_idx;
+
+       status = f81534_write_data(serial, offset, sizeof(data), data);
+       if (status) {
+               dev_err(&port->dev,
+                       "%s: f81534_write_data failed!! status:%d\n", __func__,
+                       status);
+               return status;
+       }
+
+       /* check save & memory data */
+       do {
+               memset(tmp, 0, sizeof(tmp));
+
+               status = f81534_read_data(serial,
+                                         F81534_CUSTOM_ADDRESS_START +
+                                         F81534_CUSTOM_DATA_SIZE *
+                                         serial_priv->custom_idx + 1,
+                                         sizeof(tmp), tmp);
+               if (status) {
+                       dev_err(&port->dev,
+                               "%s: f81534_read_data failed!! status:%d\n",
+                               __func__, status);
+                       return status;
+               }
+
+               for (count = 0; count < 8; ++count) {
+                       if (tmp[count] != serial_priv->reserve_data[count]) {
+                               dev_err(&port->dev,
+                                       "%s:check data error, count:%d, data:%x 
%x\n",
+                                       __func__, count, tmp[count],
+                                       serial_priv->reserve_data[count]);
+                       }
+               }
+
+       } while (0);
+
+       dev_dbg(&serial->dev->dev, "%s: complete\n", __func__);
+
+       return 0;
+}
+
+static int f81534_load_configure_data(struct usb_serial_port *port)
+{
+       int status;
+       unsigned char uart_flag, gpio_mode;
+       int device_port = f81534_port_to_phy_index(port);
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+
+       uart_flag = serial_priv->reserve_data[device_port];
+       gpio_mode = serial_priv->reserve_data[device_port + 4];
+
+       switch (uart_flag) {
+       case 0x37:
+       case 0x38:
+       case 0x39:
+               serial_priv->reserve_data[device_port] = F81534_RS232_FLAG;
+               gpio_mode = serial_priv->reserve_data[device_port + 4] =
+                   eModeRS232;
+               port_priv->port_pin_data.eForceUartMode = eModeRS232;
+               port_priv->port_pin_data.eGPIOMode = eModeRS232;
+               dev_info(&port->dev,
+                        "transceiver field with old style, upgrading\n");
+               break;
+
+       default:
+               if (uart_flag & BIT(0)) {       /* rs485 */
+                       if (uart_flag & BIT(1)) /* Inv */
+                               port_priv->port_pin_data.eForceUartMode =
+                                   eModeRS485;
+                       else
+                               port_priv->port_pin_data.eForceUartMode =
+                                   eModeRS485_1;
+               } else
+                       port_priv->port_pin_data.eForceUartMode = eModeRS232;
+
+               break;
+       }
+
+       if ((gpio_mode >= 0) && (gpio_mode < 8)) {
+               port_priv->port_pin_data.eGPIOMode = gpio_mode;
+               dev_dbg(&port->dev, "gpio set to %d\n", gpio_mode);
+       } else {
+               port_priv->port_pin_data.eGPIOMode = eModeRS232;
+               dev_info(&port->dev, "unknown gpio %d, setting to %d\n",
+                        gpio_mode, eModeRS232);
+       }
+
+       status =
+           f81534_switch_gpio_mode(port, port_priv->port_pin_data.eGPIOMode);
+       if (status) {
+               dev_err(&port->dev,
+                       "%s: f81534_switch_gpio_mode failed!! status:%d\n",
+                       __func__, status);
+               return status;
+       }
+
+       return 0;
+}
+
+static void dump_configure(struct usb_serial *serial)
+{
+       unsigned char transceiver, mode;
+       int count;
+       int index;
+       int gpio_address, uart_address;
+       struct f81534_serial_private *serial_priv = usb_get_serial_data(serial);
+
+       index = serial_priv->custom_idx;
+
+       for (count = 0; count < 4; ++count) {
+               if (index == F81534_CUSTOM_NO_CUSTOM_DATA) {
+                       uart_address = F81534_RESERVE_ADDRESS_START + count;
+                       gpio_address = F81534_RESERVE_ADDRESS_START + count + 4;
+               } else {
+
+                       /* if had custom setting, override
+                        * 1st byte is a indicater.
+                        * 0xff is empty, 0x0f is had data.
+                        * read and skip with 1st data.
+                        */
+
+                       uart_address = F81534_CUSTOM_ADDRESS_START +
+                           F81534_CUSTOM_DATA_SIZE * index + count + 1;
+
+                       gpio_address = F81534_CUSTOM_ADDRESS_START +
+                           F81534_CUSTOM_DATA_SIZE * index + count + 4 + 1;
+               }
+
+               f81534_read_data(serial, uart_address, 1, &transceiver);
+               f81534_read_data(serial, gpio_address, 1, &mode);
+
+               dev_info(&serial->dev->dev,
+                        "%s: port:%d uart_flag:%x gpio:%x\n", __func__,
+                        count, transceiver, mode);
+       }
+}
+
+static int f81534_attach(struct usb_serial *serial)
+{
+       struct f81534_serial_private *serial_priv = usb_get_serial_data(serial);
+       int status = 0;
+       int i;
+       int offset;
+       int num_port = serial->num_ports;
+
+       serial_priv->serial = serial;
+       memset(serial_priv->port_mapping, F81534_UNUSED_PORT,
+              sizeof(serial_priv->port_mapping));
+
+       switch (num_port) {
+       case eIC_F81532:
+       case eIC_F81534:
+               serial_priv->ic_type = num_port;
+               dev_info(&serial->dev->dev, "%s detected\n",
+                        m_ic_name[num_port]);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < F81534_NUM_PORT; ++i)
+               serial_priv->port_mapping[i] = i;
+
+       switch (num_port) {
+       case 4:
+               break;
+       case 2:
+               serial_priv->port_mapping[1] = 3;
+               serial_priv->port_mapping[2] = F81534_UNUSED_PORT;
+               serial_priv->port_mapping[3] = F81534_UNUSED_PORT;
+               break;
+       case 1:
+               serial_priv->port_mapping[1] = F81534_UNUSED_PORT;
+               serial_priv->port_mapping[2] = F81534_UNUSED_PORT;
+               serial_priv->port_mapping[3] = F81534_UNUSED_PORT;
+               break;
+       default:
+               dev_err(&serial->dev->dev,
+                       "%s: Cant determine ports: %d, error!!!\n", __func__,
+                       num_port);
+               status = -EINVAL;
+               goto failed;
+       }
+
+       for (i = 0; i < F81534_NUM_PORT; ++i) {
+               /* clear fifo when plug in */
+               f81534_setregister(serial->dev, i, FIFO_CONTROL_REGISTER, 0xc7);
+
+               status = f81534_get_normal_register(serial->dev, 0x5a00 + i,
+                                                   &serial_priv->shadowMSR[i]);
+               if (status) {
+                       dev_err(&serial->dev->dev,
+                               "%s f81534_get_normal_register:%x failed\n",
+                               __func__, 0x5a00 + i);
+                       goto failed;
+               }
+
+               serial_priv->msr_time[i] = jiffies;
+       }
+
+       spin_lock_init(&serial_priv->write_urb_lock);
+       spin_lock_init(&serial_priv->msr_lock);
+       mutex_init(&serial_priv->msr_mutex);
+       mutex_init(&serial_priv->updating_mutex);
+
+       status = f81534_setup_urbs(serial);
+       if (status != 0)
+               goto failed;
+
+       status = f81534_read_data(serial,
+                               F81534_RESERVE_ADDRESS_START,
+                               F81534_RESERVE_SIZE,
+                               serial_priv->reserve_data);
+       if (status) {
+               dev_err(&serial->dev->dev, "%s read reserve data failed\n",
+                       __func__);
+               goto failed;
+       }
+
+       /* if had custom setting, override
+        * 1st byte is a indicater, 0xff is empty, 0x0f is had data
+        * skip with 1st data
+        */
+
+       if (serial_priv->custom_idx == F81534_CUSTOM_NO_CUSTOM_DATA)
+               return 0;
+
+       offset = F81534_CUSTOM_ADDRESS_START +
+                       F81534_CUSTOM_DATA_SIZE * serial_priv->custom_idx + 1;
+       /* only read 8 bytes for mode & GPIO */
+       status = f81534_read_data(serial,
+                       offset,
+                       sizeof(serial_priv->reserve_data),
+                       serial_priv->reserve_data);
+       if (status) {
+               dev_err(&serial->dev->dev,
+                       "%s: get custom data failed, idx:%d, status:%d!!\n",
+                       __func__, serial_priv->custom_idx, status);
+               goto failed;
+       }
+
+       return 0;
+
+failed:
+       kfree(serial_priv);
+       return status;
+}
+
+static ssize_t uart_mode_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       int status = 0;
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+
+       status = mutex_lock_interruptible(&serial_priv->updating_mutex);
+       if (status) {
+               dev_info(&port->dev, "%s: interrupted!\n", __func__);
+               return status;
+       }
+
+       switch (port_priv->port_pin_data.eForceUartMode) {
+       case eModeRS232:
+               status = sprintf(buf, "eModeRS232\n");
+               break;
+       case eModeRS485:
+               status = sprintf(buf, "eModeRS485\n");
+               break;
+       case eModeRS485_1:
+               status = sprintf(buf, "eModeRS485_1\n");
+               break;
+       default:
+               status = -EINVAL;
+               dev_err(dev, "%s error!!\n", __func__);
+               break;
+       }
+
+       mutex_unlock(&serial_priv->updating_mutex);
+       f81534_wakeup_all_port(port->serial);
+
+       return status;
+}
+
+static ssize_t uart_mode_store(struct device *dev,
+                              struct device_attribute *attr, const char *buf,
+                              size_t count)
+{
+       struct usb_serial_port *serial_port = to_usb_serial_port(dev);
+       struct f81534_port_private *port_priv =
+           usb_get_serial_port_data(serial_port);
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(serial_port->serial);
+       struct usb_device *usb_dev = serial_port->serial->dev;
+       u16 device_port = f81534_port_to_phy_index(serial_port);
+       int index = 0;
+       int status;
+
+       status = mutex_lock_interruptible(&serial_priv->updating_mutex);
+       if (status) {
+               dev_info(&serial_port->dev, "%s: interrupted!\n", __func__);
+               return status;
+       }
+
+       if (!count) {
+               dev_err(dev, "%s: count error\n", __func__);
+               status = -EINVAL;
+               goto finish;
+       }
+
+       index = buf[0] - '0';
+
+       if ((index < eModeRS232) || (index > eModeRS485_1)) {
+               status = -EINVAL;
+               goto finish;
+       }
+
+       status = f81534_set_port_config(usb_dev, device_port, serial_port,
+                                       port_priv->currentBaudRate,
+                                       port_priv->shadowLCR);
+       if (status) {
+               dev_err(dev, "%s: set port error!!\n", __func__);
+               goto finish;
+       }
+
+       status = f81534_save_configure_data(serial_port);
+       if (status) {
+               dev_err(dev, "%s:save configure error!!\n", __func__);
+               goto finish;
+       }
+
+       port_priv->port_pin_data.eForceUartMode = index;
+       status = count;
+
+finish:
+       mutex_unlock(&serial_priv->updating_mutex);
+       f81534_wakeup_all_port(serial_port->serial);
+       return status;
+}
+
+static ssize_t gpio_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       int status = 0;
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+
+       status = mutex_lock_interruptible(&serial_priv->updating_mutex);
+       if (status) {
+               dev_info(&port->dev, "%s: interrupted!\n", __func__);
+               return status;
+       }
+
+       switch (port_priv->port_pin_data.eGPIOMode) {
+       case eModeRS232:
+               status = sprintf(buf, "001\n");
+               break;
+       case eModeRS485:
+               status = sprintf(buf, "010\n");
+               break;
+       case eModeRS485_1:
+               status = sprintf(buf, "011\n");
+               break;
+       case eModeRS422:
+               status = sprintf(buf, "000\n");
+               break;
+       case eModeRS422_term:
+               status = sprintf(buf, "100\n");
+               break;
+       case eModeRS232_coexist:
+               status = sprintf(buf, "101\n");
+               break;
+       case eModeRS485_1_term:
+               status = sprintf(buf, "110\n");
+               break;
+       case eModeShutdown:
+               status = sprintf(buf, "111\n");
+               break;
+       default:
+               status = -EINVAL;
+               dev_err(dev, "%s error!!\n", __func__);
+               break;
+       }
+
+       mutex_unlock(&serial_priv->updating_mutex);
+       f81534_wakeup_all_port(port->serial);
+
+       return status;
+}
+
+static ssize_t gpio_store(struct device *dev,
+                         struct device_attribute *attr, const char *buf,
+                         size_t count)
+{
+       struct usb_serial_port *serial_port = to_usb_serial_port(dev);
+       struct f81534_port_private *port_priv =
+           usb_get_serial_port_data(serial_port);
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(serial_port->serial);
+       int index = 0;
+       int status = 0;
+
+       status = mutex_lock_interruptible(&serial_priv->updating_mutex);
+       if (status) {
+               dev_info(&serial_port->dev, "%s: interrupted!\n", __func__);
+               goto finish;
+       }
+
+       if (!count) {
+               dev_err(dev, "%s: count error\n", __func__);
+               status = -EINVAL;
+               goto finish;
+       }
+
+       index = buf[0] - '0';
+
+       if (index > eModeShutdown) {
+               status = -EINVAL;
+               goto finish;
+       }
+
+       status = f81534_switch_gpio_mode(serial_port, index);
+       if (status) {
+               dev_err(dev, "%s: set gpio error!!\n", __func__);
+               goto finish;
+       }
+
+       port_priv->port_pin_data.eGPIOMode = index;
+
+       status = f81534_save_configure_data(serial_port);
+       if (status)
+               goto finish;
+
+       status = count;
+
+finish:
+       mutex_unlock(&serial_priv->updating_mutex);
+       f81534_wakeup_all_port(serial_port->serial);
+
+       return status;
+}
+
+static DEVICE_ATTR_RW(uart_mode);
+static DEVICE_ATTR_RW(gpio);
+
+static int f81534_port_probe(struct usb_serial_port *port)
+{
+       struct usb_serial *serial = port->serial;
+       struct f81534_port_private *port_priv = NULL;
+       int status = 0;
+
+       status |= device_create_file(&port->dev, &dev_attr_uart_mode);
+       status |= device_create_file(&port->dev, &dev_attr_gpio);
+
+       dev_dbg(&port->dev, "%s f81534_port_to_phy_index(port): %d",
+               __func__, f81534_port_to_phy_index(port));
+
+       if (status)
+               return -EPERM;
+
+       port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+
+       if (!port_priv)
+               return -ENOMEM;
+
+       usb_set_serial_port_data(port, port_priv);
+       spin_lock_init(&port_priv->lock);
+
+       port_priv->port = port;
+
+       status = f81534_load_configure_data(port);
+       if (status)
+               return status;
+
+       if ((serial->num_ports - 1) == f81534_port_index(port)) {
+               f81534_save_configure_data(port);
+               dump_configure(serial);
+       }
+
+       status = f81534_set_port_mode(port,
+                                     port_priv->port_pin_data.eForceUartMode);
+       if (status < 0) {
+               dev_err(&port->dev, "%s - initial setup failed (%i)\n",
+                       __func__, f81534_port_to_phy_index(port));
+               goto port_fail;
+       }
+       return 0;
+
+port_fail:
+
+       kfree(port_priv);
+       return status;
+}
+
+static int f81534_port_remove(struct usb_serial_port *port)
+{
+       struct f81534_port_private *port_priv;
+
+       dev_dbg(&port->dev, "%s\n", __func__);
+
+       device_remove_file(&port->dev, &dev_attr_uart_mode);
+       device_remove_file(&port->dev, &dev_attr_gpio);
+
+       port_priv = usb_get_serial_port_data(port);
+       kfree(port_priv);
+
+       return 0;
+}
+
+static int f81534_tiocmget(struct tty_struct *tty)
+{
+       struct usb_serial_port *port = tty->driver_data;
+       struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+
+       int r = 0;
+       int index = f81534_port_to_phy_index(port);
+       int count = 5, result;
+       unsigned long current_jiffies = jiffies + 1;
+       unsigned long flags = 0;
+       u8 msr = 0;
+
+       /* to try: read MSR again here? */
+
+       while (count--) {
+               mutex_lock(&serial_priv->msr_mutex);
+               spin_lock_irqsave(&serial_priv->msr_lock, flags);
+               result =
+                   time_after(current_jiffies, serial_priv->msr_time[index]);
+               msr = serial_priv->shadowMSR[index];
+               spin_unlock_irqrestore(&serial_priv->msr_lock, flags);
+               mutex_unlock(&serial_priv->msr_mutex);
+
+               if (!result)
+                       break;
+
+               /* wait for delayed MSR change from bulk-in */
+               if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
+                       dev_info(&port->dev, "%s: breaked !!\n", __func__);
+                       break;
+               }
+       }
+
+       r = (port_priv->shadowMCR & UART_MCR_DTR ? TIOCM_DTR : 0) |
+           (port_priv->shadowMCR & UART_MCR_RTS ? TIOCM_RTS : 0) |
+           (msr & UART_MSR_CTS ? TIOCM_CTS : 0) |
+           (msr & UART_MSR_DCD ? TIOCM_CAR : 0) |
+           (msr & UART_MSR_RI ? TIOCM_RI : 0) |
+           (msr & UART_MSR_DSR ? TIOCM_DSR : 0);
+
+       return r;
+}
+
+static int f81534_tiocmset(struct tty_struct *tty,
+                          unsigned int set, unsigned int clear)
+{
+       struct f81534_port_private *port_priv;
+
+       port_priv = usb_get_serial_port_data(tty->driver_data);
+
+       dev_dbg(&port_priv->port->dev, "%s set:%x, clear:%x\n",
+               __func__, set, clear);
+
+       return f81534_update_mctrl(port_priv->port, set, clear);
+}
+
+static void f81534_break_ctl(struct tty_struct *tty, int break_state)
+{
+       struct usb_serial_port *port = tty->driver_data;
+       struct f81534_port_private *port_priv;
+       u16 val;
+
+       port_priv = usb_get_serial_port_data(port);
+       val = (break_state == -1) ? 1 : 0;
+}
+
+static void f81534_dtr_rts(struct usb_serial_port *port, int on)
+{
+       struct usb_device *dev = port->serial->dev;
+
+       if (!on) {
+               if (f81534_setregister(dev, f81534_port_to_phy_index(port),
+                                      MODEM_CONTROL_REGISTER, 8) < 0) {
+                       dev_err(&port->dev, "%s-error from flowcontrol urb\n",
+                               __func__);
+                       return;
+               }
+       }
+
+       /* drop RTS and DTR */
+       if (on)
+               f81534_update_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0);
+       else
+               f81534_update_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
+}
+
+static void f81534_update_msr(struct usb_serial_port *port, unsigned char *ch)
+{
+       u8 newMSR = (u8) *ch;
+
+       if (newMSR & UART_MSR_ANY_DELTA) {
+               /* update input line counters */
+               if (newMSR & UART_MSR_DCTS)
+                       port->icount.cts++;
+               if (newMSR & UART_MSR_DDSR)
+                       port->icount.dsr++;
+               if (newMSR & UART_MSR_DDCD)
+                       port->icount.dcd++;
+               if (newMSR & UART_MSR_TERI)
+                       port->icount.rng++;
+
+               wake_up_interruptible(&port->port.delta_msr_wait);
+       }
+}
+
+static void f81534_update_lsr(struct usb_serial_port *port, unsigned char *ch)
+{
+       struct f81534_port_private *port_priv;
+       struct async_icount *icount = &port->icount;
+       unsigned long flags;
+       u8 newLSR = (u8) *ch;
+
+       port_priv = usb_get_serial_port_data(port);
+
+       if (newLSR & UART_LSR_BI)
+               newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI);
+
+       spin_lock_irqsave(&port_priv->lock, flags);
+       port_priv->shadowLSR = newLSR;
+       spin_unlock_irqrestore(&port_priv->lock, flags);
+
+       if (newLSR & UART_LSR_BRK_ERROR_BITS) {
+
+               if (newLSR & UART_LSR_BI)
+                       icount->brk++;
+
+               if (newLSR & UART_LSR_OE)
+                       icount->overrun++;
+
+               if (newLSR & UART_LSR_PE)
+                       icount->parity++;
+
+               if (newLSR & UART_LSR_FE)
+                       icount->frame++;
+       }
+}
+
+static int f81534_write_room(struct tty_struct *tty)
+{
+       struct usb_serial_port *port = tty->driver_data;
+       struct f81534_port_private *port_priv;
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+       int port_num = f81534_port_to_phy_index(port);
+       unsigned long flags = 0;
+       int r;
+
+       port_priv = usb_get_serial_port_data(port);
+
+       spin_lock_irqsave(&serial_priv->write_urb_lock, flags);
+
+       if (serial_priv->phy_port_in_use[port_num])
+               r = 0;
+       else
+               r = m_F81534_MAX_TX_SIZE;
+
+       spin_unlock_irqrestore(&serial_priv->write_urb_lock, flags);
+
+       return r;
+}
+
+static int f81534_write(struct tty_struct *tty,
+                       struct usb_serial_port *port,
+                       const unsigned char *buf, int count)
+{
+       struct f81534_serial_private *serial_priv =
+           usb_get_serial_data(port->serial);
+       struct urb *write_urb;
+       unsigned char *data;
+       unsigned long flags;
+       int status;
+       int bytes_out = 0;
+       const unsigned char *current_position = buf;
+       int port_num = f81534_port_to_phy_index(port);
+       int updating_data = mutex_is_locked(&serial_priv->updating_mutex);
+
+       if (serial_priv->write_urb[port_num] == NULL) {
+               dev_err(&port->dev, "%s - no output urb\n", __func__);
+               return 0;
+       }
+
+       if (updating_data)
+               return 0;
+
+       if (serial_priv->phy_port_in_use[port_num])
+               return 0;
+
+       write_urb = serial_priv->write_urb[port_num];
+       count = min(count, m_F81534_MAX_TX_SIZE);
+       data = write_urb->transfer_buffer;
+
+       spin_lock_irqsave(&serial_priv->write_urb_lock, flags);
+
+       if (serial_priv->phy_port_in_use[port_num])
+               goto write_out;
+
+       data[0] = 0;
+       data[128] = 1;
+       data[256] = 2;
+       data[384] = 3;
+       data[128 * port_num + 0] = port_num;
+       data[128 * port_num + 1] = 2;
+       data[128 * port_num + 2] = count;
+       data[128 * port_num + 3] = 0;
+       memcpy(&data[128 * port_num + 4], current_position, count);
+
+       write_urb->transfer_buffer_length = F81534_WRITE_BUFFER_SIZE;
+
+       status = usb_submit_urb(write_urb, GFP_ATOMIC);
+       if (status == 0) {
+               serial_priv->phy_port_in_use[port_num] = true;
+               bytes_out += count;
+       }
+
+write_out:
+       spin_unlock_irqrestore(&serial_priv->write_urb_lock, flags);
+
+       return bytes_out;
+}
+
+#ifdef CONFIG_PM
+static int f81534_usb_serial_suspend(struct usb_serial *serial,
+                       pm_message_t message)
+{
+       /* STD => PM_EVENT_FREEZE 1 */
+       /* STR => PM_EVENT_SUSPEND 2 */
+
+       dev_dbg(&serial->dev->dev, "%s message:%d\n", __func__, message.event);
+
+       if (message.event == PM_EVENT_SUSPEND)
+               f81534_free_urbs(serial);
+
+       return 0;
+}
+
+static int f81534_usb_serial_resume(struct usb_serial *serial)
+{
+       int status;
+       int i;
+       int phy;
+
+       dev_dbg(&serial->dev->dev, "%s\n", __func__);
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               struct f81534_port_private *port_priv =
+                   usb_get_serial_port_data(serial->port[i]);
+
+               phy = f81534_logic_to_phy_port(serial, i);
+
+               BUG_ON(phy == F81534_UNUSED_PORT);
+
+               f81534_set_port_config(serial->dev, phy, serial->port[i],
+                                      port_priv->currentBaudRate,
+                                      port_priv->shadowLCR);
+       }
+
+       status = f81534_setup_urbs(serial);
+
+       return status;
+}
+#endif
+
+static struct usb_serial_driver f81534_device = {
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = "F81534",
+                  },
+       .description = DRIVER_DESC,
+       .id_table = id_table,
+       .open = f81534_open,
+       .close = f81534_close,
+       .write = f81534_write,
+       .write_room = f81534_write_room,
+       .calc_num_ports = f81534_calc_num_ports,
+       .attach = f81534_attach,
+       .release = f81534_release,
+       .disconnect = f81534_disconnect,
+       .port_probe = f81534_port_probe,
+       .port_remove = f81534_port_remove,
+       .dtr_rts = f81534_dtr_rts,
+       .break_ctl = f81534_break_ctl,
+       .tiocmiwait = usb_serial_generic_tiocmiwait,
+       .get_icount = usb_serial_generic_get_icount,
+       .ioctl = f81534_ioctl,
+       .tiocmget = f81534_tiocmget,
+       .tiocmset = f81534_tiocmset,
+       .set_termios = f81534_set_termios,
+
+#ifdef CONFIG_PM
+       .resume = f81534_usb_serial_resume,
+       .suspend = f81534_usb_serial_suspend,
+#endif
+
+};
+
+static struct usb_serial_driver *const serial_drivers[] = {
+       &f81534_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Peter Hong <peter_h...@fintek.com.tw>");
+MODULE_AUTHOR("Tom Tsai <tom_t...@fintek.com.tw>");
+MODULE_LICENSE("GPL");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to