Re: usbrsa: dead lock usbrsa_write/usbrsa_write_room

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello

> But first, why are you reimplementing the write functionality -- why not
> reuse the generic implementation?
The USB-RSA has a TX buffer of 4 Kbytes. To be able to take advantage of it, I 
implemented a streaming mechanism using the whiteheat driver as role model. I 
have not fully finished it yet -- as of now, the inner loop is redundant.

> You need to call usb_serial_port_softint from your completion handler.
That did the trick -- no more stalling. Thanks.

I however still observe the buffering effect, i.e. characters sent from the 
USBRSA to a serial port is not directly dumped but buffered, and eventually 
displayed by cat. Can I set the buffer size somehow or control flushing ? 

Thanks
Tilman

Here the source for the write routine and the write handler:

static int  usbrsa_write(struct tty_struct *tty,
                        struct usb_serial_port *port,
                        const unsigned char *buf, int count)
{
	struct usb_serial*			serial = port->serial;
	struct usbrsa_port_private*	priv = usb_get_serial_port_data(port);
	unsigned long				flags;
	int 						retval;
	int						
	nof_bytes_to_be_sent;
	int 						bytes;   
	int							urb_index;
	int							sent = 0;
	struct urb*					urb;
	
	dbg("%s - port %d START", __func__, port->number);

	while (count > 0)
	{
		// transfer only as many bytes as USB-RSA can take
		nof_bytes_to_be_sent = (count > priv->nofTxBytesFree) ? 
				priv->nofTxBytesFree : count;
		dbg("%s - port %d; bytes=%d := count=%d : nofTxBytesFree=%d",
				__func__, port->number,
				nof_bytes_to_be_sent,count,
				priv->nofTxBytesFree);
		
		// debug 
		nof_bytes_to_be_sent = count;
		// end debug
		while (nof_bytes_to_be_sent > 0)
		{
			// check for empty urb in write pool
			spin_lock_irqsave(&priv->lock, flags);
			urb_index = 
					find_first_zero_bit(&priv-
>write_urb_pool_lock,
							priv->urb_pool_size);

			dbg("%s - poolsize  %d, urb_index %d\n",__func__, priv-
>urb_pool_size,urb_index);
			if (urb_index >= priv->urb_pool_size)
			{
				// no more urbs available
				spin_unlock_irqrestore(&priv->lock, flags);
				goto out_write_no_urbs;
			}

			dbg("%s - port %d;URB allocated=%d",__func__, port-
>number,urb_index);
			// reserve urb
			set_bit(urb_index, &priv->write_urb_pool_lock);
			urb = priv->write_urb_pool[urb_index];

			spin_unlock_irqrestore(&priv->lock, flags);

			// copy data from userspace into urb transfer buffer
			bytes = (nof_bytes_to_be_sent > port->bulk_out_size) ?
					port->bulk_out_size : 
nof_bytes_to_be_sent;
			memcpy(urb->transfer_buffer, buf + sent, bytes);
			dbg("%s - port %d;bytes in urb=%d",__func__, port-
>number, bytes);
			usb_serial_debug_data(debug, &port->dev,
					__func__, bytes, urb->transfer_buffer);
			urb->dev = serial->dev;
			urb->transfer_buffer_length = bytes;

			// sent urb to USB-RSA
			retval = usb_submit_urb(urb, GFP_ATOMIC);

			if (retval) 
			{
				// return urb to pool
				spin_lock_irqsave(&priv->lock, flags);
				clear_bit(urb_index, &priv-
>write_urb_pool_lock);
				spin_unlock_irqrestore(&priv->lock, flags);
				dev_err(&port->dev,
						"%s - failed submitting write 
urb, error %d\n",
						__func__, retval);
				sent = retval;

				// bail out
				goto out_write_submit_failed;
			} 
			else 
			{
				sent += bytes;
				count -= bytes;
				nof_bytes_to_be_sent -= bytes;
				dbg("%s - port %d;sent=%d;count=%d; 
nof_bytes_to_be_sent=%d;bytes=%d",
						__func__, port->number, 
sent,count, nof_bytes_to_be_sent,
						bytes);
			} 
		}
	}
	out_write_no_urbs:
	out_write_submit_failed:
	dbg("%s() End - sent=%d\n",__func__,sent);
	return sent;
}

static void  usbrsa_write_callback(struct urb *urb)
{
	struct usb_serial_port* 	port 	= urb->context;
	struct usbrsa_port_private*	priv 	= usb_get_serial_port_data
(port);
	int 						status	= urb->status;
	unsigned long				flags;
	int							urb_index;
	
	dbg("%s() - port = %d, ep =0x%x", __func__, port->number,
				priv->status_urb->pipe);
	
	usb_serial_debug_data(debug, &port->dev, __func__,
				urb->actual_length, urb->transfer_buffer);
	// find urb in write pool
	for (urb_index=0; urb_index < priv->urb_pool_size;urb_index++)
	{
		if (urb == priv->write_urb_pool[urb_index])
		{
			// urb found; return urb to pool
			spin_lock_irqsave(&priv->lock, flags);
			clear_bit(urb_index, &priv->write_urb_pool_lock);
			spin_unlock_irqrestore(&priv->lock, flags);
			break;
		}
	}
	
	if (urb != priv->write_urb_pool[urb_index])
	{
		// urb not found -- this points to a bug
		dev_err(&port->dev, "%s(): urb not in pool",
				__func__);
	}
	dbg("%s(): Returned URB %d",__func__, urb_index);
	if (status)
	{
		dbg("%s(): nonzero urb status: 0x%d", __func__, status);
	}
        usb_serial_port_softint(port);
}








--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux