Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 17 Dec 2008 04:35:31 GMT
From:      Weongyo Jeong <weongyo@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 154848 for review
Message-ID:  <200812170435.mBH4ZVUH096207@repoman.freebsd.org>

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

Change 154848 by weongyo@weongyo_ws on 2008/12/17 04:35:04

	fix a page fault that it occured at ZD1211B USB adapter.

Affected files ...

.. //depot/projects/ndisusb/sys/compat/ndis/subr_usbd.c#25 edit

Differences ...

==== //depot/projects/ndisusb/sys/compat/ndis/subr_usbd.c#25 (text+ko) ====

@@ -115,6 +115,8 @@
 static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
 		    usb_config_descriptor_t *, uint8_t, uint8_t);
 
+#define	USBD_STATUS_IIN_ERROR	0x1
+static int usbd_iin_error;
 /*
  * We need to wrap these functions because these need `context switch' from
  * Windows to UNIX before it's called.
@@ -931,8 +933,34 @@
 	usbd_private_handle priv;
 	usbd_status status;
 {
+	int set = 0;
+
+	/*
+	 * We should handle the interrupt IN pipe specially.  For a example,
+	 * ZD1211B NDIS driver uses the interrupt IN pipe so we opens its pipe
+	 * using usbd_open_pipe_intr().  In a case of we forcibly plug out
+	 * the ZD1211B USB adapter then firstly usbd_open_pipe_intr() calls our
+	 * callback function whose the value of the status is USBD_IOERROR.
+	 * As a next return, sometimes it returns USBD_CANCELLED.  The problem
+	 * is that at this case when we get USBD_IOERROR status we try to free
+	 * IRP related with the interrupt IN pipe.  As next if we get
+	 * USBD_CANCELLED, in the previous we tried to free again so it causes
+	 * a page fault.  I don't know why the USB framework reports errors
+	 * twice.  To solve this problem we only handle first error.
+	 *
+	 * XXX I don't want to use a global variable and don't like this like
+	 * a hack but no way to pass `sc' safely because `priv' can be a pointer
+	 * which already be freed.
+	 */
+	if (status == USBD_NORMAL_COMPLETION)
+		usbd_iin_error &= ~USBD_STATUS_IIN_ERROR;
+	if (status == USBD_IOERROR) {
+		usbd_iin_error |= USBD_STATUS_IIN_ERROR;
+		set = 1;
+	}
 
-	usbd_xferadd(xfer, priv, status, 0);
+	if ((!(usbd_iin_error & USBD_STATUS_IIN_ERROR)) || set == 1)
+		usbd_xferadd(xfer, priv, status, 0);
 }
 
 static void



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