PERFORCE change 157961 for review

Hans Petter Selasky hselasky at FreeBSD.org
Thu Feb 19 14:21:57 PST 2009


http://perforce.freebsd.org/chv.cgi?CH=157961

Change 157961 by hselasky at hselasky_laptop001 on 2009/02/19 22:21:40

	
	USB NDIS support:
	
	 - Upgrade old USB NDIS driver to support USB2.
	 - The code needs testing!

Affected files ...

.. //depot/projects/usb/src/sys/compat/ndis/kern_ndis.c#8 edit
.. //depot/projects/usb/src/sys/compat/ndis/kern_windrv.c#4 edit
.. //depot/projects/usb/src/sys/compat/ndis/ntoskrnl_var.h#7 edit
.. //depot/projects/usb/src/sys/compat/ndis/subr_ndis.c#11 edit
.. //depot/projects/usb/src/sys/compat/ndis/subr_usbd.c#3 edit
.. //depot/projects/usb/src/sys/compat/ndis/usbd_var.h#3 edit
.. //depot/projects/usb/src/sys/dev/if_ndis/if_ndis.c#16 edit
.. //depot/projects/usb/src/sys/dev/if_ndis/if_ndis_pccard.c#4 edit
.. //depot/projects/usb/src/sys/dev/if_ndis/if_ndis_pci.c#4 edit
.. //depot/projects/usb/src/sys/dev/if_ndis/if_ndis_usb.c#10 edit
.. //depot/projects/usb/src/sys/dev/if_ndis/if_ndisvar.h#8 edit
.. //depot/projects/usb/src/sys/modules/if_ndis/Makefile#4 edit
.. //depot/projects/usb/src/sys/modules/ndis/Makefile#5 edit

Differences ...

==== //depot/projects/usb/src/sys/compat/ndis/kern_ndis.c#8 (text+ko) ====

@@ -65,9 +65,6 @@
 #include <net80211/ieee80211_var.h>
 #include <net80211/ieee80211_ioctl.h>
 
-#include <dev/usb/usb.h>
-#include <dev/usb/usbdi.h>
-
 #include <compat/ndis/pe_var.h>
 #include <compat/ndis/cfg_var.h>
 #include <compat/ndis/resource_var.h>

==== //depot/projects/usb/src/sys/compat/ndis/kern_windrv.c#4 (text+ko) ====

@@ -56,9 +56,6 @@
 #include <machine/segments.h>
 #endif
 
-#include <dev/usb/usb.h>
-#include <dev/usb/usbdi.h>
-
 #include <compat/ndis/pe_var.h>
 #include <compat/ndis/cfg_var.h>
 #include <compat/ndis/resource_var.h>

==== //depot/projects/usb/src/sys/compat/ndis/ntoskrnl_var.h#7 (text+ko) ====

@@ -1009,7 +1009,7 @@
 #define irp_pkttype		s2.u2.irp_pkttype
 
 #define	IRP_NDIS_DEV(irp)	(irp)->irp_tail.irp_misc.irp_usb.irp_dev
-#define	IRP_NDISUSB_XFER(irp)	(irp)->irp_tail.irp_misc.irp_usb.irp_xfer
+#define	IRP_NDISUSB_EP(irp)	(irp)->irp_tail.irp_misc.irp_usb.irp_xfer
 
 typedef struct irp irp;
 

==== //depot/projects/usb/src/sys/compat/ndis/subr_ndis.c#11 (text+ko) ====

@@ -95,8 +95,6 @@
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
-#include <dev/usb/usb.h>
-#include <dev/usb/usbdi.h>
 
 #include <compat/ndis/pe_var.h>
 #include <compat/ndis/cfg_var.h>

==== //depot/projects/usb/src/sys/compat/ndis/subr_usbd.c#3 (text+ko) ====

@@ -56,12 +56,16 @@
 #include <net80211/ieee80211_var.h>
 #include <net80211/ieee80211_ioctl.h>
 
-#include <dev/usb/usb.h>
-#include <dev/usb/usbdi.h>
-#include <dev/usb/usbdi_util.h>
-#include <dev/usb/usbdivar.h>
-#include <dev/usb/usb_quirks.h>
-#include "usbdevs.h"
+#include <dev/usb2/include/usb2_error.h>
+#include <dev/usb2/include/usb2_standard.h>
+#include <dev/usb2/include/usb2_defs.h>
+
+#include <dev/usb2/core/usb2_core.h>
+#include <dev/usb2/core/usb2_request.h>
+#include <dev/usb2/core/usb2_process.h>
+#include <dev/usb2/core/usb2_device.h>
+#include <dev/usb2/core/usb2_busdma.h>
+#include <dev/usb2/core/usb2_parse.h>
 
 #include <compat/ndis/pe_var.h>
 #include <compat/ndis/cfg_var.h>
@@ -73,55 +77,45 @@
 #include <dev/if_ndis/if_ndisvar.h>
 
 static driver_object usbd_driver;
+static usb2_callback_t ndis_non_isoc_callback;
 
