Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Jul 2009 00:16:51 +0000 (UTC)
From:      Alfred Perlstein <alfred@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r195966 - head/sys/dev/usb
Message-ID:  <200907300016.n6U0Gp9X086633@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: alfred
Date: Thu Jul 30 00:16:50 2009
New Revision: 195966
URL: http://svn.freebsd.org/changeset/base/195966

Log:
  USB CORE - compat Linux:
  - Patch request from Tim Borgeaud:
  - add automatic locking
  - add refcount for killing URB's
  
  Submitted by:	hps
  Approved by:	re

Modified:
  head/sys/dev/usb/usb_compat_linux.c
  head/sys/dev/usb/usb_compat_linux.h

Modified: head/sys/dev/usb/usb_compat_linux.c
==============================================================================
--- head/sys/dev/usb/usb_compat_linux.c	Thu Jul 30 00:16:32 2009	(r195965)
+++ head/sys/dev/usb/usb_compat_linux.c	Thu Jul 30 00:16:50 2009	(r195966)
@@ -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
 
 		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, uint
 {
 	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, uint
 		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_
 	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_
 	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, 
 		 * 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);
 }
 
 /*------------------------------------------------------------------------*

Modified: head/sys/dev/usb/usb_compat_linux.h
==============================================================================
--- head/sys/dev/usb/usb_compat_linux.h	Thu Jul 30 00:16:32 2009	(r195965)
+++ head/sys/dev/usb/usb_compat_linux.h	Thu Jul 30 00:16:50 2009	(r195966)
@@ -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 */
 };



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200907300016.n6U0Gp9X086633>