On Fri, Jan 30, 2015 at 02:13:37PM +0800, Peter Hung wrote: > The F81232 interrupt ep will continuously report IIR register value. > We had implement the interrupt callback to read IIR, If noticed with > MSR change, we will call worker to read MSR later. > > Signed-off-by: Peter Hung <hpeter+linux_kernel@xxxxxxxxx> > --- > drivers/usb/serial/f81232.c | 114 +++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 107 insertions(+), 7 deletions(-) > > diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c > index 9ef9775..274120d 100644 > --- a/drivers/usb/serial/f81232.c > +++ b/drivers/usb/serial/f81232.c > @@ -23,6 +23,7 @@ > #include <linux/uaccess.h> > #include <linux/usb.h> > #include <linux/usb/serial.h> > +#include <linux/serial_reg.h> > > static const struct usb_device_id id_table[] = { > { USB_DEVICE(0x1934, 0x0706) }, > @@ -44,23 +45,112 @@ MODULE_DEVICE_TABLE(usb, id_table); > #define UART_OVERRUN_ERROR 0x40 > #define UART_CTS 0x80 Now that your including serial_req and using the standard register masks, you should remove the old (incorrect ones) at some point. Most are left unused after the whole series has been applied (except UART_DCD and that looks like a bug). > > +#define REGISTER_REQUEST 0xA0 > +#define GET_REGISTER 0xc0 > +#define SET_REGISTER 0x40 Add a F81232-prefix to these (and other driver specific defines), and a new line before the time out. > +#define F81232_USB_TIMEOUT 3000 > + > +#define SERIAL_BASE_ADDRESS (0x0120) No parentheses. > +#define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS) Missing newline. > struct f81232_private { > spinlock_t lock; > u8 line_control; > u8 line_status; How about renaming this one modem_status? > + > + struct work_struct int_worker; Call this one interrupt_work instead. > + struct usb_serial_port *port; > }; > > +static inline int f81232_get_register(struct usb_device *dev, > + u16 reg, u8 *data) Let the compiler decide whether this should be inlined. Should should probably also pass the usb-serial port rather than usb_device and use &port->dev for the error message. > +{ > + int status; > + > + 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, > + "%s status: %d\n", __func__, status); dev_err. Is the line break needed still? > + } > + > + return status; > +} > + > +static void f81232_read_msr(struct f81232_private *priv) > +{ > + int status; > + unsigned long flags; > + u8 current_msr, old_msr; > + struct usb_device *dev = priv->port->serial->dev; > + struct tty_struct *tty; > + > + status = f81232_get_register(dev, MODEM_STATUS_REGISTER, ¤t_msr); > + No newline before checking the return value. Comment applies to whole series. > + if (status < 0) { > + dev_dbg(&dev->dev, "%s fail, status: %d\n", __func__, status); > + return; > + } You already logged the error in get_register, but use dev_err (and &port->dev) if you want this here. > + > + spin_lock_irqsave(&priv->lock, flags); > + old_msr = priv->line_status; > + spin_unlock_irqrestore(&priv->lock, flags); You never use old_msr so just drop this bit. > + > + if (current_msr & UART_MSR_ANY_DELTA) { Just return unless there has been a change and reduce the indentation below. > + tty = tty_port_tty_get(&priv->port->port); > + > + if (tty) { > + if (current_msr & UART_MSR_DDCD) { > + usb_serial_handle_dcd_change(priv->port, > + tty, current_msr & UART_MSR_DCD); > + } > + > + tty_kref_put(tty); > + } > + > + spin_lock_irqsave(&priv->lock, flags); > + priv->line_status = current_msr; > + spin_unlock_irqrestore(&priv->lock, flags); > + > + wake_up_interruptible(&priv->port->port.delta_msr_wait); > + } > + > + dev_dbg(&dev->dev, "%s: %x\n", __func__, priv->line_status); > +} Missing newline. > static void f81232_update_line_status(struct usb_serial_port *port, > unsigned char *data, > unsigned int actual_length) > { > - /* > - * FIXME: Update port->icount, and call > - * > - * wake_up_interruptible(&port->port.delta_msr_wait); > - * > - * on MSR changes. > - */ > + struct f81232_private *priv = usb_get_serial_port_data(port); > + struct usb_device *dev = port->serial->dev; Use &port->dev for debugging and drop this one. > + > + if (!actual_length) > + return; > + > + switch (data[0] & 0x07) { > + case 0x00: /* msr change */ > + dev_dbg(&dev->dev, "IIR: MSR Change: %x\n", data[0]); > + schedule_work(&priv->int_worker); > + break; > + I'd drop the newlines after break. > + case 0x02: /* tx-empty */ > + break; > + > + case 0x04: /* rx data available */ > + break; > + > + case 0x06: /* lsr change */ > + /* we can forget it. the LSR will read from bulk-in */ > + dev_dbg(&dev->dev, "IIR: LSR Change: %x\n", data[0]); > + break; > + } > } > > static void f81232_read_int_callback(struct urb *urb) > @@ -270,6 +360,14 @@ static int f81232_ioctl(struct tty_struct *tty, > return -ENOIOCTLCMD; > } > > +static void f81232_int_work_wq(struct work_struct *work) Rename this f81232_interrupt_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 +377,12 @@ 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; > } This already looks much better, thanks for resending. Johan -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html