-static int32_t		 usbd_func_bulkintr(irp *);
-static int32_t		 usbd_func_vendorclass(irp *);
-static int32_t		 usbd_func_selconf(irp *);
-static int32_t		 usbd_func_getdesc(irp *);
-static usbd_status	 usbd_get_desc_ndis(usbd_device_handle, int, int, int,
-			    void *, int *);
-static union usbd_urb	*usbd_geturb(irp *);
-static usbd_status	 usbd_init_ndispipe(irp *, usb_endpoint_descriptor_t *);
-static usbd_xfer_handle	 usbd_init_ndisxfer(irp *, usb_endpoint_descriptor_t *,
-			    void *, uint32_t);
-static int32_t		 usbd_iodispatch(device_object *, irp *);
-static int32_t		 usbd_ioinvalid(device_object *, irp *);
-static int32_t		 usbd_pnp(device_object *, irp *);
-static int32_t		 usbd_power(device_object *, irp *);
-static void		 usbd_irpcancel(device_object *, irp *);
-static void		 usbd_irpcancel_cb(void *);
-static int32_t		 usbd_submit_urb(irp *);
-static int32_t		 usbd_urb2nt(int32_t);
-static void		 usbd_xfereof(usbd_xfer_handle, usbd_private_handle,
-			    usbd_status);
-static void		 usbd_xferadd(usbd_xfer_handle, usbd_private_handle,
-			    usbd_status);
-static void		 usbd_xfertask(device_object *, void *);
-static void		 dummy(void);
+/* prototypes */
 
-static union usbd_urb	*USBD_CreateConfigurationRequestEx(
-			    usb_config_descriptor_t *,
-			    struct usbd_interface_list_entry *);
-static union usbd_urb	*USBD_CreateConfigurationRequest(
-			    usb_config_descriptor_t *,
-			    uint16_t *);
-static void		 USBD_GetUSBDIVersion(usbd_version_info *);
-static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
-			    usb_config_descriptor_t *, void *, int32_t, int32_t,
-			    int32_t, int32_t, int32_t);
-static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
-		    usb_config_descriptor_t *, uint8_t, uint8_t);
+static void usbd_enqueue_ubi(struct ndisusb_ep *nuep, struct usbd_urb_bulk_or_intr_transfer *ubi);
+static struct usbd_urb_bulk_or_intr_transfer * usbd_first_ubi(struct ndisusb_ep *nuep);
+static void usbd_remove_ubi(struct ndisusb_ep *nuep, struct usbd_urb_bulk_or_intr_transfer *ubi);
+static struct ndisusb_ep *usbd_get_ndisusb_ep(struct ndis_softc *sc, uint8_t ep_addr);
+static int32_t usbd_iodispatch(device_object *dobj, irp *ip);
+static int32_t usbd_ioinvalid(device_object *dobj, irp *ip);
+static int32_t usbd_pnp(device_object *dobj, irp *ip);
+static int32_t usbd_power(device_object *dobj, irp *ip);
+static int32_t usbd_urb2nt(int32_t status);
+static int32_t usbd_usb2urb(int32_t status);
+static union usbd_urb *usbd_geturb(irp *ip);
+static int32_t usbd_submit_urb(irp *ip);
+static int32_t usbd_func_getdesc(irp *ip);
+static usb2_error_t usbd_get_desc_ndis(struct usb2_device *udev, struct mtx *mtx, uint16_t id, uint16_t maxlen, uint8_t type, uint8_t index, uint8_t retries, void *desc, uint16_t *actlen);
+static int32_t usbd_func_selconf(irp *ip);
+static int32_t usbd_func_vendorclass(irp *ip);
+static void usbd_irpcancel(device_object *dobj, irp *ip);
+static int32_t ndis_setup_endpoint(struct ndis_softc *sc, uint8_t iface_index, struct usb2_endpoint_descriptor *edesc, uint32_t bufsize);
+static void ndis_xfer_complete(struct ndisusb_ep *nuep, int32_t status);
+static int32_t usbd_func_bulkintr(irp *ip);
+static union usbd_urb *USBD_CreateConfigurationRequest(struct usb2_config_descriptor *conf, uint16_t *len);
+static union usbd_urb *USBD_CreateConfigurationRequestEx(struct usb2_config_descriptor *conf, struct usbd_interface_list_entry *list);
+static void USBD_GetUSBDIVersion(usbd_version_info *ui);
+static struct usb2_interface_descriptor *USBD_ParseConfigurationDescriptorEx(struct usb2_config_descriptor *conf, void *start, int32_t intfnum, int32_t altset, int32_t intfclass, int32_t intfsubclass, int32_t intfproto);
+static void dummy(void);
 
 /*
- * We need to wrap these functions because these need `context switch' from
- * Windows to UNIX before it's called.
+ * We need to wrap these functions because these need `context switch'
+ * from Windows to UNIX before it's called.
  */
 static funcptr usbd_iodispatch_wrap;
 static funcptr usbd_ioinvalid_wrap;
 static funcptr usbd_pnp_wrap;
 static funcptr usbd_power_wrap;
 static funcptr usbd_irpcancel_wrap;
-static funcptr usbd_xfertask_wrap;
 
 int
 usbd_libinit(void)
