This removes a lot of racy and buggy code by trying to check the status of the urb.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
return (0);
}
- if (port->write_urb->status == -EINPROGRESS) {
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
spin_lock_irqsave(&priv->lock, flags);
/* To much data for buffer. Reset buffer. */
priv->wrfilled=0;
spin_unlock_irqrestore(&priv->lock, flags);
+ port->write_urb_busy = 0;
return (0);
}
priv->wrfilled=0;
priv->wrsent=0;
spin_unlock_irqrestore(&priv->lock, flags);
+ port->write_urb_busy = 0;
return 0;
}
struct cyberjack_private *priv = usb_get_serial_port_data(port);
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
if( priv->wrfilled ) {
int length, blksize, result;
- if (port->write_urb->status == -EINPROGRESS) {
- dbg("%s - already writing", __FUNCTION__);
- spin_unlock(&priv->lock);
- return;
- }
-
dbg("%s - transmitting data (frame n)", __FUNCTION__);
length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
usb_serial_generic_write_bulk_callback), port);
/* send the data out the bulk port */
+ port->write_urb_busy = 1;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
- else
+ /* don't have to grab the lock here, as we will retry if != 0 */
+ port->write_urb_busy = 0;
+ } else
result = count;
return result;
}
/* no bulk out, so return 0 bytes written */
- return (0);
+ return 0;
}
int usb_serial_generic_write_room (struct usb_serial_port *port)
int room = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
if (serial->num_bulk_out) {
- if (port->write_urb->status != -EINPROGRESS)
+ if (port->write_urb_busy)
room = port->bulk_out_size;
}
dbg("%s - port %d", __FUNCTION__, port->number);
if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS)
+ if (port->write_urb_busy)
chars = port->write_urb->transfer_buffer_length;
}
dbg("%s - port %d", __FUNCTION__, port->number);
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
struct ipaq_packet *pkt, *tmp;
struct urb *urb = port->write_urb;
- if (urb->status == -EINPROGRESS) {
- /* Should never happen */
- err("%s - flushing while urb is active !", __FUNCTION__);
- return;
- }
room = URBDATA_SIZE;
list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
count = min(room, (int)(pkt->len - pkt->written));
dbg("%s - write request of 0 bytes", __FUNCTION__);
return 0;
}
-
- /* Racy and broken, FIXME properly! */
- if (port->write_urb->status == -EINPROGRESS)
+
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
return 0;
+ }
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = min(count, port->bulk_out_size);
memcpy(port->bulk_out_buffer, buf, count);
dbg("%s count now:%d", __FUNCTION__, count);
-
+
usb_fill_bulk_urb(port->write_urb, dev,
usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer,
ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (ret != 0) {
+ port->write_urb_busy = 0;
dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret);
return ret;
}
if (count == 0)
return 0;
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("%s - already writing", __FUNCTION__);
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
transfer_buffer = port->write_urb->transfer_buffer;
transfer_size = min(count, port->bulk_out_size - 1);
port->write_urb->transfer_flags = URB_ZERO_PACKET;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
+ port->write_urb_busy = 0;
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
- else
+ } else
result = transfer_size;
return result;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
- if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {
- return( 0 );
+ spin_lock(&port->lock);
+ if (port->write_urb_busy || priv->tx_throttled) {
+ spin_unlock(&port->lock);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
/* At this point the URB is in our control, nobody else can submit it
again (the only sudden transition was the one from EINPROGRESS to
memcpy (port->write_urb->transfer_buffer, buf, count);
/* send the data out the bulk port */
port->write_urb->transfer_buffer_length = count;
-
+
priv->tx_room -= count;
port->write_urb->dev = port->serial->dev;
rc = count;
exit:
+ if (rc < 0)
+ port->write_urb_busy = 0;
return rc;
}
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct keyspan_pda_private *priv;
+ port->write_urb_busy = 0;
priv = usb_get_serial_port_data(port);
/* queue up a wakeup at scheduler time */
static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
struct keyspan_pda_private *priv;
-
+
priv = usb_get_serial_port_data(port);
-
+
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
- if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )
+ if (port->write_urb_busy || priv->tx_throttled)
return 256;
return 0;
}
dbg("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
- if (wport->write_urb->status == -EINPROGRESS) {
+
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
wport->write_urb->dev = serial->dev;
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
+ port->write_urb_busy = 0;
err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
- else
+ } else
result = count;
return result;
int room = 0; // Default: no room
- if (wport->write_urb->status != -EINPROGRESS)
+ if (wport->write_urb_busy)
room = wport->bulk_out_size - OMNINET_HEADERLEN;
// dbg("omninet_write_room returns %d", room);
// dbg("omninet_write_bulk_callback, port %0x\n", port);
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
dbg ("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("%s - already writing", __FUNCTION__);
- return (0);
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
packet_length = port->bulk_out_size; // get max packetsize
#endif
port->write_urb->dev = port->serial->dev;
if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
+ port->write_urb_busy = 0;
err ("%s - failed submitting write urb, error %d", __FUNCTION__, result);
return 0;
}
dbg ("%s", __FUNCTION__);
- if (port->write_urb->status != -EINPROGRESS)
+ if (port->write_urb_busy)
room = port->bulk_out_size - (safe ? 2 : 0);
if (room) {
memset(port, 0x00, sizeof(struct usb_serial_port));
port->number = i + serial->minor;
port->serial = serial;
+ spin_lock_init(&port->lock);
INIT_WORK(&port->work, usb_serial_port_softint, port);
serial->port[i] = port;
}
* usb_serial_port: structure for the specific ports of a device.
* @serial: pointer back to the struct usb_serial owner of this port.
* @tty: pointer to the corresponding tty for this port.
+ * @lock: spinlock to grab when updating portions of this structure.
* @number: the number of the port (the minor number).
* @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
* @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
struct usb_serial_port {
struct usb_serial * serial;
struct tty_struct * tty;
+ spinlock_t lock;
unsigned char number;
unsigned char * interrupt_in_buffer;
unsigned char * bulk_out_buffer;
int bulk_out_size;
struct urb * write_urb;
+ int write_urb_busy;
__u8 bulk_out_endpointAddress;
wait_queue_head_t write_wait;