USB: serial: pl2303: new device id for Chilitag
[pandora-kernel.git] / drivers / usb / serial / mct_u232.c
index ba0d287..8901b8d 100644 (file)
@@ -168,8 +168,6 @@ struct mct_u232_private {
        unsigned char        last_msr;      /* Modem Status Register */
        unsigned int         rx_flags;      /* Throttling flags */
        struct async_icount  icount;
-       wait_queue_head_t    msr_wait;  /* for handling sleeping while waiting
-                                               for msr change to happen */
 };
 
 #define THROTTLED              0x01
@@ -253,7 +251,7 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
                return -ENOMEM;
 
        divisor = mct_u232_calculate_baud_rate(serial, value, &speed);
-       put_unaligned_le32(cpu_to_le32(divisor), buf);
+       put_unaligned_le32(divisor, buf);
        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                                MCT_U232_SET_BAUD_RATE_REQUEST,
                                MCT_U232_SET_REQUEST_TYPE,
@@ -359,13 +357,16 @@ static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
                        MCT_U232_SET_REQUEST_TYPE,
                        0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE,
                        WDR_TIMEOUT);
-       if (rc < 0)
-               dev_err(&serial->dev->dev,
-                       "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
+       kfree(buf);
+
        dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
 
-       kfree(buf);
-       return rc;
+       if (rc < 0) {
+               dev_err(&serial->dev->dev,
+                       "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
+               return rc;
+       }
+       return 0;
 } /* mct_u232_set_modem_ctrl */
 
 static int mct_u232_get_modem_stat(struct usb_serial *serial,
@@ -384,9 +385,13 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial,
                        MCT_U232_GET_REQUEST_TYPE,
                        0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
                        WDR_TIMEOUT);
-       if (rc < 0) {
+       if (rc < MCT_U232_GET_MODEM_STAT_SIZE) {
                dev_err(&serial->dev->dev,
                        "Get MODEM STATus failed (error = %d)\n", rc);
+
+               if (rc >= 0)
+                       rc = -EIO;
+
                *msr = 0;
        } else {
                *msr = buf[0];
@@ -442,11 +447,16 @@ static int mct_u232_startup(struct usb_serial *serial)
        struct mct_u232_private *priv;
        struct usb_serial_port *port, *rport;
 
+       /* check first to simplify error handling */
+       if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) {
+               dev_err(&serial->dev->dev, "expected endpoint missing\n");
+               return -ENODEV;
+       }
+
        priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
        spin_lock_init(&priv->lock);
-       init_waitqueue_head(&priv->msr_wait);
        usb_set_serial_port_data(serial->port[0], priv);
 
        init_waitqueue_head(&serial->port[0]->write_wait);
@@ -555,31 +565,29 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
        unsigned int control_state;
        struct mct_u232_private *priv = usb_get_serial_port_data(port);
 
-       mutex_lock(&port->serial->disc_mutex);
-       if (!port->serial->disconnected) {
-               /* drop DTR and RTS */
-               spin_lock_irq(&priv->lock);
-               if (on)
-                       priv->control_state |= TIOCM_DTR | TIOCM_RTS;
-               else
-                       priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
-               control_state = priv->control_state;
-               spin_unlock_irq(&priv->lock);
-               mct_u232_set_modem_ctrl(port->serial, control_state);
-       }
-       mutex_unlock(&port->serial->disc_mutex);
+       spin_lock_irq(&priv->lock);
+       if (on)
+               priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+       else
+               priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+       control_state = priv->control_state;
+       spin_unlock_irq(&priv->lock);
+
+       mct_u232_set_modem_ctrl(port->serial, control_state);
 }
 
 static void mct_u232_close(struct usb_serial_port *port)
 {
        dbg("%s port %d", __func__, port->number);
 
-       if (port->serial->dev) {
-               /* shutdown our urbs */
-               usb_kill_urb(port->write_urb);
-               usb_kill_urb(port->read_urb);
-               usb_kill_urb(port->interrupt_in_urb);
-       }
+       /*
+        * Must kill the read urb as it is actually an interrupt urb, which
+        * generic close thus fails to kill.
+        */
+       usb_kill_urb(port->read_urb);
+       usb_kill_urb(port->interrupt_in_urb);
+
+       usb_serial_generic_close(port);
 } /* mct_u232_close */
 
 
@@ -674,7 +682,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
                tty_kref_put(tty);
        }
 #endif
-       wake_up_interruptible(&priv->msr_wait);
+       wake_up_interruptible(&port->delta_msr_wait);
        spin_unlock_irqrestore(&priv->lock, flags);
 exit:
        retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -895,13 +903,17 @@ static int  mct_u232_ioctl(struct tty_struct *tty,
                cprev = mct_u232_port->icount;
                spin_unlock_irqrestore(&mct_u232_port->lock, flags);
                for ( ; ; ) {
-                       prepare_to_wait(&mct_u232_port->msr_wait,
+                       prepare_to_wait(&port->delta_msr_wait,
                                        &wait, TASK_INTERRUPTIBLE);
                        schedule();
-                       finish_wait(&mct_u232_port->msr_wait, &wait);
+                       finish_wait(&port->delta_msr_wait, &wait);
                        /* see if a signal did it */
                        if (signal_pending(current))
                                return -ERESTARTSYS;
+
+                       if (port->serial->disconnected)
+                               return -EIO;
+
                        spin_lock_irqsave(&mct_u232_port->lock, flags);
                        cnow = mct_u232_port->icount;
                        spin_unlock_irqrestore(&mct_u232_port->lock, flags);