Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Jul 2009 16:04:42 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 166559 for review
Message-ID:  <200907251604.n6PG4gAl020170@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=166559

Change 166559 by hselasky@hselasky_laptop001 on 2009/07/25 16:04:38

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

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb_compat_linux.c#45 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_compat_linux.h#21 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/usb_compat_linux.c#45 (text+ko) ====

@@ -398,15 +398,32 @@
 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);
+
+	do_unlock = mtx_owned(&Giant) ? 0 : 1;
+	if (do_unlock)
+		mtx_lock(&Giant);
+
+	if (urb->endpoint == NULL) {
+		err = -EINVAL;
+		goto done;
 	}
-	mtx_assert(&Giant, MA_OWNED);
 
-	if (urb->endpoint == NULL) {
-		return (-EINVAL);
+	/*
+         * 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 @@
 
 		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 @@
 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 @@
 {
 	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_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 @@
 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 @@
 	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 @@
 	err = urb->status;
 
 done:
+	if (do_unlock)
+		mtx_unlock(&Giant);
 	if (err) {
 		*p_actlen = 0;
 	} else {
@@ -638,7 +680,7 @@
 		 * 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 @@
 void
 usb_kill_urb(struct urb *urb)
 {
-	if (usb_unlink_urb_sub(urb, 1)) {
-		/* ignore */
-	}
+	usb_unlink_urb_sub(urb, 1);
 }
 
 /*------------------------------------------------------------------------*

==== //depot/projects/usb/src/sys/dev/usb/usb_compat_linux.h#21 (text+ko) ====

@@ -262,6 +262,7 @@
 	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?200907251604.n6PG4gAl020170>