usb: serial: add register map for F81232
Subsystems (2)
PATCH v2 1/4 usb: serial: add register map for F81232
Add register map for F81232. and add some function to operating this device. etc. f81232_get_register()/f81232_set_register() to work with USB control point. and worker f81232_int_work_wq() to read MSR when IIR acquired.
Signed-off-by Peter Hung <[email protected]>
--- drivers/usb/serial/f81232.c | 229 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 214 insertions(+), 15 deletions(-)
drivers/usb/serial/f81232.c +214 -15
@@ -23,6 +23,8 @@#include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/serial_reg.h> +#include <linux/version.h> static const struct usb_device_id id_table[] = { {USB_DEVICE (0x1934 ,0x0706 ) },
@@ -37,19 +39,197 @@ MODULE_DEVICE_TABLE(usb, id_table);#define UART_STATE_TRANSIENT_MASK 0x74#define UART_DCD 0x01#define UART_DSR 0x02 -#define UART_BREAK_ERROR 0x04#define UART_RING 0x08 -#define UART_FRAME_ERROR 0x10 -#define UART_PARITY_ERROR 0x20 -#define UART_OVERRUN_ERROR 0x40#define UART_CTS 0x80 +#define UART_BREAK_ERROR 0x10 +#define UART_FRAME_ERROR 0x08 +#define UART_PARITY_ERROR 0x04 +#define UART_OVERRUN_ERROR 0x02 +#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) + +#define REGISTER_REQUEST 0xA0 +#define GET_REGISTER 0xc0 +#define SET_REGISTER 0x40 +#define F81232_USB_TIMEOUT 1000 +#define F81232_USB_RETRY 20 + +#define SERIAL_BASE_ADDRESS (0x0120) +#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) +struct f81232_private {spinlock_t lock;u8 line_control;u8 line_status; + +struct work_struct int_worker; +struct usb_serial_port *port; }; +static inline int calc_baud_divisor (u32 baudrate) +{ +u32 divisor, rem; + + divisor =115200L / baudrate; + rem =115200L % baudrate; + +/* Round to nearest divisor */ +if (((rem *2 ) >= baudrate) && (baudrate !=110 )) + divisor++; + +return divisor; +} + + +static inline int f81232_get_register (struct usb_device *dev, +u16 reg,u8 *data) +{ +int status; +int i =F81232_USB_RETRY ; + +while (i--) { + status =usb_control_msg (dev, +usb_rcvctrlpipe (dev,0 ), +REGISTER_REQUEST , +GET_REGISTER , + reg, +0 , + data, +sizeof (*data), +F81232_USB_TIMEOUT ); + +if (status <0 ) { +dev_dbg (&dev->dev, +"f81232_get_register status: %d, fail:%d\n" , + status, i); + }else +break ; + } + +return status; +} + + +static inline int f81232_set_register (struct usb_device *dev, +u16 reg,u8 data) +{ +int status; +int i =F81232_USB_RETRY ; + +while (i--) { + status =usb_control_msg (dev, +usb_sndctrlpipe (dev,0 ), +REGISTER_REQUEST , +SET_REGISTER , + reg, +0 , + &data, +1 , +F81232_USB_TIMEOUT ); + +if (status <0 ) +dev_dbg (&dev->dev, +"f81232_set_register status: %d, fail:%d\n" , + status, i); +else +break ; + } + +return status; +} + +static void f81232_read_msr (struct f81232_private *priv) +{ +unsigned long flags; +u8 current_msr, old_msr; +struct usb_device *dev = priv->port->serial->dev; + +f81232_get_register (dev,MODEM_STATUS_REGISTER , ¤t_msr); + +spin_lock_irqsave (&priv->lock, flags); + old_msr = priv->line_status; +spin_unlock_irqrestore (&priv->lock, flags); + + +if ((current_msr &0xf0 ) ^ (old_msr &0xf0 )) { +if (priv->port->port.tty) +usb_serial_handle_dcd_change (priv->port, + priv->port->port.tty, + current_msr &UART_MSR_DCD ); + +spin_lock_irqsave (&priv->lock, flags); + priv->line_status = current_msr; +spin_unlock_irqrestore (&priv->lock, flags); + } + +dev_dbg (&dev->dev,"f81232_read_msr: %x\n" , priv->line_status); +} + + +static inline int update_mctrl (struct f81232_private *port_priv, +unsigned int set,unsigned int clear) +{ +struct usb_device *dev = port_priv->port->serial->dev; +u8 urb_value; +int status; +unsigned long flags; + +if (((set | clear) & (TIOCM_DTR |TIOCM_RTS )) ==0 ) { +dev_dbg (&dev->dev,"update_mctrl fail - DTR|RTS %d\n" , + __LINE__); +return 0 ;/* no change */ + } + + + clear &= ~set;/* 'set' takes precedence over 'clear' */ + urb_value =8 | port_priv->line_control; + + +if (clear &TIOCM_DTR ) { + urb_value &= ~UART_MCR_DTR ; +dev_dbg (&dev->dev,"clear DTR\n" ); + } + +if (clear &TIOCM_RTS ) { + urb_value &= ~UART_MCR_RTS ; +dev_dbg (&dev->dev,"clear RTS\n" ); + } + +if (set &TIOCM_DTR ) { + urb_value |=UART_MCR_DTR ; +dev_dbg (&dev->dev,"set DTR\n" ); + } + +if (set &TIOCM_RTS ) { + urb_value |=UART_MCR_RTS ; +dev_dbg (&dev->dev,"set RTS\n" ); + } + +dev_dbg (&dev->dev,"update_mctrl n:%x o:%x\n" , urb_value, + port_priv->line_control); + + status =f81232_set_register (dev,MODEM_CONTROL_REGISTER , urb_value); + +if (status <0 ) { +dev_dbg (&dev->dev,"MODEM_CONTROL_REGISTER < 0\n" ); + }else { +spin_lock_irqsave (&port_priv->lock, flags); + port_priv->line_control = urb_value; +spin_unlock_irqrestore (&port_priv->lock, flags); + } + +f81232_read_msr (port_priv); + +return status; +}static void f81232_update_line_status (struct usb_serial_port *port,unsigned char *data,unsigned int actual_length)
@@ -201,8 +381,8 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) result =usb_submit_urb (port->interrupt_in_urb,GFP_KERNEL );if (result) { -dev_err (&port->dev,"%s - failed submitting interrupt urb," -" error %d\n" , __func__, result); +dev_err (&port->dev,"failed submitting interrupt urb, error %d\n" , + result);return result; }
@@ -241,6 +421,7 @@ static void f81232_dtr_rts(struct usb_serial_port *port, int on)static int f81232_carrier_raised (struct usb_serial_port *port) {struct f81232_private *priv =usb_get_serial_port_data (port); +if (priv->line_status &UART_DCD )return 1 ;return 0 ;
@@ -254,13 +435,18 @@ static int f81232_ioctl(struct tty_struct *tty,switch (cmd) {case TIOCGSERIAL : -memset (&ser,0 ,sizeof ser); - ser.type =PORT_16654 ; +memset (&ser,0 ,sizeof (ser)); + ser.flags =ASYNC_SKIP_TEST |ASYNC_AUTO_IRQ ; + ser.xmit_fifo_size = port->bulk_out_size; + ser.close_delay =5 *HZ ; + ser.closing_wait =30 *HZ ; + + ser.type =PORT_16550A ; ser.line = port->minor; ser.port = port->port_number; - ser.baud_base =460800 ; + ser.baud_base =115200 ; -if (copy_to_user ((void __user *)arg, &ser,sizeof ser)) +if (copy_to_user ((void __user *)arg, &ser,sizeof (ser)))return -EFAULT ;return 0 ;
@@ -270,6 +456,17 @@ static int f81232_ioctl(struct tty_struct *tty,return -ENOIOCTLCMD ; } + + + +static void f81232_int_work_wq (struct work_struct *work) +{ +struct f81232_private *priv = + container_of(work, struct f81232_private, int_worker); + +f81232_read_msr (priv); +} +static int f81232_port_probe (struct usb_serial_port *port) {struct f81232_private *priv;
@@ -279,10 +476,11 @@ static int f81232_port_probe(struct usb_serial_port *port)return -ENOMEM ;spin_lock_init (&priv->lock); +INIT_WORK (&priv->int_worker, f81232_int_work_wq);usb_set_serial_port_data (port, priv); - port->port.drain_delay =256 ; + priv->port = port;return 0 ; }
@@ -304,11 +502,11 @@ static struct usb_serial_driver f81232_device = { }, .id_table = id_table, .num_ports = 1, - .bulk_in_size = 256, - .bulk_out_size = 256, + .bulk_in_size = 64, + .bulk_out_size = 64, .open = f81232_open, .close = f81232_close, - .dtr_rts = f81232_dtr_rts, + .dtr_rts = f81232_dtr_rts, .carrier_raised = f81232_carrier_raised, .ioctl = f81232_ioctl, .break_ctl = f81232_break_ctl,
@@ -330,5 +528,6 @@ static struct usb_serial_driver * const serial_drivers[] = {module_usb_serial_driver (serial_drivers, id_table);MODULE_DESCRIPTION ("Fintek F81232 USB to serial adaptor driver" ); -MODULE_AUTHOR ("Greg Kroah-Hartman <[email protected]" ); +MODULE_AUTHOR ("Greg Kroah-Hartman <[email protected]>" ); +MODULE_AUTHOR ("Peter Hong <[email protected]>" );MODULE_LICENSE ("GPL v2" );
Signature · 1 line
1.9.1