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