USB CORE - compat Linux:

- Patch request from Tim Borgeaud:
- add automatic locking
- add refcount for killing URB's

Submitted by:	hps
Approved by:	re
This commit is contained in:
Alfred Perlstein 2009-07-30 00:16:50 +00:00
parent a0c61406ad
commit bf3254f22e
2 changed files with 59 additions and 18 deletions

View File

@ -398,15 +398,32 @@ int
usb_submit_urb(struct urb *urb, uint16_t mem_flags)
{
struct usb_host_endpoint *uhe;
uint8_t do_unlock;
int err;
if (urb == NULL) {
if (urb == NULL)
return (-EINVAL);
}
mtx_assert(&Giant, MA_OWNED);
do_unlock = mtx_owned(&Giant) ? 0 : 1;
if (do_unlock)
mtx_lock(&Giant);
if (urb->endpoint == NULL) {
return (-EINVAL);
err = -EINVAL;
goto done;
}
/*
* Check to see if the urb is in the process of being killed
* and stop a urb that is in the process of being killed from
* being re-submitted (e.g. from its completion callback
* function).
*/
if (urb->kill_count != 0) {
err = -EPERM;
goto done;
}
uhe = urb->endpoint;
/*
@ -424,12 +441,16 @@ usb_submit_urb(struct urb *urb, uint16_t mem_flags)
usbd_transfer_start(uhe->bsd_xfer[0]);
usbd_transfer_start(uhe->bsd_xfer[1]);
err = 0;
} else {
/* no pipes have been setup yet! */
urb->status = -EINVAL;
return (-EINVAL);
err = -EINVAL;
}
return (0);
done:
if (do_unlock)
mtx_unlock(&Giant);
return (err);
}
/*------------------------------------------------------------------------*
@ -448,9 +469,11 @@ static void
usb_unlink_bsd(struct usb_xfer *xfer,
struct urb *urb, uint8_t drain)
{
if (xfer &&
usbd_transfer_pending(xfer) &&
(xfer->priv_fifo == (void *)urb)) {
if (xfer == NULL)
return;
if (!usbd_transfer_pending(xfer))
return;
if (xfer->priv_fifo == (void *)urb) {
if (drain) {
mtx_unlock(&Giant);
usbd_transfer_drain(xfer);
@ -467,14 +490,21 @@ usb_unlink_urb_sub(struct urb *urb, uint8_t drain)
{
struct usb_host_endpoint *uhe;
uint16_t x;
uint8_t do_unlock;
int err;
if (urb == NULL) {
if (urb == NULL)
return (-EINVAL);
}
mtx_assert(&Giant, MA_OWNED);
do_unlock = mtx_owned(&Giant) ? 0 : 1;
if (do_unlock)
mtx_lock(&Giant);
if (drain)
urb->kill_count++;
if (urb->endpoint == NULL) {
return (-EINVAL);
err = -EINVAL;
goto done;
}
uhe = urb->endpoint;
@ -504,7 +534,13 @@ usb_unlink_urb_sub(struct urb *urb, uint8_t drain)
usb_unlink_bsd(uhe->bsd_xfer[0], urb, drain);
usb_unlink_bsd(uhe->bsd_xfer[1], urb, drain);
}
return (0);
err = 0;
done:
if (drain)
urb->kill_count--;
if (do_unlock)
mtx_unlock(&Giant);
return (err);
}
/*------------------------------------------------------------------------*
@ -555,6 +591,7 @@ static int
usb_start_wait_urb(struct urb *urb, usb_timeout_t timeout, uint16_t *p_actlen)
{
int err;
uint8_t do_unlock;
/* you must have a timeout! */
if (timeout == 0) {
@ -565,6 +602,9 @@ usb_start_wait_urb(struct urb *urb, usb_timeout_t timeout, uint16_t *p_actlen)
urb->transfer_flags |= URB_WAIT_WAKEUP;
urb->transfer_flags &= ~URB_IS_SLEEPING;
do_unlock = mtx_owned(&Giant) ? 0 : 1;
if (do_unlock)
mtx_lock(&Giant);
err = usb_submit_urb(urb, 0);
if (err)
goto done;
@ -582,6 +622,8 @@ usb_start_wait_urb(struct urb *urb, usb_timeout_t timeout, uint16_t *p_actlen)
err = urb->status;
done:
if (do_unlock)
mtx_unlock(&Giant);
if (err) {
*p_actlen = 0;
} else {
@ -638,7 +680,7 @@ usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe,
* transfers on control endpoint zero:
*/
err = usbd_do_request_flags(dev,
&Giant, &req, data, USB_SHORT_XFER_OK,
NULL, &req, data, USB_SHORT_XFER_OK,
&actlen, timeout);
if (err) {
err = -EPIPE;
@ -1216,9 +1258,7 @@ usb_init_urb(struct urb *urb)
void
usb_kill_urb(struct urb *urb)
{
if (usb_unlink_urb_sub(urb, 1)) {
/* ignore */
}
usb_unlink_urb_sub(urb, 1);
}
/*------------------------------------------------------------------------*

View File

@ -262,6 +262,7 @@ struct urb {
uint8_t setup_dma; /* (in) not used on FreeBSD */
uint8_t transfer_dma; /* (in) not used on FreeBSD */
uint8_t bsd_isread;
uint8_t kill_count; /* FreeBSD specific */
struct usb_iso_packet_descriptor iso_frame_desc[]; /* (in) ISO ONLY */
};