From 59c82d12aa898c2f373b7e44bdea0b7c762ceccc Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 30 Sep 2009 11:57:24 +0000 Subject: usb: r8a66597-udc unaligned fifo fix Rework the r8a66597-udc fifo code to avoid unaligned accesses. Without this patch unaligned exceptions will degrade the USB performance. The exceptions come from the fact that the usb fifo data buffers may be misaligned. This patch updates the fifo access code to only use insl()/outsl() and insw()/outsw() in the case of properly aligned data buffers. The fallback case is that inl()/inw() are used for misaligned buffer reads together with outb() that is used for misaligned buffer writes. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/usb/gadget/r8a66597-udc.h | 105 ++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 43 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 03087e7b9190..9a537aa07968 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -131,31 +131,48 @@ static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset) } static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, - unsigned long offset, u16 *buf, + unsigned long offset, + unsigned char *buf, int len) { + unsigned long fifoaddr = r8a66597->reg + offset; + unsigned int data; + int i; + if (r8a66597->pdata->on_chip) { - unsigned long fifoaddr = r8a66597->reg + offset; - unsigned long count; - union { - unsigned long dword; - unsigned char byte[4]; - } data; - unsigned char *pb; - int i; - - count = len / 4; - insl(fifoaddr, buf, count); - - if (len & 0x00000003) { - data.dword = inl(fifoaddr); - pb = (unsigned char *)buf + count * 4; - for (i = 0; i < (len & 0x00000003); i++) - pb[i] = data.byte[i]; + /* 32-bit accesses for on_chip controllers */ + + /* aligned buf case */ + if (len >= 4 && !((unsigned long)buf & 0x03)) { + insl(fifoaddr, buf, len / 4); + buf += len & ~0x03; + len &= 0x03; + } + + /* unaligned buf case */ + for (i = 0; i < len; i++) { + if (!(i & 0x03)) + data = inl(fifoaddr); + + buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; } } else { - len = (len + 1) / 2; - insw(r8a66597->reg + offset, buf, len); + /* 16-bit accesses for external controllers */ + + /* aligned buf case */ + if (len >= 2 && !((unsigned long)buf & 0x01)) { + insw(fifoaddr, buf, len / 2); + buf += len & ~0x01; + len &= 0x01; + } + + /* unaligned buf case */ + for (i = 0; i < len; i++) { + if (!(i & 0x01)) + data = inw(fifoaddr); + + buf[i] = (data >> ((i & 0x01) * 8)) & 0xff; + } } } @@ -166,38 +183,40 @@ static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, } static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, - unsigned long offset, u16 *buf, + unsigned long offset, + unsigned char *buf, int len) { unsigned long fifoaddr = r8a66597->reg + offset; + int adj = 0; + int i; if (r8a66597->pdata->on_chip) { - unsigned long count; - unsigned char *pb; - int i; - - count = len / 4; - outsl(fifoaddr, buf, count); - - if (len & 0x00000003) { - pb = (unsigned char *)buf + count * 4; - for (i = 0; i < (len & 0x00000003); i++) { - if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND) - outb(pb[i], fifoaddr + i); - else - outb(pb[i], fifoaddr + 3 - i); - } + /* 32-bit access only if buf is 32-bit aligned */ + if (len >= 4 && !((unsigned long)buf & 0x03)) { + outsl(fifoaddr, buf, len / 4); + buf += len & ~0x03; + len &= 0x03; } } else { - int odd = len & 0x0001; - - len = len / 2; - outsw(fifoaddr, buf, len); - if (unlikely(odd)) { - buf = &buf[len]; - outb((unsigned char)*buf, fifoaddr); + /* 16-bit access only if buf is 16-bit aligned */ + if (len >= 2 && !((unsigned long)buf & 0x01)) { + outsw(fifoaddr, buf, len / 2); + buf += len & ~0x01; + len &= 0x01; } } + + /* adjust fifo address in the little endian case */ + if (!(r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)) { + if (r8a66597->pdata->on_chip) + adj = 0x03; /* 32-bit wide */ + else + adj = 0x01; /* 16-bit wide */ + } + + for (i = 0; i < len; i++) + outb(buf[i], fifoaddr + adj - (i & adj)); } static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, -- cgit v1.2.3 From 0cbd81a9f6bac734ac3266687bf027af1e395270 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Oct 2009 20:05:04 +0200 Subject: USB: ftdi_sio: remove tty->low_latency Fixes tty_flip_buffer_push being called from hard interrupt context with low_latency set. Signed-off-by: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 4f883b1773d0..0ac2c2f540c9 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1234,7 +1234,6 @@ static int set_serial_info(struct tty_struct *tty, (new_serial.flags & ASYNC_FLAGS)); priv->custom_divisor = new_serial.custom_divisor; - tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; write_latency_timer(port); check_and_exit: @@ -1704,9 +1703,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) priv->rx_bytes = 0; spin_unlock_irqrestore(&priv->rx_lock, flags); - if (tty) - tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - write_latency_timer(port); /* No error checking for this (will get errors later anyway) */ -- cgit v1.2.3 From 63b0061246b54b849da8f189ae048e8110d8ce7d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Oct 2009 20:05:05 +0200 Subject: USB: ftdi_sio: remove unused rx_byte counter Remove unused rx_byte counter which is never exposed as noted by Alan Cox. Signed-off-by: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0ac2c2f540c9..bfb23d64bc6a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -81,7 +81,6 @@ struct ftdi_private { struct delayed_work rx_work; struct usb_serial_port *port; int rx_processed; - unsigned long rx_bytes; __u16 interface; /* FT2232C, FT2232H or FT4232H port interface (0 for FT232/245) */ @@ -1699,9 +1698,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) spin_lock_irqsave(&priv->tx_lock, flags); priv->tx_bytes = 0; spin_unlock_irqrestore(&priv->tx_lock, flags); - spin_lock_irqsave(&priv->rx_lock, flags); - priv->rx_bytes = 0; - spin_unlock_irqrestore(&priv->rx_lock, flags); write_latency_timer(port); @@ -2014,8 +2010,6 @@ static void ftdi_read_bulk_callback(struct urb *urb) struct usb_serial_port *port = urb->context; struct tty_struct *tty; struct ftdi_private *priv; - unsigned long countread; - unsigned long flags; int status = urb->status; if (urb->number_of_packets > 0) { @@ -2054,13 +2048,6 @@ static void ftdi_read_bulk_callback(struct urb *urb) goto out; } - /* count data bytes, but not status bytes */ - countread = urb->actual_length; - countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size); - spin_lock_irqsave(&priv->rx_lock, flags); - priv->rx_bytes += countread; - spin_unlock_irqrestore(&priv->rx_lock, flags); - ftdi_process_read(&priv->rx_work.work); out: tty_kref_put(tty); -- cgit v1.2.3 From e63e278b4d2d867893962d3c7cd13a3a24ceb3f1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Oct 2009 20:05:06 +0200 Subject: USB: ftdi_sio: clean up read completion handler Remove superfluous error checks in completion handler: - No need to check private data and urb pointers as we check urb-status before dereferencing priv (which is not freed until urb has been killed on close). - No need to check tty as it is checked again when processing. - No need to check urb->number_of_packets on bulk urb. Note that both private data and tty are checked again before processing (possibly from work queue which also is cancelled on close). Signed-off-by: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index bfb23d64bc6a..75c84d9b080d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2008,39 +2008,14 @@ static int ftdi_chars_in_buffer(struct tty_struct *tty) static void ftdi_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty; struct ftdi_private *priv; int status = urb->status; - if (urb->number_of_packets > 0) { - dev_err(&port->dev, "%s transfer_buffer_length %d " - "actual_length %d number of packets %d\n", __func__, - urb->transfer_buffer_length, - urb->actual_length, urb->number_of_packets); - dev_err(&port->dev, "%s transfer_flags %x\n", __func__, - urb->transfer_flags); - } - dbg("%s - port %d", __func__, port->number); if (port->port.count <= 0) return; - tty = tty_port_tty_get(&port->port); - if (!tty) { - dbg("%s - bad tty pointer - exiting", __func__); - return; - } - - priv = usb_get_serial_port_data(port); - if (!priv) { - dbg("%s - bad port private data pointer - exiting", __func__); - goto out; - } - - if (urb != port->read_urb) - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - if (status) { /* This will happen at close every time so it is a dbg not an err */ @@ -2048,9 +2023,8 @@ static void ftdi_read_bulk_callback(struct urb *urb) goto out; } + priv = usb_get_serial_port_data(port); ftdi_process_read(&priv->rx_work.work); -out: - tty_kref_put(tty); } /* ftdi_read_bulk_callback */ -- cgit v1.2.3 From cc01f17d5cb8ac604108515735aeca72e17944c1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Oct 2009 20:05:07 +0200 Subject: USB: ftdi_sio: re-implement read processing - Re-structure read processing. - Kill obsolete work queue and always push to tty in completion handler. - Use tty_insert_flip_string instead of per character push when possible. - Fix stalled-read regression in 2.6.31 by using urb status to determine when port is closed rather than port count. - Fix race with open/close by checking ASYNCB_INITIALIZED in unthrottle. - Kill private rx_flag and lock and use throttle flags in usb_serial_port instead. Signed-off-by: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 383 +++++++++++++++--------------------------- 1 file changed, 131 insertions(+), 252 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 75c84d9b080d..9c60d6d4908a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -76,12 +76,7 @@ struct ftdi_private { unsigned long last_dtr_rts; /* saved modem control outputs */ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ char prev_status, diff_status; /* Used for TIOCMIWAIT */ - __u8 rx_flags; /* receive state flags (throttling) */ - spinlock_t rx_lock; /* spinlock for receive state */ - struct delayed_work rx_work; struct usb_serial_port *port; - int rx_processed; - __u16 interface; /* FT2232C, FT2232H or FT4232H port interface (0 for FT232/245) */ @@ -736,10 +731,6 @@ static const char *ftdi_chip_name[] = { /* Constants for read urb and write urb */ #define BUFSZ 512 -/* rx_flags */ -#define THROTTLED 0x01 -#define ACTUALLY_THROTTLED 0x02 - /* Used for TIOCMIWAIT */ #define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD) #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) @@ -762,7 +753,7 @@ static int ftdi_write_room(struct tty_struct *tty); static int ftdi_chars_in_buffer(struct tty_struct *tty); static void ftdi_write_bulk_callback(struct urb *urb); static void ftdi_read_bulk_callback(struct urb *urb); -static void ftdi_process_read(struct work_struct *work); +static void ftdi_process_read(struct usb_serial_port *port); static void ftdi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int ftdi_tiocmget(struct tty_struct *tty, struct file *file); @@ -1525,7 +1516,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) } kref_init(&priv->kref); - spin_lock_init(&priv->rx_lock); spin_lock_init(&priv->tx_lock); init_waitqueue_head(&priv->delta_msr_wait); /* This will push the characters through immediately rather @@ -1547,7 +1537,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) port->read_urb->transfer_buffer_length = BUFSZ; } - INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read); priv->port = port; /* Free port's existing write urb and transfer buffer. */ @@ -1684,6 +1673,26 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) return 0; } +static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) +{ + struct urb *urb = port->read_urb; + struct usb_serial *serial = port->serial; + int result; + + usb_fill_bulk_urb(urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + urb->transfer_buffer, + urb->transfer_buffer_length, + ftdi_read_bulk_callback, port); + result = usb_submit_urb(urb, mem_flags); + if (result) + dev_err(&port->dev, + "%s - failed submitting read urb, error %d\n", + __func__, result); + return result; +} + static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) { /* ftdi_open */ struct usb_device *dev = port->serial->dev; @@ -1717,23 +1726,14 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) ftdi_set_termios(tty, port, tty->termios); /* Not throttled */ - spin_lock_irqsave(&priv->rx_lock, flags); - priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irqrestore(&priv->rx_lock, flags); + spin_lock_irqsave(&port->lock, flags); + port->throttled = 0; + port->throttle_req = 0; + spin_unlock_irqrestore(&port->lock, flags); /* Start reading from the device */ - priv->rx_processed = 0; - usb_fill_bulk_urb(port->read_urb, dev, - usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ftdi_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - else + result = ftdi_submit_read_urb(port, GFP_KERNEL); + if (!result) kref_get(&priv->kref); return result; @@ -1779,10 +1779,6 @@ static void ftdi_close(struct usb_serial_port *port) dbg("%s", __func__); - - /* cancel any scheduled reading */ - cancel_delayed_work_sync(&priv->rx_work); - /* shutdown our bulk read */ usb_kill_urb(port->read_urb); kref_put(&priv->kref, ftdi_sio_priv_release); @@ -2005,236 +2001,121 @@ static int ftdi_chars_in_buffer(struct tty_struct *tty) return buffered; } -static void ftdi_read_bulk_callback(struct urb *urb) +static int ftdi_process_packet(struct tty_struct *tty, + struct usb_serial_port *port, struct ftdi_private *priv, + char *packet, int len) { - struct usb_serial_port *port = urb->context; - struct ftdi_private *priv; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (port->port.count <= 0) - return; - - if (status) { - /* This will happen at close every time so it is a dbg not an - err */ - dbg("(this is ok on close) nonzero read bulk status received: %d", status); - goto out; - } - - priv = usb_get_serial_port_data(port); - ftdi_process_read(&priv->rx_work.work); -} /* ftdi_read_bulk_callback */ - - -static void ftdi_process_read(struct work_struct *work) -{ /* ftdi_process_read */ - struct ftdi_private *priv = - container_of(work, struct ftdi_private, rx_work.work); - struct usb_serial_port *port = priv->port; - struct urb *urb; - struct tty_struct *tty; - char error_flag; - unsigned char *data; - int i; - int result; - int need_flip; - int packet_offset; - unsigned long flags; + char status; + char flag; + char *ch; dbg("%s - port %d", __func__, port->number); - if (port->port.count <= 0) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) { - dbg("%s - bad tty pointer - exiting", __func__); - return; + if (len < 2) { + dbg("malformed packet"); + return 0; } - priv = usb_get_serial_port_data(port); - if (!priv) { - dbg("%s - bad port private data pointer - exiting", __func__); - goto out; + /* Compare new line status to the old one, signal if different/ + N.B. packet may be processed more than once, but differences + are only processed once. */ + status = packet[0] & FTDI_STATUS_B0_MASK; + if (status != priv->prev_status) { + priv->diff_status |= status ^ priv->prev_status; + wake_up_interruptible(&priv->delta_msr_wait); + priv->prev_status = status; } - urb = port->read_urb; - if (!urb) { - dbg("%s - bad read_urb pointer - exiting", __func__); - goto out; + /* + * Although the device uses a bitmask and hence can have multiple + * errors on a packet - the order here sets the priority the error is + * returned to the tty layer. + */ + flag = TTY_NORMAL; + if (packet[1] & FTDI_RS_OE) { + flag = TTY_OVERRUN; + dbg("OVERRRUN error"); } - - data = urb->transfer_buffer; - - if (priv->rx_processed) { - dbg("%s - already processed: %d bytes, %d remain", __func__, - priv->rx_processed, - urb->actual_length - priv->rx_processed); - } else { - /* The first two bytes of every read packet are status */ - if (urb->actual_length > 2) - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - else - dbg("Status only: %03oo %03oo", data[0], data[1]); + if (packet[1] & FTDI_RS_BI) { + flag = TTY_BREAK; + dbg("BREAK received"); + usb_serial_handle_break(port); + } + if (packet[1] & FTDI_RS_PE) { + flag = TTY_PARITY; + dbg("PARITY error"); + } + if (packet[1] & FTDI_RS_FE) { + flag = TTY_FRAME; + dbg("FRAMING error"); } - - /* TO DO -- check for hung up line and handle appropriately: */ - /* send hangup */ - /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */ - /* if CD is dropped and the line is not CLOCAL then we should hangup */ - - need_flip = 0; - for (packet_offset = priv->rx_processed; - packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) { - int length; - - /* Compare new line status to the old one, signal if different/ - N.B. packet may be processed more than once, but differences - are only processed once. */ - char new_status = data[packet_offset + 0] & - FTDI_STATUS_B0_MASK; - if (new_status != priv->prev_status) { - priv->diff_status |= - new_status ^ priv->prev_status; - wake_up_interruptible(&priv->delta_msr_wait); - priv->prev_status = new_status; - } - - length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2; - if (length < 0) { - dev_err(&port->dev, "%s - bad packet length: %d\n", - __func__, length+2); - length = 0; - } - - if (priv->rx_flags & THROTTLED) { - dbg("%s - throttled", __func__); - break; - } - if (tty_buffer_request_room(tty, length) < length) { - /* break out & wait for throttling/unthrottling to - happen */ - dbg("%s - receive room low", __func__); - break; + len -= 2; + if (!len) + return 0; /* status only */ + ch = packet + 2; + + if (!(port->console && port->sysrq) && flag == TTY_NORMAL) + tty_insert_flip_string(tty, ch, len); + else { + for (i = 0; i < len; i++, ch++) { + if (!usb_serial_handle_sysrq_char(tty, port, *ch)) + tty_insert_flip_char(tty, *ch, flag); } + } + return len; +} - /* Handle errors and break */ - error_flag = TTY_NORMAL; - /* Although the device uses a bitmask and hence can have - multiple errors on a packet - the order here sets the - priority the error is returned to the tty layer */ +static void ftdi_process_read(struct usb_serial_port *port) +{ + struct urb *urb = port->read_urb; + struct tty_struct *tty; + struct ftdi_private *priv = usb_get_serial_port_data(port); + char *data = (char *)urb->transfer_buffer; + int i; + int len; + int count = 0; - if (data[packet_offset+1] & FTDI_RS_OE) { - error_flag = TTY_OVERRUN; - dbg("OVERRRUN error"); - } - if (data[packet_offset+1] & FTDI_RS_BI) { - error_flag = TTY_BREAK; - dbg("BREAK received"); - usb_serial_handle_break(port); - } - if (data[packet_offset+1] & FTDI_RS_PE) { - error_flag = TTY_PARITY; - dbg("PARITY error"); - } - if (data[packet_offset+1] & FTDI_RS_FE) { - error_flag = TTY_FRAME; - dbg("FRAMING error"); - } - if (length > 0) { - for (i = 2; i < length+2; i++) { - /* Note that the error flag is duplicated for - every character received since we don't know - which character it applied to */ - if (!usb_serial_handle_sysrq_char(tty, port, - data[packet_offset + i])) - tty_insert_flip_char(tty, - data[packet_offset + i], - error_flag); - } - need_flip = 1; - } + tty = tty_port_tty_get(&port->port); + if (!tty) + return; -#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW - /* if a parity error is detected you get status packets forever - until a character is sent without a parity error. - This doesn't work well since the application receives a - never ending stream of bad data - even though new data - hasn't been sent. Therefore I (bill) have taken this out. - However - this might make sense for framing errors and so on - so I am leaving the code in for now. - */ - else { - if (error_flag != TTY_NORMAL) { - dbg("error_flag is not normal"); - /* In this case it is just status - if that is - an error send a bad character */ - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - tty_flip_buffer_push(tty); - tty_insert_flip_char(tty, 0xff, error_flag); - need_flip = 1; - } - } -#endif - } /* "for(packet_offset=0..." */ + for (i = 0; i < urb->actual_length; i += priv->max_packet_size) { + len = min_t(int, urb->actual_length - i, priv->max_packet_size); + count += ftdi_process_packet(tty, port, priv, &data[i], len); + } - /* Low latency */ - if (need_flip) + if (count) tty_flip_buffer_push(tty); + tty_kref_put(tty); +} - if (packet_offset < urb->actual_length) { - /* not completely processed - record progress */ - priv->rx_processed = packet_offset; - dbg("%s - incomplete, %d bytes processed, %d remain", - __func__, packet_offset, - urb->actual_length - packet_offset); - /* check if we were throttled while processing */ - spin_lock_irqsave(&priv->rx_lock, flags); - if (priv->rx_flags & THROTTLED) { - priv->rx_flags |= ACTUALLY_THROTTLED; - spin_unlock_irqrestore(&priv->rx_lock, flags); - dbg("%s - deferring remainder until unthrottled", - __func__); - goto out; - } - spin_unlock_irqrestore(&priv->rx_lock, flags); - /* if the port is closed stop trying to read */ - if (port->port.count > 0) - /* delay processing of remainder */ - schedule_delayed_work(&priv->rx_work, 1); - else - dbg("%s - port is closed", __func__); - goto out; - } - - /* urb is completely processed */ - priv->rx_processed = 0; +static void ftdi_read_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + unsigned long flags; - /* if the port is closed stop trying to read */ - if (port->port.count > 0) { - /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ftdi_read_bulk_callback, port); + dbg("%s - port %d", __func__, port->number); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); + if (urb->status) { + dbg("%s - nonzero read bulk status received: %d", + __func__, urb->status); + return; } -out: - tty_kref_put(tty); -} /* ftdi_process_read */ + usb_serial_debug_data(debug, &port->dev, __func__, + urb->actual_length, urb->transfer_buffer); + ftdi_process_read(port); + + spin_lock_irqsave(&port->lock, flags); + port->throttled = port->throttle_req; + if (!port->throttled) { + spin_unlock_irqrestore(&port->lock, flags); + ftdi_submit_read_urb(port, GFP_ATOMIC); + } else + spin_unlock_irqrestore(&port->lock, flags); +} static void ftdi_break_ctl(struct tty_struct *tty, int break_state) { @@ -2566,33 +2447,31 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file, static void ftdi_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->rx_lock, flags); - priv->rx_flags |= THROTTLED; - spin_unlock_irqrestore(&priv->rx_lock, flags); + spin_lock_irqsave(&port->lock, flags); + port->throttle_req = 1; + spin_unlock_irqrestore(&port->lock, flags); } - -static void ftdi_unthrottle(struct tty_struct *tty) +void ftdi_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - int actually_throttled; + int was_throttled; unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->rx_lock, flags); - actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; - priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irqrestore(&priv->rx_lock, flags); + spin_lock_irqsave(&port->lock, flags); + was_throttled = port->throttled; + port->throttled = port->throttle_req = 0; + spin_unlock_irqrestore(&port->lock, flags); - if (actually_throttled) - schedule_delayed_work(&priv->rx_work, 0); + /* Resubmit urb if throttled and open. */ + if (was_throttled && test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + ftdi_submit_read_urb(port, GFP_KERNEL); } static int __init ftdi_init(void) -- cgit v1.2.3 From 9388e2e71a51fab0aa2309bbb45e8a23d89a95a9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 8 Oct 2009 11:36:46 +0200 Subject: USB: pl2303: fix error characters not being reported to ldisc Fix regression introduced by commit d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6 (tty: Fix the PL2303 private methods for sysrq). Signed-off-by: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1128e01525b1..9ec1a49e2362 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1046,13 +1046,15 @@ static void pl2303_push_data(struct tty_struct *tty, /* overrun is special, not associated with a char */ if (line_status & UART_OVERRUN_ERROR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); - if (port->console && port->sysrq) { + + if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq)) + tty_insert_flip_string(tty, data, urb->actual_length); + else { int i; for (i = 0; i < urb->actual_length; ++i) if (!usb_serial_handle_sysrq_char(tty, port, data[i])) tty_insert_flip_char(tty, data[i], tty_flag); - } else - tty_insert_flip_string(tty, data, urb->actual_length); + } tty_flip_buffer_push(tty); } -- cgit v1.2.3 From ba6b702f85a61561d329c4c11d3ed95604924f9a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 29 Sep 2009 12:39:23 +0200 Subject: USB: digi_acceleport: Fix broken unthrottle. This patch fixes a regression introduced in 39892da44b21b5362eb848ca424d73a25ccc488f. Signed-off-by: Johan Hovold Acked-by: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/digi_acceleport.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index ab3dd991586b..68e80be6b9e1 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -898,16 +898,16 @@ static void digi_rx_unthrottle(struct tty_struct *tty) spin_lock_irqsave(&priv->dp_port_lock, flags); - /* turn throttle off */ - priv->dp_throttled = 0; - priv->dp_throttle_restart = 0; - /* restart read chain */ if (priv->dp_throttle_restart) { port->read_urb->dev = port->serial->dev; ret = usb_submit_urb(port->read_urb, GFP_ATOMIC); } + /* turn throttle off */ + priv->dp_throttled = 0; + priv->dp_throttle_restart = 0; + spin_unlock_irqrestore(&priv->dp_port_lock, flags); if (ret) -- cgit v1.2.3 From a4720c650b68a5fe7faed2edeb0ad12645f7ae63 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 9 Oct 2009 12:43:12 -0400 Subject: USB: serial: don't call release without attach This patch (as1295) fixes a recently-added bug in the USB serial core. If certain kinds of errors occur during probing, the core may call a serial driver's release method without previously calling the attach method. This causes some drivers (io_ti in particular) to perform an invalid memory access. The patch adds a new flag to keep track of whether or not attach has been called. Signed-off-by: Alan Stern Tested-by: Jean-Denis Girard CC: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 6 +++++- include/linux/usb/serial.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index aa6b2ae951ae..2d0f75d63ff0 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -156,7 +156,8 @@ static void destroy_serial(struct kref *kref) if (serial->minor != SERIAL_TTY_NO_MINOR) return_serial(serial); - serial->type->release(serial); + if (serial->attached) + serial->type->release(serial); /* Now that nothing is using the ports, they can be freed */ for (i = 0; i < serial->num_port_pointers; ++i) { @@ -1059,12 +1060,15 @@ int usb_serial_probe(struct usb_interface *interface, module_put(type->driver.owner); if (retval < 0) goto probe_error; + serial->attached = 1; if (retval > 0) { /* quietly accept this device, but don't bind to a serial port as it's about to disappear */ serial->num_ports = 0; goto exit; } + } else { + serial->attached = 1; } if (get_free_serial(serial, num_ports, &minor) == NULL) { diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index c17eb64d7213..ce911ebf91e8 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -150,6 +150,7 @@ struct usb_serial { struct usb_interface *interface; unsigned char disconnected:1; unsigned char suspending:1; + unsigned char attached:1; unsigned char minor; unsigned char num_ports; unsigned char num_port_pointers; -- cgit v1.2.3 From 0f0ba794dcd14c9154afdf36df6a7e18cceec121 Mon Sep 17 00:00:00 2001 From: Elina Pasheva Date: Thu, 17 Sep 2009 15:26:20 -0700 Subject: USB: serial: sierra driver version change to 1.3.8 Updated sierra driver version from 1.3.7 to 1.3.8 now that the autosuspend capabilities were added to the driver. Signed-off-by: Elina Pasheva Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 8c075b2416bb..45883988a005 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -17,7 +17,7 @@ Whom based his on the Keyspan driver by Hugh Blemings */ -#define DRIVER_VERSION "v.1.3.7" +#define DRIVER_VERSION "v.1.3.8" #define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" -- cgit v1.2.3 From 696a4ace98b6b9c05c642a6840be98d6fde57655 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 23 Sep 2009 16:09:56 +0200 Subject: USB: usblcd, fix memory leak Stanse found a memory leak in lcd_probe. Instead of returning without releasing the memory, jump to the error label which frees it. http://stanse.fi.muni.cz/ Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usblcd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 29092b8e59ce..4fb120357c55 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -313,7 +313,8 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) { dev_warn(&interface->dev, "USBLCD model not supported.\n"); - return -ENODEV; + retval = -ENODEV; + goto error; } /* set up the endpoint information */ -- cgit v1.2.3 From 75f47214f90e996eb184eb6e6b0e8b817999c8f7 Mon Sep 17 00:00:00 2001 From: Peter Magdina Date: Wed, 7 Oct 2009 16:22:17 +0200 Subject: USB: option: Toshiba G450 device id Signed-off-by: Peter Magdina Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index f66e39883218..32702480b526 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -318,6 +318,7 @@ static int option_resume(struct usb_serial *serial); /* TOSHIBA PRODUCTS */ #define TOSHIBA_VENDOR_ID 0x0930 #define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302 +#define TOSHIBA_PRODUCT_G450 0x0d45 #define ALINK_VENDOR_ID 0x1e0e #define ALINK_PRODUCT_3GU 0x9200 @@ -581,6 +582,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) }, + { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, -- cgit v1.2.3 From 0ee3a33a0481c8f5c9edb7a5a02f3c76496d9551 Mon Sep 17 00:00:00 2001 From: Ronnie Furuskog Date: Mon, 21 Sep 2009 21:20:55 +0200 Subject: USB: option: Patch for Huawei Mobile Broadband E270+ Modem Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 32702480b526..43c227027560 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -165,6 +165,7 @@ static int option_resume(struct usb_serial *serial); #define HUAWEI_PRODUCT_E143D 0x143D #define HUAWEI_PRODUCT_E143E 0x143E #define HUAWEI_PRODUCT_E143F 0x143F +#define HUAWEI_PRODUCT_E14AC 0x14AC #define QUANTA_VENDOR_ID 0x0408 #define QUANTA_PRODUCT_Q101 0xEA02 @@ -425,6 +426,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_9508) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */ -- cgit v1.2.3 From 35f76e897d67fb62b4ec0be01fc0caaeb7f90108 Mon Sep 17 00:00:00 2001 From: Gergely Imreh Date: Tue, 15 Sep 2009 16:03:31 +0800 Subject: USB: usbtmc: fix timeout increase The current 10ms timeout is too short for some normal USBTMC device operation, increase it to a value which was tested with previously affected Tektronix oscilloscopes. Signed-off-by: Gergely Imreh Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 864f0ba6a344..2473cf0c6b1d 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -39,7 +39,7 @@ #define USBTMC_SIZE_IOBUFFER 2048 /* Default USB timeout (in milliseconds) */ -#define USBTMC_TIMEOUT 10 +#define USBTMC_TIMEOUT 5000 /* * Maximum number of read cycles to empty bulk in endpoint during CLEAR and -- cgit v1.2.3 From e4ab05df573834b8c70d19db426b7d6286782c1d Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 16 Sep 2009 16:42:30 -0700 Subject: USB: xhci: Stop debugging polling loop when HC dies. If the host controller card is removed from the system, stop the timer function to debug the xHCI rings. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 99911e727e0b..8719a3f6851d 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -335,6 +335,12 @@ void xhci_event_ring_work(unsigned long arg) spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, &xhci->op_regs->status); xhci_dbg(xhci, "op reg status = 0x%x\n", temp); + if (temp == 0xffffffff) { + xhci_dbg(xhci, "HW died, polling stopped.\n"); + spin_unlock_irqrestore(&xhci->lock, flags); + return; + } + temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp); xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled); -- cgit v1.2.3 From e34b2fbf28741310d1d59a217d34e050ce7867e8 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 28 Sep 2009 17:21:37 -0700 Subject: USB: xhci: Handle canceled URBs when HC dies. When the host controller dies (e.g. it is removed from a PCI card slot), the xHCI driver cannot expect commands to complete. The buggy code this patch fixes would mark an URB as canceled and then expect the URB to be completed when the stop endpoint command completed. That would never happen if the host controller was dead, so the USB core would just hang in the disconnect code. If the host controller died, and the driver asks to cancel an URB, free any structures associated with that URB and immediately give it back. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 8719a3f6851d..592e742c5f35 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -782,6 +782,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { unsigned long flags; int ret; + u32 temp; struct xhci_hcd *xhci; struct xhci_td *td; unsigned int ep_index; @@ -794,6 +795,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret || !urb->hcpriv) goto done; + temp = xhci_readl(xhci, &xhci->op_regs->status); + if (temp == 0xffffffff) { + xhci_dbg(xhci, "HW died, freeing TD.\n"); + td = (struct xhci_td *) urb->hcpriv; + + usb_hcd_unlink_urb_from_ep(hcd, urb); + spin_unlock_irqrestore(&xhci->lock, flags); + usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN); + kfree(td); + return ret; + } xhci_dbg(xhci, "Cancel URB %p\n", urb); xhci_dbg(xhci, "Event ring:\n"); -- cgit v1.2.3 From c526d0d4fc9707816b407d2d3336267d3271db2b Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 16 Sep 2009 16:42:39 -0700 Subject: USB: xhci: Don't wait for a disable slot cmd when HC dies. When the host controller dies or is removed while a device is plugged in, the USB core will attempt to deallocate the struct usb_device. That will call into xhci_free_dev(). This function used to attempt to submit a disable slot command to the host controller and clean up the device structures when that command returned. Change xhci_free_dev() to skip the command submission and just free the memory if the host controller died. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 592e742c5f35..d61c49f90f4a 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -1428,11 +1428,20 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); unsigned long flags; + u32 state; if (udev->slot_id == 0) return; spin_lock_irqsave(&xhci->lock, flags); + /* Don't disable the slot if the host controller is dead. */ + state = xhci_readl(xhci, &xhci->op_regs->status); + if (state == 0xffffffff) { + xhci_free_virt_device(xhci, udev->slot_id); + spin_unlock_irqrestore(&xhci->lock, flags); + return; + } + if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); -- cgit v1.2.3 From 0a023c6cf10c63d2ce68a2816d90c2f0f1ad2763 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 18 Sep 2009 08:55:12 -0700 Subject: USB: xhci: Fix dropping endpoints from the xHC schedule. When an endpoint is to be dropped from the hardware bandwidth schedule, we want to clear its add flag. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index d61c49f90f4a..932f99938481 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -895,7 +895,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, ctrl_ctx->drop_flags |= drop_flag; new_drop_flags = ctrl_ctx->drop_flags; - ctrl_ctx->add_flags = ~drop_flag; + ctrl_ctx->add_flags &= ~drop_flag; new_add_flags = ctrl_ctx->add_flags; last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags); -- cgit v1.2.3 From b20cf90650badaa5e6ec1bdbe61a63528818e8ce Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 16 Sep 2009 21:10:53 -0400 Subject: USB: musb: make HAVE_CLK support optional The Blackfin port doesn't support HAVE_CLK and the musb driver works fine with support stubbed out, so take the existing Blackfin clk stubs and move them to common musb code so we can drop the Kconfig dependency. Signed-off-by: Bryan Wu Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/Kconfig | 2 +- drivers/usb/musb/blackfin.c | 1 - drivers/usb/musb/musb_core.h | 7 +++++++ drivers/usb/musb/musb_regs.h | 9 --------- 4 files changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 803adcb5ac1d..760e7271d17b 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -8,7 +8,7 @@ comment "Enable Host or Gadget support to see Inventra options" # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller config USB_MUSB_HDRC - depends on (USB || USB_GADGET) && HAVE_CLK + depends on (USB || USB_GADGET) depends on !SUPERH select NOP_USB_XCEIV if ARCH_DAVINCI select TWL4030_USB if MACH_OMAP_3430SDP diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index f2f66ebc7362..fcec87ea709e 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 381d648a36b8..6aa5f22e5274 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -95,6 +95,13 @@ struct musb_ep; #endif #endif /* need MUSB gadget selection */ +#ifndef CONFIG_HAVE_CLK +/* Dummy stub for clk framework */ +#define clk_get(dev, id) NULL +#define clk_put(clock) do {} while (0) +#define clk_enable(clock) do {} while (0) +#define clk_disable(clock) do {} while (0) +#endif #ifdef CONFIG_PROC_FS #include diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index fbfd3fd9ce1f..cc1d71b57d3c 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -439,15 +439,6 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum, /* Not implemented - HW has seperate Tx/Rx FIFO */ #define MUSB_TXCSR_MODE 0x0000 -/* - * Dummy stub for clk framework, it will be removed - * until Blackfin supports clk framework - */ -#define clk_get(dev, id) NULL -#define clk_put(clock) do {} while (0) -#define clk_enable(clock) do {} while (0) -#define clk_disable(clock) do {} while (0) - static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size) { } -- cgit v1.2.3 From 2f13612a86dd785d581e29aed4db2fb98ba507ca Mon Sep 17 00:00:00 2001 From: Sergey Pinaev Date: Thu, 17 Sep 2009 17:26:50 +0400 Subject: USB: storage: iRiver P7 UNUSUAL_DEV patch Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 079ae0f7bec1..d4f034ebaa8a 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1823,6 +1823,13 @@ UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Sergey Pinaev */ +UNUSUAL_DEV( 0x4102, 0x1059, 0x0000, 0x0000, + "iRiver", + "P7K", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* * David Härdeman * The key makes the SCSI stack print confusing (but harmless) messages -- cgit v1.2.3 From d86a83f4acbded4095a632e861183d117ec7405a Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 18 Sep 2009 09:14:46 +0200 Subject: USB: gadget: imx_udc: Use resource size Use the resource_size function instead of manually calculating the resource size. This reduces the chance of introducing off-by-one errors. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/imx_udc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index c52a681f376c..01ee0b9bc957 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1402,7 +1402,8 @@ static int __init imx_udc_probe(struct platform_device *pdev) struct clk *clk; void __iomem *base; int ret = 0; - int i, res_size; + int i; + resource_size_t res_size; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -1416,7 +1417,7 @@ static int __init imx_udc_probe(struct platform_device *pdev) return -ENODEV; } - res_size = res->end - res->start + 1; + res_size = resource_size(res); if (!request_mem_region(res->start, res_size, res->name)) { dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n", res_size, res->start); @@ -1527,8 +1528,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev) clk_disable(imx_usb->clk); iounmap(imx_usb->base); - release_mem_region(imx_usb->res->start, - imx_usb->res->end - imx_usb->res->start + 1); + release_mem_region(imx_usb->res->start, resource_size(imx_usb->res)); if (pdata->exit) pdata->exit(&pdev->dev); -- cgit v1.2.3 From b0a9cf297e587219332ee4acca243627702c2cc9 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 7 Oct 2009 04:29:31 -0400 Subject: USB: isp1362: fix build warnings on 64-bit systems A bunch of places assumed pointers were 32-bits in size (bit checking and debug output), but none of these affected runtime functionality. Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1362-hcd.c | 18 +++++++++--------- drivers/usb/host/isp1362.h | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index e35d82808bab..5c774ab98252 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2284,10 +2284,10 @@ static int isp1362_mem_config(struct usb_hcd *hcd) dev_info(hcd->self.controller, "ISP1362 Memory usage:\n"); dev_info(hcd->self.controller, " ISTL: 2 * %4d: %4d @ $%04x:$%04x\n", istl_size / 2, istl_size, 0, istl_size / 2); - dev_info(hcd->self.controller, " INTL: %4d * (%3u+8): %4d @ $%04x\n", + dev_info(hcd->self.controller, " INTL: %4d * (%3lu+8): %4d @ $%04x\n", ISP1362_INTL_BUFFERS, intl_blksize - PTD_HEADER_SIZE, intl_size, istl_size); - dev_info(hcd->self.controller, " ATL : %4d * (%3u+8): %4d @ $%04x\n", + dev_info(hcd->self.controller, " ATL : %4d * (%3lu+8): %4d @ $%04x\n", atl_buffers, atl_blksize - PTD_HEADER_SIZE, atl_size, istl_size + intl_size); dev_info(hcd->self.controller, " USED/FREE: %4d %4d\n", total, @@ -2677,12 +2677,12 @@ static int __devexit isp1362_remove(struct platform_device *pdev) DBG(0, "%s: Removing HCD\n", __func__); usb_remove_hcd(hcd); - DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__, - (u32)isp1362_hcd->data_reg); + DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, + isp1362_hcd->data_reg); iounmap(isp1362_hcd->data_reg); - DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__, - (u32)isp1362_hcd->addr_reg); + DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, + isp1362_hcd->addr_reg); iounmap(isp1362_hcd->addr_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); @@ -2810,16 +2810,16 @@ static int __init isp1362_probe(struct platform_device *pdev) return 0; err6: - DBG(0, "%s: Freeing dev %08x\n", __func__, (u32)isp1362_hcd); + DBG(0, "%s: Freeing dev %p\n", __func__, isp1362_hcd); usb_put_hcd(hcd); err5: - DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__, (u32)data_reg); + DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, data_reg); iounmap(data_reg); err4: DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)data->start); release_mem_region(data->start, resource_len(data)); err3: - DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__, (u32)addr_reg); + DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, addr_reg); iounmap(addr_reg); err2: DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)addr->start); diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h index fe60f62a32f3..1a253ebf7e50 100644 --- a/drivers/usb/host/isp1362.h +++ b/drivers/usb/host/isp1362.h @@ -580,7 +580,7 @@ static inline const char *ISP1362_INT_NAME(int n) static inline void ALIGNSTAT(struct isp1362_hcd *isp1362_hcd, void *ptr) { - unsigned p = (unsigned)ptr; + unsigned long p = (unsigned long)ptr; if (!(p & 0xf)) isp1362_hcd->stat16++; else if (!(p & 0x7)) @@ -770,7 +770,7 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l if (!len) return; - if ((unsigned)dp & 0x1) { + if ((unsigned long)dp & 0x1) { /* not aligned */ for (; len > 1; len -= 2) { data = *dp++; @@ -962,8 +962,8 @@ static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 isp1362_write_diraddr(isp1362_hcd, offset, len); - DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %08x\n", __func__, - len, offset, (u32)buf); + DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n", + __func__, len, offset, buf); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); @@ -982,8 +982,8 @@ static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 isp1362_write_diraddr(isp1362_hcd, offset, len); - DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %08x\n", __func__, - len, offset, (u32)buf); + DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n", + __func__, len, offset, buf); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); -- cgit v1.2.3 From 06bad89da686f6323e95cf925105e8cf88d87caf Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 5 Oct 2009 15:53:58 -0400 Subject: USB: ipaq: fix oops when device is plugged in This patch (as1293) fixes a problem with the ipaq serial driver. It tries to bind to all the interfaces, even those that don't have enough endpoints. The symptom is an invalid memory reference and oops when the device is plugged in. Signed-off-by: Alan Stern CC: stable Tested-by: Matthias Geissert Tested-by: Tilman Schmidt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 24fcc64b837d..d6231c38813e 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -966,6 +966,15 @@ static int ipaq_calc_num_ports(struct usb_serial *serial) static int ipaq_startup(struct usb_serial *serial) { dbg("%s", __func__); + + /* Some of the devices in ipaq_id_table[] are composite, and we + * shouldn't bind to all the interfaces. This test will rule out + * some obviously invalid possibilities. + */ + if (serial->num_bulk_in < serial->num_ports || + serial->num_bulk_out < serial->num_ports) + return -ENODEV; + if (serial->dev->actconfig->desc.bConfigurationValue != 1) { /* * FIXME: HP iPaq rx3715, possibly others, have 1 config that -- cgit v1.2.3 From 6f88139eb9eae8003683689f93402264a73fb754 Mon Sep 17 00:00:00 2001 From: Éric Piel Date: Sun, 4 Oct 2009 13:45:07 +0200 Subject: USB: cp210x: Add support for the DW700 UART MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the Dell inspiron mini 10, the GPS is connected via a cp2102. This patch adds detection of this USB device. (I haven't managed to use the GPS under Linux yet, though) Signed-off-by: Éric Piel Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 4a208fe85bc9..698252a4dc5d 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -113,6 +113,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ }; -- cgit v1.2.3 From 63a9609513007537a0b23ac511fd73f9bd609ea0 Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Thu, 24 Sep 2009 20:20:20 +0200 Subject: USB: Fix throttling in generic usbserial driver The generic usbserial driver in Linux 2.6.31 halts its receiving channel in response to throttle requests from the line discipline. Unfortunately it drops the contents of the first URB received after throttling takes effect. This patch corrects that problem. Signed-off-by: Joris van Rantwijk Acked-by: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index deba08c7a015..bbe005cefcfb 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -546,7 +546,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) if (was_throttled) { /* Resume reading from device */ - usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL); + flush_and_resubmit_read_urb(port); } } -- cgit v1.2.3 From 4c9fde9b860ccb27a7b026844eb3ef64c77e5a49 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 1 Oct 2009 14:54:46 +0200 Subject: USB: visor: fix trivial accounting bug in visor driver usb:usbserial:visor: fix accounting in error case data not pushed to the tty layer due to an error mustn't be counted Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/visor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 1aa5d20a5d99..8e2d6dd9add0 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -513,7 +513,8 @@ static void visor_read_bulk_callback(struct urb *urb) tty_kref_put(tty); } spin_lock(&priv->lock); - priv->bytes_in += available_room; + if (tty) + priv->bytes_in += available_room; } else { spin_lock(&priv->lock); -- cgit v1.2.3 From a5f6005d7b1821d2085d9749b56500a8f2610924 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 1 Oct 2009 15:01:17 +0200 Subject: USB: small fix in error case of suspend in generic usbserial code usb:usbserial: fix flags in error case of suspension suspended flag must be reset in error case Signed-off-by: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 2d0f75d63ff0..bd3fa7ff15b1 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1168,8 +1168,10 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) if (serial->type->suspend) { r = serial->type->suspend(serial, message); - if (r < 0) + if (r < 0) { + serial->suspending = 0; goto err_out; + } } for (i = 0; i < serial->num_ports; ++i) { -- cgit v1.2.3 From f1a0743bc0e7a30c032b1eb78f6a2b0f805b4597 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 6 Oct 2009 14:07:57 -0400 Subject: USB: storage: When a device returns no sense data, call it a Hardware Error This patch (as1294) fixes a problem that has plagued users for several kernel releases. Some USB mass-storage devices don't return any sense data when they encounter certain kinds of errors. The SCSI layer interprets this to mean that the operation should be retried, and the same thing happens -- over and over again with no limit. In some circumstances (such as when a bus reset occurs) that is the right thing to do, but not here. The patch checks for this condition (a transport failure with no sense data) and changes the result code to DID_ERROR and the sense code to Hardware Error. This does get only a limited number of retries, and so the command will fail relatively quickly instead of getting stuck in an infinite loop. This fixes a large part of Bugzilla #14118. Signed-off-by: Alan Stern Tested-by: Mantas Mikulenas CC: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index e20dc525d177..3a4fb023af72 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -768,17 +768,32 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; - /* If things are really okay, then let's show that. Zero - * out the sense buffer so the higher layers won't realize - * we did an unsolicited auto-sense. */ - if (result == USB_STOR_TRANSPORT_GOOD && - /* Filemark 0, ignore EOM, ILI 0, no sense */ + /* We often get empty sense data. This could indicate that + * everything worked or that there was an unspecified + * problem. We have to decide which. + */ + if ( /* Filemark 0, ignore EOM, ILI 0, no sense */ (srb->sense_buffer[2] & 0xaf) == 0 && /* No ASC or ASCQ */ srb->sense_buffer[12] == 0 && srb->sense_buffer[13] == 0) { - srb->result = SAM_STAT_GOOD; - srb->sense_buffer[0] = 0x0; + + /* If things are really okay, then let's show that. + * Zero out the sense buffer so the higher layers + * won't realize we did an unsolicited auto-sense. + */ + if (result == USB_STOR_TRANSPORT_GOOD) { + srb->result = SAM_STAT_GOOD; + srb->sense_buffer[0] = 0x0; + + /* If there was a problem, report an unspecified + * hardware error to prevent the higher layers from + * entering an infinite retry loop. + */ + } else { + srb->result = DID_ERROR << 16; + srb->sense_buffer[2] = HARDWARE_ERROR; + } } } -- cgit v1.2.3 From d55500941fe6db4d7424c744522ee2451ac1ceda Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 6 Oct 2009 13:45:59 -0700 Subject: USB: ehci: Fix isoc scheduling boundary checking. The EHCI driver does some bounds checking when it's scheduling an iTD for an active endpoint. It sets the local variable start to stream->next_uframe and moves that variable further in the schedule if necessary. However, the driver fails to do anything with start before jumping to the ready label and setting the URB's starting frame to stream->next_uframe. Alan Stern confirms the EHCI driver should set stream->next_uframe to start before jumping. Signed-off-by: Sarah Sharp Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 3ea05936851f..3efa59b18044 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1425,6 +1425,7 @@ iso_stream_schedule ( status = -EFBIG; goto fail; } + stream->next_uframe = start; goto ready; } -- cgit v1.2.3 From 88fa6590b30ef8c4d41923449ada104f915d8df8 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 7 Oct 2009 09:25:10 +0200 Subject: USB: serial: fix race between unthrottle and completion handler in opticon usb:usbserial:opticon: fix race between unthrottle and completion handler opticon_unthrottle() mustn't resubmit the URB unconditionally as the URB may still be running. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/opticon.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 1085a577c5c1..80f59b6350cb 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -314,21 +314,24 @@ static void opticon_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct opticon_private *priv = usb_get_serial_data(port->serial); unsigned long flags; - int result; + int result, was_throttled; dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; + was_throttled = priv->actually_throttled; priv->actually_throttled = false; spin_unlock_irqrestore(&priv->lock, flags); priv->bulk_read_urb->dev = port->serial->dev; - result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", + if (was_throttled) { + result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); + if (result) + dev_err(&port->dev, + "%s - failed submitting read urb, error %d\n", __func__, result); + } } static int opticon_tiocmget(struct tty_struct *tty, struct file *file) -- cgit v1.2.3 From b2a5cf1bdc011f5474c72543f9d8116c0f07f452 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 7 Oct 2009 09:30:49 +0200 Subject: USB: serial: fix race between unthrottle and completion handler in symbolserial usb:usbserial:symbolserial: fix race between unthrottle and completion handler symbol_unthrottle() mustn't resubmit the URB unconditionally as the URB may still be running. the same bug as opticon. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/symbolserial.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index cb7e95f9fcbf..f25e54526843 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -179,20 +179,24 @@ static void symbol_unthrottle(struct tty_struct *tty) struct symbol_private *priv = usb_get_serial_data(port->serial); unsigned long flags; int result; + bool was_throttled; dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; + was_throttled = priv->actually_throttled; priv->actually_throttled = false; spin_unlock_irqrestore(&priv->lock, flags); priv->int_urb->dev = port->serial->dev; - result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", + if (was_throttled) { + result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); + if (result) + dev_err(&port->dev, + "%s - failed submitting read urb, error %d\n", __func__, result); + } } static int symbol_startup(struct usb_serial *serial) -- cgit v1.2.3 From 638325154572ba2113a18669fe3b299caa2dabd9 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 7 Oct 2009 10:50:23 +0200 Subject: USB: serial: fix assumption that throttle/unthrottle cannot sleep many serial subdrivers are clearly written as if throttle/unthrottle cannot sleep. This leads to unneeded atomic submissions. This patch converts affected drivers in a way to makes very clear that throttle/unthrottle can sleep. Thus future misdesigns can be avoided and efficiency and reliability improved. This removes any such assumption using GFP_KERNEL and spin_lock_irq() Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/aircable.c | 10 ++++------ drivers/usb/serial/cypress_m8.c | 12 +++++------- drivers/usb/serial/empeg.c | 2 +- drivers/usb/serial/garmin_gps.c | 12 +++++------- drivers/usb/serial/keyspan_pda.c | 2 +- drivers/usb/serial/kl5kusb105.c | 2 +- drivers/usb/serial/mct_u232.c | 14 ++++++-------- drivers/usb/serial/symbolserial.c | 12 +++++------- drivers/usb/serial/visor.c | 12 +++++------- drivers/usb/serial/whiteheat.c | 10 ++++------ 10 files changed, 37 insertions(+), 51 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 2cbfab3716e5..b10ac8409411 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -554,13 +554,12 @@ static void aircable_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct aircable_private *priv = usb_get_serial_port_data(port); - unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->rx_lock, flags); + spin_lock_irq(&priv->rx_lock); priv->rx_flags |= THROTTLED; - spin_unlock_irqrestore(&priv->rx_lock, flags); + spin_unlock_irq(&priv->rx_lock); } /* Based on ftdi_sio.c unthrottle */ @@ -569,14 +568,13 @@ static void aircable_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct aircable_private *priv = usb_get_serial_port_data(port); int actually_throttled; - unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->rx_lock, flags); + spin_lock_irq(&priv->rx_lock); actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irqrestore(&priv->rx_lock, flags); + spin_unlock_irq(&priv->rx_lock); if (actually_throttled) schedule_work(&priv->rx_work); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index e0a8b715f2f2..a591ebec0f89 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -1155,13 +1155,12 @@ static void cypress_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); - unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); priv->rx_flags = THROTTLED; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); } @@ -1170,14 +1169,13 @@ static void cypress_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); int actually_throttled, result; - unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; priv->rx_flags = 0; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); if (!priv->comm_is_ok) return; @@ -1185,7 +1183,7 @@ static void cypress_unthrottle(struct tty_struct *tty) if (actually_throttled) { port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting read urb, " "error %d\n", __func__, result); diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 33c9e9cf9eb2..7dd0e3eadbe6 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -391,7 +391,7 @@ static void empeg_unthrottle(struct tty_struct *tty) dbg("%s - port %d", __func__, port->number); port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 20432d345529..5ac900e5a50e 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1390,14 +1390,13 @@ static void garmin_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - unsigned long flags; dbg("%s - port %d", __func__, port->number); /* set flag, data received will be put into a queue for later processing */ - spin_lock_irqsave(&garmin_data_p->lock, flags); + spin_lock_irq(&garmin_data_p->lock); garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); + spin_unlock_irq(&garmin_data_p->lock); } @@ -1405,13 +1404,12 @@ static void garmin_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - unsigned long flags; int status; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&garmin_data_p->lock, flags); + spin_lock_irq(&garmin_data_p->lock); garmin_data_p->flags &= ~FLAGS_THROTTLED; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); + spin_unlock_irq(&garmin_data_p->lock); /* in native mode send queued data to tty, in serial mode nothing needs to be done here */ @@ -1419,7 +1417,7 @@ static void garmin_unthrottle(struct tty_struct *tty) garmin_flush_queue(garmin_data_p); if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) { - status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + status = usb_submit_urb(port->read_urb, GFP_KERNEL); if (status) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 257c16cc6b2a..1296a097f5c3 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -290,7 +290,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) /* just restart the receive interrupt URB */ dbg("keyspan_pda_rx_unthrottle port %d", port->number); port->interrupt_in_urb->dev = port->serial->dev; - if (usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC)) + if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) dbg(" usb_submit_urb(read urb) failed"); return; } diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index f7373371b137..3a7873806f46 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -951,7 +951,7 @@ static void klsi_105_unthrottle(struct tty_struct *tty) dbg("%s - port %d", __func__, port->number); port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index ad4998bbf16f..cd009cb280a5 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -777,20 +777,19 @@ static void mct_u232_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned long flags; unsigned int control_state; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); priv->rx_flags |= THROTTLED; if (C_CRTSCTS(tty)) { priv->control_state &= ~TIOCM_RTS; control_state = priv->control_state; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); (void) mct_u232_set_modem_ctrl(port->serial, control_state); } else { - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); } } @@ -799,20 +798,19 @@ static void mct_u232_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned long flags; unsigned int control_state; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) { priv->rx_flags &= ~THROTTLED; priv->control_state |= TIOCM_RTS; control_state = priv->control_state; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); (void) mct_u232_set_modem_ctrl(port->serial, control_state); } else { - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); } } diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index f25e54526843..b282c0f2d8e5 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -165,33 +165,31 @@ static void symbol_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct symbol_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); priv->throttled = true; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); } static void symbol_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct symbol_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; int result; bool was_throttled; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); priv->throttled = false; was_throttled = priv->actually_throttled; priv->actually_throttled = false; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); priv->int_urb->dev = port->serial->dev; if (was_throttled) { - result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); + result = usb_submit_urb(priv->int_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 8e2d6dd9add0..b9341f0e452b 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -583,12 +583,11 @@ static void visor_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct visor_private *priv = usb_get_serial_port_data(port); - unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); priv->throttled = 1; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); } @@ -596,17 +595,16 @@ static void visor_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct visor_private *priv = usb_get_serial_port_data(port); - unsigned long flags; int result; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); priv->throttled = 0; priv->actually_throttled = 0; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irq(&priv->lock); port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 62424eec33ec..1093d2eb046a 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -949,13 +949,12 @@ static void whiteheat_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct whiteheat_private *info = usb_get_serial_port_data(port); - unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&info->lock, flags); + spin_lock_irq(&info->lock); info->flags |= THROTTLED; - spin_unlock_irqrestore(&info->lock, flags); + spin_unlock_irq(&info->lock); return; } @@ -966,14 +965,13 @@ static void whiteheat_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct whiteheat_private *info = usb_get_serial_port_data(port); int actually_throttled; - unsigned long flags; dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&info->lock, flags); + spin_lock_irq(&info->lock); actually_throttled = info->flags & ACTUALLY_THROTTLED; info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irqrestore(&info->lock, flags); + spin_unlock_irq(&info->lock); if (actually_throttled) rx_data_softint(&info->rx_work); -- cgit v1.2.3 From a1c33952b729eba4cedb8dbe54765921f2b3062f Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 7 Oct 2009 11:01:38 +0200 Subject: USB: serial: fix race between unthrottle and completion handler in visor usb:usbserial:visor: fix race between unthrottle and completion handler visor_unthrottle() mustn't resubmit the URB unconditionally as the URB may still be running. the same bug as opticon. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/visor.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index b9341f0e452b..ad1f9232292d 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -595,20 +595,23 @@ static void visor_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct visor_private *priv = usb_get_serial_port_data(port); - int result; + int result, was_throttled; dbg("%s - port %d", __func__, port->number); spin_lock_irq(&priv->lock); priv->throttled = 0; + was_throttled = priv->actually_throttled; priv->actually_throttled = 0; spin_unlock_irq(&priv->lock); - port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", + if (was_throttled) { + port->read_urb->dev = port->serial->dev; + result = usb_submit_urb(port->read_urb, GFP_KERNEL); + if (result) + dev_err(&port->dev, + "%s - failed submitting read urb, error %d\n", __func__, result); + } } static int palm_os_3_probe(struct usb_serial *serial, -- cgit v1.2.3 From 40d28582316d8dcb535c359a14b71cb910ad6e73 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 7 Oct 2009 18:07:10 +0200 Subject: USB: serial: no unnecessary GFP_ATOMIC in oti6858 GFP_ATOMIC without good cause is evil. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/oti6858.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 0f4a70ce3823..c644e26394b4 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -288,7 +288,7 @@ static void setup_line(struct work_struct *work) dbg("%s(): submitting interrupt urb", __func__); port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, result); @@ -335,7 +335,7 @@ void send_data(struct work_struct *work) dbg("%s(): submitting interrupt urb", __func__); port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); + result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); if (result != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, result); @@ -349,7 +349,7 @@ void send_data(struct work_struct *work) port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + result = usb_submit_urb(port->write_urb, GFP_NOIO); if (result != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, result); -- cgit v1.2.3 From d93a8f829fe1d2f3002f2c6ddb553d12db420412 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 11 Oct 2009 15:57:57 -0700 Subject: Revert "USB: Work around BIOS bugs by quiescing USB controllers earlier" This reverts commit db8be50c4307dac2b37305fc59c8dc0f978d09ea, as per http://bugzilla.kernel.org/show_bug.cgi?id=14374 http://marc.info/?l=linux-kernel&m=125446885705223&w=4 We simply can't do the USB handoff at FIXUP_HEADER time, since it will often require us to have valid IO mappings etc. But that in turn requires a whole different approach, not this trivial one-liner. Maybe we could teach all the USB quirk handoff handlers to only do the quirk if the device has all its registers set up (since if it isn't initialized, it's unlikely to be active), but regardless that will need a whole lot more code than just saying "let's do it really early". The proper fix is almost certainly to just leave the legacy IOMMU mappings active until after all devices have been initialized. Reported-by: Nick Piggin Cc: David Woodhouse Cc: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/host/pci-quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 23cf3bde4762..83b5f9cea85a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -475,4 +475,4 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) quirk_usb_handoff_xhci(pdev); } -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); -- cgit v1.2.3 From e3c6f15fecee5aaa2dd1d0b83b17d09b64997e31 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 12 Oct 2009 09:49:56 -0400 Subject: USB: musb: invert arch depend string The MUSB code relies on platform implementations that currently only exists for Arm and Blackfin processors, so have the MUSB Kconfig depend upon those arches. This should prevent other arches from building MUSB via randconfig. Reported-by: Ingo Molnar Signed-off-by: Mike Frysinger Signed-off-by: Linus Torvalds --- drivers/usb/musb/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 760e7271d17b..b84abd8ee8a5 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -9,7 +9,7 @@ comment "Enable Host or Gadget support to see Inventra options" # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller config USB_MUSB_HDRC depends on (USB || USB_GADGET) - depends on !SUPERH + depends on (ARM || BLACKFIN) select NOP_USB_XCEIV if ARCH_DAVINCI select TWL4030_USB if MACH_OMAP_3430SDP select NOP_USB_XCEIV if MACH_OMAP3EVM -- cgit v1.2.3 From b41ecf9a80a55406eb4bf90c1ba260785002e103 Mon Sep 17 00:00:00 2001 From: Stefano Panella Date: Mon, 12 Oct 2009 15:45:14 +0000 Subject: USB: wusb: don't use the stack to read security descriptor An urb's transfer buffer must be kmalloc'd memory and not point to the stack or a DMA API warning results. Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/security.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index b2f149fedcc5..4516c36436e6 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -200,35 +200,40 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, { int result, bytes, secd_size; struct device *dev = &usb_dev->dev; - struct usb_security_descriptor secd; + struct usb_security_descriptor *secd; const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL; - void *secd_buf; const void *itr, *top; char buf[64]; + secd = kmalloc(sizeof(struct usb_security_descriptor), GFP_KERNEL); + if (secd == NULL) { + result = -ENOMEM; + goto out; + } + result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, - 0, &secd, sizeof(secd)); + 0, secd, sizeof(struct usb_security_descriptor)); if (result < sizeof(secd)) { dev_err(dev, "Can't read security descriptor or " "not enough data: %d\n", result); - goto error_secd; + goto out; } - secd_size = le16_to_cpu(secd.wTotalLength); - secd_buf = kmalloc(secd_size, GFP_KERNEL); - if (secd_buf == NULL) { + secd_size = le16_to_cpu(secd->wTotalLength); + secd = krealloc(secd, secd_size, GFP_KERNEL); + if (secd == NULL) { dev_err(dev, "Can't allocate space for security descriptors\n"); - goto error_secd_alloc; + goto out; } result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, - 0, secd_buf, secd_size); + 0, secd, secd_size); if (result < secd_size) { dev_err(dev, "Can't read security descriptor or " "not enough data: %d\n", result); - goto error_secd_all; + goto out; } bytes = 0; - itr = secd_buf + sizeof(secd); - top = secd_buf + result; + itr = &secd[1]; + top = (void *)secd + result; while (itr < top) { etd = itr; if (top - itr < sizeof(*etd)) { @@ -259,24 +264,16 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, dev_err(dev, "WUSB device doesn't support CCM1 encryption, " "can't use!\n"); result = -EINVAL; - goto error_no_ccm1; + goto out; } wusb_dev->ccm1_etd = *ccm1_etd; dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n", buf, wusb_et_name(ccm1_etd->bEncryptionType), ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex); result = 0; - kfree(secd_buf); out: + kfree(secd); return result; - - -error_no_ccm1: -error_secd_all: - kfree(secd_buf); -error_secd_alloc: -error_secd: - goto out; } void wusb_dev_sec_rm(struct wusb_dev *wusb_dev) -- cgit v1.2.3 From 171b37ee95865c052a88d52a05895c3c584f4871 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Mon, 12 Oct 2009 15:45:15 +0000 Subject: USB: whci-hcd: handle early deletion of endpoints If an endpoint is deleted before it's been fully added to the hardware list, the associated qset will not be fully initialized and an oops will occur when complete(&qset->remove_complete) is called. This can happen if a queued URB is cancelled. Fix this by only removing the qset from the hardware list if the cancelled URB had qTDs. Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/whci/asl.c | 19 ++++++++++++------- drivers/usb/host/whci/pzl.c | 20 +++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index c632437c7649..14ccbcfc4315 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -305,6 +305,7 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status) struct whc_urb *wurb = urb->hcpriv; struct whc_qset *qset = wurb->qset; struct whc_std *std, *t; + bool has_qtd = false; int ret; unsigned long flags; @@ -315,17 +316,21 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status) goto out; list_for_each_entry_safe(std, t, &qset->stds, list_node) { - if (std->urb == urb) + if (std->urb == urb) { + if (std->qtd) + has_qtd = true; qset_free_std(whc, std); - else + } else std->qtd = NULL; /* so this std is re-added when the qset is */ } - asl_qset_remove(whc, qset); - wurb->status = status; - wurb->is_async = true; - queue_work(whc->workqueue, &wurb->dequeue_work); - + if (has_qtd) { + asl_qset_remove(whc, qset); + wurb->status = status; + wurb->is_async = true; + queue_work(whc->workqueue, &wurb->dequeue_work); + } else + qset_remove_urb(whc, qset, urb, status); out: spin_unlock_irqrestore(&whc->lock, flags); diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index a9e05bac6646..e923633f30c1 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c @@ -333,6 +333,7 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status) struct whc_urb *wurb = urb->hcpriv; struct whc_qset *qset = wurb->qset; struct whc_std *std, *t; + bool has_qtd = false; int ret; unsigned long flags; @@ -343,17 +344,22 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status) goto out; list_for_each_entry_safe(std, t, &qset->stds, list_node) { - if (std->urb == urb) + if (std->urb == urb) { + if (std->qtd) + has_qtd = true; qset_free_std(whc, std); - else + } else std->qtd = NULL; /* so this std is re-added when the qset is */ } - pzl_qset_remove(whc, qset); - wurb->status = status; - wurb->is_async = false; - queue_work(whc->workqueue, &wurb->dequeue_work); - + if (has_qtd) { + pzl_qset_remove(whc, qset); + update_pzl_hw_view(whc); + wurb->status = status; + wurb->is_async = false; + queue_work(whc->workqueue, &wurb->dequeue_work); + } else + qset_remove_urb(whc, qset, urb, status); out: spin_unlock_irqrestore(&whc->lock, flags); -- cgit v1.2.3 From 1f01ca4e0c1d4126eb663f8ea0bab03836099770 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Mon, 12 Oct 2009 15:45:16 +0000 Subject: USB: whci-hcd: always do an update after processing a halted qTD A halted qTD always triggers a hardware list update because the qset was either removed or reactivated. Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/whci/asl.c | 4 ++++ drivers/usb/host/whci/pzl.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index 14ccbcfc4315..562eba108816 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -115,6 +115,10 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) if (status & QTD_STS_HALTED) { /* Ug, an error. */ process_halted_qtd(whc, qset, td); + /* A halted qTD always triggers an update + because the qset was either removed or + reactivated. */ + update |= WHC_UPDATE_UPDATED; goto done; } diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index e923633f30c1..0db3fb2dc03a 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c @@ -121,6 +121,10 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset) if (status & QTD_STS_HALTED) { /* Ug, an error. */ process_halted_qtd(whc, qset, td); + /* A halted qTD always triggers an update + because the qset was either removed or + reactivated. */ + update |= WHC_UPDATE_UPDATED; goto done; } -- cgit v1.2.3 From 12148da6722be3b44c2220206b6ccb80d2d9d8f8 Mon Sep 17 00:00:00 2001 From: Huzaifa Sidhpurwala Date: Mon, 12 Oct 2009 14:34:45 +0530 Subject: USB: option: Support for AIRPLUS MCD650 Datacard Here is a patch for Airplus MCD 650 card Note: This device is with Victor V Kudlak, and he confirmed that this device works with the patch. Signed-off-by: Huzaifa Sidhpurwala Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 43c227027560..65d96b214f95 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -328,6 +328,9 @@ static int option_resume(struct usb_serial *serial); #define ALCATEL_VENDOR_ID 0x1bbb #define ALCATEL_PRODUCT_X060S 0x0000 +/* Airplus products */ +#define AIRPLUS_VENDOR_ID 0x1011 +#define AIRPLUS_PRODUCT_MCD650 0x3198 static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, @@ -589,6 +592,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) }, + { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v1.2.3 From 36f21329d217016f0f212f0752ae595b4a76754d Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 9 Oct 2009 12:28:41 -0700 Subject: USB: ehci: Fix IST boundary checking interval math. When the EHCI driver falls behind in its scheduling, the active stream's first empty microframe may be in the past with respect to the current microframe. The code attempts to move the starting microframe ("start") N number of microframes forward, where N is the interval of endpoint. However, stream->interval is a copy of the endpoint's bInterval, which is designated in frames for FS devices, and microframes for HS devices. Convert stream->interval to microframes before using it to move the starting microframe forward. Acked-by: Alan Stern Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 3efa59b18044..b25cdea93a1f 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1400,6 +1400,10 @@ iso_stream_schedule ( goto fail; } + period = urb->interval; + if (!stream->highspeed) + period <<= 3; + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; /* when's the last uframe this urb could start? */ @@ -1417,8 +1421,8 @@ iso_stream_schedule ( /* Fell behind (by up to twice the slop amount)? */ if (start >= max - 2 * 8 * SCHEDULE_SLOP) - start += stream->interval * DIV_ROUND_UP( - max - start, stream->interval) - mod; + start += period * DIV_ROUND_UP( + max - start, period) - mod; /* Tried to schedule too far into the future? */ if (unlikely((start + sched->span) >= max)) { @@ -1441,10 +1445,6 @@ iso_stream_schedule ( /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ - period = urb->interval; - if (!stream->highspeed) - period <<= 3; - /* find a uframe slot with enough bandwidth */ for (; start < (stream->next_uframe + period); start++) { int enough_space; -- cgit v1.2.3 From b8430e1b82b7e514d76a88eb70a7d8831d50df1e Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 13 Oct 2009 15:53:47 +1100 Subject: usb-storage: Workaround devices with bogus sense size usb-storage: Workaround devices with bogus sense size Some devices, such as Huawei E169, advertise more than the standard amount of sense data, causing us to set US_FL_SANE_SENSE, assuming they support it. However, they subsequently fail the request sense with that size. This works around it generically. When a sense request fails due to a device returning an error, US_FL_SANE_SENSE was set, and that sense request used a larger sense size, we retry with a smaller size before giving up. Based on an original patch by Ben Efros Signed-off-by: Benjamin Herrenschmidt Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 3a4fb023af72..589f6b4404f0 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -696,7 +696,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) /* device supports and needs bigger sense buffer */ if (us->fflags & US_FL_SANE_SENSE) sense_size = ~0; - +Retry_Sense: US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); @@ -720,6 +720,21 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) srb->result = DID_ABORT << 16; goto Handle_Errors; } + + /* Some devices claim to support larger sense but fail when + * trying to request it. When a transport failure happens + * using US_FS_SANE_SENSE, we always retry with a standard + * (small) sense request. This fixes some USB GSM modems + */ + if (temp_result == USB_STOR_TRANSPORT_FAILED && + (us->fflags & US_FL_SANE_SENSE) && + sense_size != US_SENSE_SIZE) { + US_DEBUGP("-- auto-sense failure, retry small sense\n"); + sense_size = US_SENSE_SIZE; + goto Retry_Sense; + } + + /* Other failures */ if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); -- cgit v1.2.3 From 4238ef54690ea502a22aab41c377f23588c387d0 Mon Sep 17 00:00:00 2001 From: Brian Niebuhr Date: Wed, 14 Oct 2009 12:04:33 -0500 Subject: USB: gadget: Fix EEM driver comments and VID/PID Remove expository comments and fix USB VID and PID Signed-off-by: Brian Niebuhr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f37de283d0ab..167cb2a8ecef 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -61,11 +61,6 @@ * simpler, Microsoft pushes their own approach: RNDIS. The published * RNDIS specs are ambiguous and appear to be incomplete, and are also * needlessly complex. They borrow more from CDC ACM than CDC ECM. - * - * While CDC ECM, CDC Subset, and RNDIS are designed to extend the ethernet - * interface to the target, CDC EEM was designed to use ethernet over the USB - * link between the host and target. CDC EEM is implemented as an alternative - * to those other protocols when that communication model is more appropriate */ #define DRIVER_DESC "Ethernet Gadget" @@ -157,8 +152,8 @@ static inline bool has_rndis(void) #define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ /* For EEM gadgets */ -#define EEM_VENDOR_NUM 0x0525 /* INVALID - NEEDS TO BE ALLOCATED */ -#define EEM_PRODUCT_NUM 0xa4a1 /* INVALID - NEEDS TO BE ALLOCATED */ +#define EEM_VENDOR_NUM 0x1d6b /* Linux Foundation */ +#define EEM_PRODUCT_NUM 0x0102 /* EEM Gadget */ /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 0996391139f43d032335b5360db11da62a2cbb39 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 21 Oct 2009 13:20:32 +0100 Subject: ARM: Fix lubbock defconfig build drivers/built-in.o: In function `pxa25x_udc_probe': drivers/usb/gadget/pxa25x_udc.c:2195: undefined reference to `otg_get_transceiver' drivers/usb/gadget/pxa25x_udc.c:2300: undefined reference to `otg_put_transceiver' pxa25x_udc.c unconditionally uses these two functions, so we need to ensure that the object providing them is also built. Signed-off-by: Russell King --- drivers/usb/gadget/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 33351312327f..a18e3c5dd82e 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -223,6 +223,7 @@ config USB_OTG config USB_GADGET_PXA25X boolean "PXA 25x or IXP 4xx" depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX + select USB_OTG_UTILS help Intel's PXA 25x series XScale ARM-5TE processors include an integrated full speed USB 1.1 device controller. The -- cgit v1.2.3 From 3c77d5137d3f4ff41721e9b4f4812db56a6065c0 Mon Sep 17 00:00:00 2001 From: Elina Pasheva Date: Fri, 16 Oct 2009 12:04:54 -0700 Subject: USB: serial: sierra driver send_setup() autopm fix This patch presents a fix for the autosuspend feature implementation in sierra usb serial driver for function sierra_send_setup(). Because it is possible to call sierra_send_setup() before sierra_open() or after sierra_close() we added a get/put interface activity to assure that the usb control can happen even when the device is autosuspended. Signed-off-by: Elina Pasheva Tested-by: Matthew Safar Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 45883988a005..3ec79dfc41fd 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -296,7 +296,6 @@ struct sierra_port_private { int dsr_state; int dcd_state; int ri_state; - unsigned int opened:1; }; @@ -306,6 +305,8 @@ static int sierra_send_setup(struct usb_serial_port *port) struct sierra_port_private *portdata; __u16 interface = 0; int val = 0; + int do_send = 0; + int retval; dev_dbg(&port->dev, "%s\n", __func__); @@ -324,10 +325,7 @@ static int sierra_send_setup(struct usb_serial_port *port) */ if (port->interrupt_in_urb) { /* send control message */ - return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22, 0x21, val, interface, - NULL, 0, USB_CTRL_SET_TIMEOUT); + do_send = 1; } } @@ -339,12 +337,18 @@ static int sierra_send_setup(struct usb_serial_port *port) interface = 1; else if (port->bulk_out_endpointAddress == 5) interface = 2; - return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22, 0x21, val, interface, - NULL, 0, USB_CTRL_SET_TIMEOUT); + + do_send = 1; } - return 0; + if (!do_send) + return 0; + + usb_autopm_get_interface(serial->interface); + retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT); + usb_autopm_put_interface(serial->interface); + + return retval; } static void sierra_set_termios(struct tty_struct *tty, -- cgit v1.2.3 From b64dc0a597fd3c66d888df0886635eba210cc19f Mon Sep 17 00:00:00 2001 From: Elina Pasheva Date: Tue, 27 Oct 2009 13:49:59 -0700 Subject: USB: serial: sierra driver autopm fixes This patch presents fixes for the autosuspend feature implementation in sierra usb serial driver in functions sierra_open(), sierra_close() and stop_read_write_urbs(). The patch "sierra_close() must resume the device before it notifies it of a closure" submitted by Oliver Neukum on Wed, October 14 has been merged as fix in sierra_close() function. The bug fix in sierra_open() function restores the autopm interface state on error condition. The bug fix in in stop_read_write_urbs() function assures that both receive and interrupt urbs are recycled. Signed-off-by: Elina Pasheva Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 3ec79dfc41fd..5019325ba25d 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -777,8 +777,11 @@ static void sierra_close(struct usb_serial_port *port) if (serial->dev) { mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) + if (!serial->disconnected) { + serial->interface->needs_remote_wakeup = 0; + usb_autopm_get_interface(serial->interface); sierra_send_setup(port); + } mutex_unlock(&serial->disc_mutex); spin_lock_irq(&intfdata->susp_lock); portdata->opened = 0; @@ -792,8 +795,6 @@ static void sierra_close(struct usb_serial_port *port) sierra_release_urb(portdata->in_urbs[i]); portdata->in_urbs[i] = NULL; } - usb_autopm_get_interface(serial->interface); - serial->interface->needs_remote_wakeup = 0; } } @@ -831,6 +832,8 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) if (err) { /* get rid of everything as in close */ sierra_close(port); + /* restore balance for autopm */ + usb_autopm_put_interface(serial->interface); return err; } sierra_send_setup(port); @@ -919,7 +922,7 @@ static void sierra_release(struct usb_serial *serial) #ifdef CONFIG_PM static void stop_read_write_urbs(struct usb_serial *serial) { - int i, j; + int i; struct usb_serial_port *port; struct sierra_port_private *portdata; @@ -927,8 +930,7 @@ static void stop_read_write_urbs(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; portdata = usb_get_serial_port_data(port); - for (j = 0; j < N_IN_URB; j++) - usb_kill_urb(portdata->in_urbs[j]); + sierra_stop_rx_urbs(port); usb_kill_anchored_urbs(&portdata->active); } } -- cgit v1.2.3 From 1e6159f858f5da608612ae10d6554bb7ecac9755 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 21 Oct 2009 20:33:39 +0900 Subject: USB: r8a66597-hcd: fix cannot detect a device when uses_new_polling is set Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 749b53742828..e33d36256350 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1003,19 +1003,20 @@ static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port, if (syssts == SE0) { r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port)); r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port)); - return; - } + } else { + if (syssts == FS_JSTS) + r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); + else if (syssts == LS_JSTS) + r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port)); - if (syssts == FS_JSTS) - r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); - else if (syssts == LS_JSTS) - r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port)); + r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); + r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port)); - r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); - r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port)); + if (r8a66597->bus_suspended) + usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597)); + } - if (r8a66597->bus_suspended) - usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597)); + usb_hcd_poll_rh_status(r8a66597_to_hcd(r8a66597)); } /* this function must be called with interrupt disabled */ @@ -1024,6 +1025,8 @@ static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port) u16 speed = get_rh_usb_speed(r8a66597, port); struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; + rh->port &= ~((1 << USB_PORT_FEAT_HIGHSPEED) | + (1 << USB_PORT_FEAT_LOWSPEED)); if (speed == HSMODE) rh->port |= (1 << USB_PORT_FEAT_HIGHSPEED); else if (speed == LSMODE) -- cgit v1.2.3 From fead2ab6cf9ad3a84a06e68ccc20d1e460fad13e Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Thu, 22 Oct 2009 15:00:36 +0800 Subject: USB: option: TLAYTECH TUE800 support Add ID for Tlaytech TUE800 CDMA modem to the option driver. Signed-off-by: Bryan Wu Acked-By: Matthias Urlichs Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 65d96b214f95..cd44c68954df 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -315,6 +315,9 @@ static int option_resume(struct usb_serial *serial); #define QISDA_PRODUCT_H20_4515 0x4515 #define QISDA_PRODUCT_H20_4519 0x4519 +/* TLAYTECH PRODUCTS */ +#define TLAYTECH_VENDOR_ID 0x20B9 +#define TLAYTECH_PRODUCT_TEU800 0x1682 /* TOSHIBA PRODUCTS */ #define TOSHIBA_VENDOR_ID 0x0930 @@ -593,6 +596,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) }, { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, + { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v1.2.3 From 37c4fd8c7551c7419a5faf87a76ff6949c5adaf3 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 29 Oct 2009 19:50:43 +0300 Subject: USB: fsl_udc_core: Fix kernel oops on module removal fsl_udc_release() calls dma_free_coherent() with an inappropriate device passed to it, and since the device has no dma_ops, the following oops pops up: Kernel BUG at d103ce9c [verbose debug info unavailable] Oops: Exception in kernel mode, sig: 5 [#1] ... NIP [d103ce9c] fsl_udc_release+0x50/0x80 [fsl_usb2_udc] LR [d103ce74] fsl_udc_release+0x28/0x80 [fsl_usb2_udc] Call Trace: [cfbc7dc0] [d103ce74] fsl_udc_release+0x28/0x80 [fsl_usb2_udc] [cfbc7dd0] [c01a35c4] device_release+0x2c/0x90 [cfbc7de0] [c016b480] kobject_cleanup+0x58/0x98 [cfbc7e00] [c016c52c] kref_put+0x54/0x6c [cfbc7e10] [c016b360] kobject_put+0x34/0x64 [cfbc7e20] [c01a1d0c] put_device+0x1c/0x2c [cfbc7e30] [d103dbfc] fsl_udc_remove+0xc0/0x1e4 [fsl_usb2_udc] ... This patch fixes the issue by passing dev->parent, which points to a correct device. Signed-off-by: Anton Vorontsov Cc: Li Yang Cc: David Brownell Cc: Guennadi Liakhovetski Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/fsl_udc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 42a74b8a0bb8..fa3d142ba64d 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2139,7 +2139,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, static void fsl_udc_release(struct device *dev) { complete(udc_controller->done); - dma_free_coherent(dev, udc_controller->ep_qh_size, + dma_free_coherent(dev->parent, udc_controller->ep_qh_size, udc_controller->ep_qh, udc_controller->ep_qh_dma); kfree(udc_controller); } -- cgit v1.2.3