@@ -147,8 +141,6 @@
 	    (funcptr *)&usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
 	windrv_wrap((funcptr)usbd_irpcancel,
 	    (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
-	windrv_wrap((funcptr)usbd_xfertask,
-	    (funcptr *)&usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
 
 	/* Create a fake USB driver instance. */
 
@@ -156,7 +148,7 @@
 
 	/* Set up our dipatch routine. */
 	for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
-                usbd_driver.dro_dispatch[i] =
+		usbd_driver.dro_dispatch[i] =
 			(driver_dispatch)usbd_ioinvalid_wrap;
 
 	usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
@@ -187,17 +179,62 @@
 	windrv_unwrap(usbd_pnp_wrap);
 	windrv_unwrap(usbd_power_wrap);
 	windrv_unwrap(usbd_irpcancel_wrap);
-	windrv_unwrap(usbd_xfertask_wrap);
 
 	free(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
 
 	return(0);
 }
 
+static void
+usbd_enqueue_ubi(struct ndisusb_ep *nuep,
+    struct usbd_urb_bulk_or_intr_transfer *ubi)
+{
+	/* code taken from TAILQ_ENQUEUE_TAIL() macro */
+	ubi->ubi_hca.reserved8[0] = NULL;
+	ubi->ubi_hca.reserved8[1] = nuep->ubi_last;
+	*nuep->ubi_last = ubi;
+	nuep->ubi_last = (struct usbd_urb_bulk_or_intr_transfer **)
+	    &ubi->ubi_hca.reserved8[0];
+}
+
+static struct usbd_urb_bulk_or_intr_transfer *
+usbd_first_ubi(struct ndisusb_ep *nuep)
+{
+	return (nuep->ubi_first);
+}
+
+static void
+usbd_remove_ubi(struct ndisusb_ep *nuep, 
+    struct usbd_urb_bulk_or_intr_transfer *ubi)
+{
+	/* code taken from TAILQ_REMOVE() macro */
+
+	if (ubi->ubi_hca.reserved8[0] != NULL)
+		((struct usbd_urb_bulk_or_intr_transfer *)
+		 ubi->ubi_hca.reserved8[0])->ubi_hca.reserved8[1] =
+		    ubi->ubi_hca.reserved8[1];
+	else
+		nuep->ubi_last = ubi->ubi_hca.reserved8[1];
+	*((void **)ubi->ubi_hca.reserved8[1]) = ubi->ubi_hca.reserved8[0];
+}
+
+static struct ndisusb_ep *
+usbd_get_ndisusb_ep(struct ndis_softc *sc, uint8_t ep_addr)
+{
+	struct ndisusb_ep *nuep;
+
+	nuep = &sc->ndisusb_ep[((ep_addr & 0x80) >> 7) | 
+	    ((ep_addr & 0x0F) << 1)];
+
+	/* check if endpoint is not properly setup */
+	if (nuep->urb_xfer[0] == NULL)
+		return (NULL);
+
+	return (nuep);
+}
+
 static int32_t
-usbd_iodispatch(dobj, ip)
-	device_object		*dobj;
-	irp			*ip;
+usbd_iodispatch(device_object *dobj, irp *ip)
 {
 	device_t dev = dobj->do_devext;
 	int32_t status;
@@ -227,9 +264,7 @@
 }
 
 static int32_t
-usbd_ioinvalid(dobj, ip)
-	device_object		*dobj;
-	irp			*ip;
+usbd_ioinvalid(device_object *dobj, irp *ip)
 {
 	device_t dev = dobj->do_devext;
 	struct io_stack_location *irp_sl;
@@ -247,9 +282,7 @@
 }
 
 static int32_t
-usbd_pnp(dobj, ip)
-	device_object		*dobj;
-	irp			*ip;
+usbd_pnp(device_object *dobj, irp *ip)
 {
 	device_t dev = dobj->do_devext;
 	struct io_stack_location *irp_sl;
@@ -267,9 +300,7 @@
 }
 
 static int32_t
-usbd_power(dobj, ip)
-	device_object		*dobj;
-	irp			*ip;
+usbd_power(device_object *dobj, irp *ip)
 {
 	device_t dev = dobj->do_devext;
 	struct io_stack_location *irp_sl;
@@ -288,8 +319,7 @@
 
 /* Convert USBD_STATUS to NTSTATUS  */
 static int32_t
-usbd_urb2nt(status)
-	int32_t			status;
+usbd_urb2nt(int32_t status)
 {
 
 	switch (status) {
@@ -314,42 +344,35 @@
 	return (STATUS_FAILURE);
 }
 
-/* Convert FreeBSD's usbd_status to USBD_STATUS  */
+/* Convert FreeBSD's USB_ERR_XXX to USBD_STATUS_XXX  */
 static int32_t
-usbd_usb2urb(int status)
+usbd_usb2urb(int32_t status)
 {
 
 	switch (status) {
-	case USBD_NORMAL_COMPLETION:
+	case USB_ERR_NORMAL_COMPLETION:
 		return (USBD_STATUS_SUCCESS);
-	case USBD_IN_PROGRESS:
-		return (USBD_STATUS_PENDING);
-	case USBD_TIMEOUT:
+	case USB_ERR_TIMEOUT:
 		return (USBD_STATUS_TIMEOUT);
-	case USBD_SHORT_XFER:
+	case USB_ERR_SHORT_XFER:
 		return (USBD_STATUS_ERROR_SHORT_TRANSFER);
-	case USBD_IOERROR:
+	case USB_ERR_IOERROR:
 		return (USBD_STATUS_XACT_ERROR);
-	case USBD_NOMEM:
+	case USB_ERR_NOMEM:
 		return (USBD_STATUS_NO_MEMORY);
-	case USBD_INVAL:
+	case USB_ERR_STALLED:
+		return (USBD_STATUS_STALL_PID);
+	case USB_ERR_INVAL:
 		return (USBD_STATUS_REQUEST_FAILED);
-	case USBD_NOT_STARTED:
-	case USBD_TOO_DEEP:
-	case USBD_NO_POWER:
-		return (USBD_STATUS_DEVICE_GONE);
-	case USBD_CANCELLED:
+	case USB_ERR_CANCELLED:
 		return (USBD_STATUS_CANCELED);
 	default:
-		break;
+		return (USBD_STATUS_NOT_SUPPORTED);
 	}
-	
-	return (USBD_STATUS_NOT_SUPPORTED);
 }
 
 static union usbd_urb *
-usbd_geturb(ip)
-	irp			*ip;
+usbd_geturb(irp *ip)
 {
 	struct io_stack_location *irp_sl;
 
@@ -359,8 +382,7 @@
 }
 
 static int32_t
-usbd_submit_urb(ip)
-	irp			*ip;
+usbd_submit_urb(irp *ip)
 {
 	device_t dev = IRP_NDIS_DEV(ip);
 	int32_t status;
@@ -369,14 +391,13 @@
 	urb = usbd_geturb(ip);
 	/*
 	 * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
-	 * USBD_URB_STATUS(urb) would be set at callback functions like
-	 * usbd_intr() or usbd_xfereof().
+	 * USBD_URB_STATUS(urb) would be set at the transfer
+	 * completion callback functions.
 	 */
 	switch (urb->uu_hdr.uuh_func) {
 	case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
 		status = usbd_func_bulkintr(ip);
-		if (status != USBD_STATUS_SUCCESS &&
-		    status != USBD_STATUS_PENDING)
+		if (status != USBD_STATUS_PENDING)
 			USBD_URB_STATUS(urb) = status;
 		break;
 	case URB_FUNCTION_VENDOR_DEVICE:
@@ -409,181 +430,151 @@
 }
 
 static int32_t
-usbd_func_getdesc(ip)
-	irp			*ip;
+usbd_func_getdesc(irp *ip)
 {
 	device_t dev = IRP_NDIS_DEV(ip);
-	int actlen, i;
-	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	struct ndis_softc *sc;
+	union usbd_urb *urb;
 	struct usbd_urb_control_descriptor_request *ctldesc;
-	uint32_t len;
-	union usbd_urb *urb;
-	usb_config_descriptor_t cd, *cdp;
-	usbd_status status;
+	struct usb2_config_descriptor *cd;
+	uint16_t actlen;
+	uint16_t len;
+	usb2_error_t status;
 
-	mtx_lock(&Giant);
-
+	sc = device_get_softc(dev);
 	urb = usbd_geturb(ip);
 	ctldesc = &urb->uu_ctldesc;
 	if (ctldesc->ucd_desctype == UDESC_CONFIG) {
-		/* Get the short config descriptor. */
-		status = usbd_get_config_desc(uaa->device, ctldesc->ucd_idx,
-		    &cd);
-		if (status != USBD_NORMAL_COMPLETION) {
+		/* 
+		 * The NDIS driver is not allowed to change the
+		 * config! There is only one choice!
+		 */
+		cd = usb2_get_config_descriptor(sc->ndisusb_dev);
+		if (cd == NULL) {
 			ctldesc->ucd_trans_buflen = 0;
-			mtx_unlock(&Giant);
-			return usbd_usb2urb(status);
+			return (USBD_STATUS_REQUEST_FAILED);
 		}
-		/* Get the full descriptor.  Try a few times for slow devices. */
-		len = MIN(ctldesc->ucd_trans_buflen, UGETW(cd.wTotalLength));
-		for (i = 0; i < 3; i++) {
-			status = usbd_get_desc_ndis(uaa->device,
-			    ctldesc->ucd_desctype, ctldesc->ucd_idx,
-			    len, ctldesc->ucd_trans_buf, &actlen);
-			if (status == USBD_NORMAL_COMPLETION)
-				break;
-			usbd_delay_ms(uaa->device, 200);
-		}
-		if (status != USBD_NORMAL_COMPLETION) {
-			ctldesc->ucd_trans_buflen = 0;
-			mtx_unlock(&Giant);
-			return usbd_usb2urb(status);
-		}
+
+		/* Get minimum length */
+		len = UGETW(cd->wTotalLength);
+		if (len > ctldesc->ucd_trans_buflen)
+			len = ctldesc->ucd_trans_buflen;
+
+		/* Copy out config descriptor */
+		memcpy(ctldesc->ucd_trans_buf, cd, len);
+
+		/* Set actual length */
+		actlen = len;
 
-		cdp = (usb_config_descriptor_t *)ctldesc->ucd_trans_buf;
-		if (cdp->bDescriptorType != UDESC_CONFIG) {
-			device_printf(dev, "bad desc %d\n",
-			    cdp->bDescriptorType);
-			status = USBD_INVAL;
-		}
-	} else if (ctldesc->ucd_desctype == UDESC_STRING) {
-		/* Try a few times for slow devices.  */
-		for (i = 0; i < 3; i++) {
-			status = usbd_get_string_desc(uaa->device,
-			    (UDESC_STRING << 8) + ctldesc->ucd_idx,
-			    ctldesc->ucd_langid, ctldesc->ucd_trans_buf,
-			    &actlen);
-			if (actlen > ctldesc->ucd_trans_buflen)
-				panic("small string buffer for UDESC_STRING");
-			if (status == USBD_NORMAL_COMPLETION)
-				break;
-			usbd_delay_ms(uaa->device, 200);
-		}
-	} else
-		status = usbd_get_desc_ndis(uaa->device, ctldesc->ucd_desctype,
-		    ctldesc->ucd_idx, ctldesc->ucd_trans_buflen,
+		/* Success */
+		status = USB_ERR_NORMAL_COMPLETION;
+	} else {
+		status = usbd_get_desc_ndis(sc->ndisusb_dev, &sc->ndis_mtx,
+		    ctldesc->ucd_langid, ctldesc->ucd_trans_buflen,
+		    ctldesc->ucd_desctype, ctldesc->ucd_idx, 3,
 		    ctldesc->ucd_trans_buf, &actlen);
+	}
 
-	if (status != USBD_NORMAL_COMPLETION) {
+	if (status != USB_ERR_NORMAL_COMPLETION) {
 		ctldesc->ucd_trans_buflen = 0;
-		mtx_unlock(&Giant);
 		return usbd_usb2urb(status);
 	}
 
 	ctldesc->ucd_trans_buflen = actlen;
 	ip->irp_iostat.isb_info = actlen;
 
-	mtx_unlock(&Giant);
-
 	return (USBD_STATUS_SUCCESS);
 }
 
-/*
- * FIXME: at USB1, not USB2, framework, there's no a interface to get `actlen'.
- * However, we need it!!!
- */
-static usbd_status
-usbd_get_desc_ndis(usbd_device_handle dev, int type, int index, int len,
-    void *desc, int *actlen)
+static usb2_error_t
+usbd_get_desc_ndis(struct usb2_device *udev, struct mtx *mtx,
+    uint16_t id, uint16_t maxlen, uint8_t type, uint8_t index,
+    uint8_t retries, void *desc, uint16_t *actlen)
 {
-	usb_device_request_t req;
+	usb2_error_t err;
+
+	err = usb2_req_get_desc(udev, mtx,
+	    actlen, desc, 2, maxlen, id, 
+	    type, index, retries);
 
-	req.bmRequestType = UT_READ_DEVICE;
-	req.bRequest = UR_GET_DESCRIPTOR;
-	USETW2(req.wValue, type, index);
-	USETW(req.wIndex, 0);
-	USETW(req.wLength, len);
-	return usbd_do_request_flags_pipe(dev, dev->default_pipe, &req, desc,
-	    0, actlen, USBD_DEFAULT_TIMEOUT);
+	return (err);
 }
 
 static int32_t
-usbd_func_selconf(ip)
-	irp			*ip;
+usbd_func_selconf(irp *ip)
 {
 	device_t dev = IRP_NDIS_DEV(ip);
-	int i, j;
-	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	struct ndis_softc *sc;
 	struct usbd_interface_information *intf;
 	struct usbd_pipe_information *pipe;
 	struct usbd_urb_select_configuration *selconf;
+	struct usb2_config_descriptor *conf;
+	struct usb2_endpoint_descriptor *edesc;
+	struct usb2_pipe *p2;
 	union usbd_urb *urb;
-	usb_config_descriptor_t *conf;
-	usb_endpoint_descriptor_t *edesc;
-	usbd_device_handle udev = uaa->device;
-	usbd_interface_handle iface;
-	usbd_status ret;
+	unsigned int i;
+	unsigned int j;
+	int32_t err;
 
+	sc = device_get_softc(dev);
 	urb = usbd_geturb(ip);
 
 	selconf = &urb->uu_selconf;
 	conf = selconf->usc_conf;
 	if (conf == NULL) {
 		device_printf(dev, "select configuration is NULL\n");
-		return usbd_usb2urb(USBD_NORMAL_COMPLETION);
+		return usbd_usb2urb(USB_ERR_NORMAL_COMPLETION);
 	}
 
-	if (conf->bConfigurationValue > NDISUSB_CONFIG_NO)
-		device_printf(dev, "warning: config_no is larger than default");
+	/* free any previous endpoints */
+	ndis_unsetup_endpoint(sc);
 
 	intf = &selconf->usc_intf;
 	for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
-		ret = usbd_device2interface_handle(uaa->device,
-		    intf->uii_intfnum, &iface);
-		if (ret != USBD_NORMAL_COMPLETION) {
-			device_printf(dev,
-			    "getting interface handle failed: %s\n",
-			    usbd_errstr(ret));
-			return usbd_usb2urb(ret);
-		}
-		
-		ret = usbd_set_interface(iface, intf->uii_altset);
-		if (ret != USBD_NORMAL_COMPLETION && ret != USBD_IN_USE) {
+
+		mtx_unlock(&sc->ndis_mtx);
+
+		err = usb2_set_alt_interface_index(sc->ndisusb_dev,
+		    intf->uii_intfnum, intf->uii_altset);
+
+		mtx_lock(&sc->ndis_mtx);
+
+		if (err != USB_ERR_NORMAL_COMPLETION) {
 			device_printf(dev,
 			    "setting alternate interface failed: %s\n",
-			    usbd_errstr(ret));
-			return usbd_usb2urb(ret);
+			    usb2_errstr(err));
+			return usbd_usb2urb(err);
 		}
-		
-		for (j = 0; j < iface->idesc->bNumEndpoints; j++) {
+
+		/* fill in the endpoints */
+		p2 = NULL;
+		j = 0;
+		while ((p2 = usb2_pipe_foreach(sc->ndisusb_dev, p2))) {
 			if (j >= intf->uii_numeps) {
 				device_printf(dev,
 				    "endpoint %d and above are ignored",
 				    intf->uii_numeps);
 				break;
 			}
-			edesc = iface->endpoints[j].edesc;
+			edesc = p2->edesc;
+
 			pipe = &intf->uii_pipes[j];
 			pipe->upi_handle = edesc;
 			pipe->upi_epaddr = edesc->bEndpointAddress;
 			pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
 			pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
-			if (pipe->upi_type != UE_INTERRUPT)
-				continue;
+
+			/* XXX what about ISOCHRONOUS --hps */
+			if (pipe->upi_type == UE_INTERRUPT)
+				pipe->upi_interval = 1;		/* dummy value - not used ? */
+
+			err = ndis_setup_endpoint(sc, intf->uii_intfnum, edesc,
+			    (pipe->upi_type == UE_INTERRUPT) ? 1024 : 16*1024);
+
+			if (err)
+				return (err);
 
-			/* XXX we're following linux USB's interval policy.  */
-			if (udev->speed == USB_SPEED_LOW)
-				pipe->upi_interval = edesc->bInterval + 5;
-			else if (udev->speed == USB_SPEED_FULL)
-				pipe->upi_interval = edesc->bInterval;
-			else {
-				int k0 = 0, k1 = 1;
-				do {
-					k1 = k1 * 2;
-					k0 = k0 + 1;
-				} while (k1 < edesc->bInterval);
-				pipe->upi_interval = k0;
-			}
+			j++;
 		}
 
 		intf = (struct usbd_interface_information *)(((char *)intf) +
@@ -594,16 +585,15 @@
 }
 
 static int32_t
-usbd_func_vendorclass(ip)
-	irp			*ip;
+usbd_func_vendorclass(irp *ip)
 {
 	device_t dev = IRP_NDIS_DEV(ip);
-	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	struct ndis_softc *sc = device_get_softc(dev);
 	struct usbd_urb_vendor_or_class_request *vcreq;
+	union usbd_urb *urb;
+	struct usb2_device_request req;
 	uint8_t type = 0;
-	union usbd_urb *urb;
-	usb_device_request_t req;
-	usbd_status status;
+	usb2_error_t err;
 
 	urb = usbd_geturb(ip);
 	vcreq = &urb->uu_vcreq;
@@ -634,7 +624,7 @@
 		type = UT_VENDOR | UT_ENDPOINT;
 		break;
 	default:
-		/* never reach.  */
+		/* never reached */
 		break;
 	}
 
@@ -648,437 +638,333 @@
 	USETW(req.wValue, vcreq->uvc_value);
 	USETW(req.wLength, vcreq->uvc_trans_buflen);
 
-	if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
-		mtx_lock(&Giant);
-		status = usbd_do_request(uaa->device, &req,
-		    vcreq->uvc_trans_buf);
-		mtx_unlock(&Giant);
-	} else
-		status = usbd_do_request_async(uaa->device, &req,
-		    vcreq->uvc_trans_buf);
+	err = usb2_do_request(sc->ndisusb_dev, 
+	    &sc->ndis_mtx, &req, vcreq->uvc_trans_buf);
 
-	return usbd_usb2urb(status);
+	return usbd_usb2urb(err);
 }
 
-static usbd_status
-usbd_init_ndispipe(ip, ep)
-	irp			*ip;
-	usb_endpoint_descriptor_t *ep;
+static void
+usbd_irpcancel(device_object *dobj, irp *ip)
 {
-	device_t dev = IRP_NDIS_DEV(ip);
-	struct ndis_softc *sc = device_get_softc(dev);
-	struct usb_attach_arg *uaa = device_get_ivars(dev);
-	usbd_interface_handle iface;
-	usbd_status status;
+	struct ndisusb_ep *nuep;
+	union usbd_urb *urb;
+	struct usbd_urb_bulk_or_intr_transfer *ubi;
 
-	status = usbd_device2interface_handle(uaa->device, NDISUSB_IFACE_INDEX,
-	    &iface);
-	if (status != USBD_NORMAL_COMPLETION) {
-		device_printf(dev, "could not get interface handle\n");
-		return (status);
+	if (IRP_NDISUSB_EP(ip) == NULL) {
+		ip->irp_cancel = TRUE;
+		IoReleaseCancelSpinLock(ip->irp_cancelirql);
+		return;
 	}
 
-	switch (UE_GET_XFERTYPE(ep->bmAttributes)) {
-	case UE_BULK:
-		if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
-			/* RX (bulk IN)  */
-			if (sc->ndisusb_ep[NDISUSB_ENDPT_BIN] != NULL)
-				return (USBD_NORMAL_COMPLETION);
+	nuep = IRP_NDISUSB_EP(ip);
+	IRP_NDISUSB_EP(ip) = NULL;
 
-			status = usbd_open_pipe(iface, ep->bEndpointAddress,
-			    USBD_EXCLUSIVE_USE,
-			    &sc->ndisusb_ep[NDISUSB_ENDPT_BIN]);
-			break;
-		}
+	urb = usbd_geturb(ip);
+	ubi = &urb->uu_bulkintr;
 
-		/* TX (bulk OUT)  */
-		if (sc->ndisusb_ep[NDISUSB_ENDPT_BOUT] != NULL)
-			return (USBD_NORMAL_COMPLETION);
+	/* remove UBI from queue */
+	usbd_remove_ubi(nuep, ubi);
 
-		status = usbd_open_pipe(iface, ep->bEndpointAddress,
-		    USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_BOUT]);
-		break;
-	case UE_INTERRUPT:
-		if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
-			/* Interrupt IN.  */
-			if (sc->ndisusb_ep[NDISUSB_ENDPT_IIN] != NULL)
-				return (USBD_NORMAL_COMPLETION);
+	/* check if the currently executing transfer is being cancelled */
+	if (nuep->irp_curr == ip) {
+		nuep->irp_curr = NULL;
 
-			status = usbd_open_pipe(iface, ep->bEndpointAddress,
-			    USBD_EXCLUSIVE_USE,
-			    &sc->ndisusb_ep[NDISUSB_ENDPT_IIN]);
-			break;
-		}
+		/*
+		 * Make sure that the current USB transfer proxy is
+		 * cancelled and then restarted.
+		 */
+		usb2_transfer_stop(nuep->urb_xfer[0]);
+		usb2_transfer_start(nuep->urb_xfer[0]);
+	}
 
-		/* Interrupt OUT.  */
-		if (sc->ndisusb_ep[NDISUSB_ENDPT_IOUT] != NULL)
-			return (USBD_NORMAL_COMPLETION);
+	ip->irp_cancel = TRUE;
+	IoReleaseCancelSpinLock(ip->irp_cancelirql);
+}
 
-		status = usbd_open_pipe(iface, ep->bEndpointAddress,
-		    USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_IOUT]);
-		break;
-	default:
-		device_printf(dev, "can't handle xfertype 0x%x\n",
-		    UE_GET_XFERTYPE(ep->bmAttributes));
-		return (USBD_INVAL);
-	}
+static int32_t
+ndis_setup_endpoint(struct ndis_softc *sc, uint8_t iface_index,
+    struct usb2_endpoint_descriptor *edesc, uint32_t bufsize)
+{
+	struct usb2_config cfg[1];
+	struct ndisusb_ep *nuep;
+	struct usb2_xfer *xfer;
+	uint8_t ep_type = edesc->bmAttributes & UE_XFERTYPE;
+	uint8_t ep_addr = edesc->bEndpointAddress;
+	usb2_error_t err;
 
-	if (status != USBD_NORMAL_COMPLETION)
-		device_printf(dev,  "open pipe failed: (0x%x) %s\n",
-		    ep->bEndpointAddress, usbd_errstr(status));
+	/* check for non-supported transfer types */
+	if ((ep_type == UE_CONTROL) || (ep_type == UE_ISOCHRONOUS))
+		return (USBD_STATUS_SUCCESS);
 
-	return (status);
-}
+	nuep = &sc->ndisusb_ep[((ep_addr & 0x80) >> 7) | 
+	    ((ep_addr & 0x0F) << 1)];
 
-static void
-usbd_irpcancel_cb(priv)
-	void			*priv;
-{
-	struct ndisusb_cancel *nc = priv;
-	struct ndis_softc *sc = device_get_softc(nc->dev);
-	usbd_status status;
-	usbd_xfer_handle xfer = nc->xfer;
+	/* check if the endpoint is already setup */
+	if (nuep->urb_xfer[0])
+		return (USBD_STATUS_SUCCESS);
 
-	if (sc->ndisusb_status & NDISUSB_STATUS_DETACH)
-		goto exit;
+	memset(nuep, 0, sizeof(*nuep));
 
-	status = usbd_abort_pipe(xfer->pipe);
-	if (status != USBD_NORMAL_COMPLETION)
-		device_printf(nc->dev, "can't be canceld");
-exit:
-	free(nc, M_USBDEV);
-}
+	memset(cfg, 0, sizeof(cfg));
 
-static void
-usbd_irpcancel(dobj, ip)
-	device_object		*dobj;
-	irp			*ip;
-{
-	device_t dev = IRP_NDIS_DEV(ip);
-	struct ndisusb_cancel *nc;
-	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	/* Allocate and setup one generic FreeBSD USB transfer */
 
-	if (IRP_NDISUSB_XFER(ip) == NULL) {
-		ip->irp_cancel = TRUE;
-		IoReleaseCancelSpinLock(ip->irp_cancelirql);
-		return;
-	}
+	cfg[0].type = ep_type;
+	cfg[0].endpoint = ep_addr & UE_ADDR;
+	cfg[0].direction = ep_addr & (UE_DIR_OUT | UE_DIR_IN);
+	cfg[0].mh.callback = &ndis_non_isoc_callback;
+	cfg[0].mh.bufsize = bufsize;
+	cfg[0].mh.flags.proxy_buffer = 1;
+	cfg[0].mh.flags.short_xfer_ok = 1;
 
-	/*
-	 * XXX Since we're under DISPATCH_LEVEL during calling usbd_irpcancel(),
-	 * we can't sleep at all.  However, currently FreeBSD's USB stack
-	 * requires a sleep to abort a transfer.  It's inevitable! so it causes
-	 * serveral fatal problems (e.g. kernel hangups or crashes).  I think
-	 * that there are no ways to make this reliable.  In this implementation,
-	 * I used usb_add_task() but it's not a perfect method to solve this
-	 * because of as follows: NDIS drivers would expect that IRP's
-	 * completely canceld when usbd_irpcancel() is returned but we need
-	 * a sleep to do it.  During canceling XFERs, usbd_intr() would be
-	 * called with a status, USBD_CANCELLED.
-	 */
-	nc = malloc(sizeof(struct ndisusb_cancel), M_USBDEV, M_NOWAIT | M_ZERO);
-	if (nc == NULL) {
-		ip->irp_cancel = FALSE;
-		IoReleaseCancelSpinLock(ip->irp_cancelirql);
-		return;
-	}
+	mtx_unlock(&sc->ndis_mtx);
 
-	nc->dev = dev;
-	nc->xfer = IRP_NDISUSB_XFER(ip);
-	usb_init_task(&nc->task, usbd_irpcancel_cb, nc);
+	err = usb2_transfer_setup(sc->ndisusb_dev, &iface_index,
+	    nuep->urb_xfer, cfg, 1, sc, &sc->ndis_mtx);
 
-	IRP_NDISUSB_XFER(ip) = NULL;
-	usb_add_task(uaa->device, &nc->task, USB_TASKQ_DRIVER);
+	mtx_lock(&sc->ndis_mtx);
 
-	ip->irp_cancel = TRUE;
-	IoReleaseCancelSpinLock(ip->irp_cancelirql);
-}
+	if (err)
+		return (usbd_usb2urb(err));
 
-static usbd_xfer_handle
-usbd_init_ndisxfer(ip, ep, buf, buflen)
-	irp			*ip;
-	usb_endpoint_descriptor_t *ep;
-	void			*buf;
-	uint32_t		buflen;
-{
-	device_t dev = IRP_NDIS_DEV(ip);
-	struct usb_attach_arg *uaa = device_get_ivars(dev);
-	usbd_xfer_handle xfer;
-	
-	xfer = usbd_alloc_xfer(uaa->device);
-	if (xfer == NULL)
-		return (NULL);
+	xfer = nuep->urb_xfer[0];
 
-	if (buf != NULL && MmIsAddressValid(buf) == FALSE && buflen > 0) {
-		xfer->buffer = usbd_alloc_buffer(xfer, buflen);
-		if (xfer->buffer == NULL)
-			return (NULL);
+	xfer->priv_fifo = nuep;
 
-		if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
-			memcpy(xfer->buffer, buf, buflen);
-	} else
-		xfer->buffer = buf;
+	/* initialise queue head */
+	nuep->ubi_first = NULL;
+	nuep->ubi_last = &nuep->ubi_first;
 
-	xfer->length = buflen;
+	/* get RX or TX direction bit */
+	nuep->urb_rx_data = (ep_addr & 0x80) >> 7;
 
-	IoAcquireCancelSpinLock(&ip->irp_cancelirql);
-	IRP_NDISUSB_XFER(ip) = xfer;
-	ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
-	IoReleaseCancelSpinLock(ip->irp_cancelirql);
+	if (nuep->urb_rx_data != 0)
+		xfer->timeout = 0;
+	else
+		xfer->timeout = 5000; /* 5seconds, default USB timeout */
 
-	return (xfer);
+	return (USBD_STATUS_SUCCESS);
 }
 
-static void
-usbd_xferadd(xfer, priv, status)
-	usbd_xfer_handle xfer;
-	usbd_private_handle priv;
-	usbd_status status;
+void
+ndis_unsetup_endpoint(struct ndis_softc *sc)
 {
-	irp *ip = priv;
-	device_t dev = IRP_NDIS_DEV(ip);
-	struct ndis_softc *sc = device_get_softc(dev);
-	struct ndisusb_xfer *nx;
-	uint8_t irql;
+	struct ndisusb_ep *nuep;
+	uint8_t n;
 
-	nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
-	if (nx == NULL) {
-		device_printf(dev, "out of memory");
-		return;
+	for (n = 0; n != NDISUSB_ENDPT_MAX; n++) {
+		nuep = &sc->ndisusb_ep[n];
+		usb2_transfer_unsetup(nuep->urb_xfer, 1);
 	}
-	nx->nx_xfer = xfer;
-	nx->nx_priv = priv;
-	nx->nx_status = status;
-
-	KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
-	InsertTailList((&sc->ndisusb_xferlist), (&nx->nx_xferlist));
-	KeReleaseSpinLock(&sc->ndisusb_xferlock, irql);
-
-	IoQueueWorkItem(sc->ndisusb_xferitem,
-	    (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
 }
 
 static void
-usbd_xfereof(xfer, priv, status)
-	usbd_xfer_handle xfer;
-	usbd_private_handle priv;
-	usbd_status status;
+ndis_xfer_complete(struct ndisusb_ep *nuep, int32_t status)

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list