From owner-p4-projects@FreeBSD.ORG Thu Feb 19 22:21:56 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 2F7A3106567A; Thu, 19 Feb 2009 22:21:56 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D18D91065674 for ; Thu, 19 Feb 2009 22:21:55 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id BD83C8FC0C for ; Thu, 19 Feb 2009 22:21:55 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n1JMLtJ2039168 for ; Thu, 19 Feb 2009 22:21:55 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n1JMLt3V039166 for perforce@freebsd.org; Thu, 19 Feb 2009 22:21:55 GMT (envelope-from hselasky@FreeBSD.org) Date: Thu, 19 Feb 2009 22:21:55 GMT Message-Id: <200902192221.n1JMLt3V039166@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 157961 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Feb 2009 22:21:57 -0000 http://perforce.freebsd.org/chv.cgi?CH=157961 Change 157961 by hselasky@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 #include -#include -#include - #include #include #include ==== //depot/projects/usb/src/sys/compat/ndis/kern_windrv.c#4 (text+ko) ==== @@ -56,9 +56,6 @@ #include #endif -#include -#include - #include #include #include ==== //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 #include -#include -#include #include #include ==== //depot/projects/usb/src/sys/compat/ndis/subr_usbd.c#3 (text+ko) ==== @@ -56,12 +56,16 @@ #include #include -#include -#include -#include -#include -#include -#include "usbdevs.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include #include #include @@ -73,55 +77,45 @@ #include 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) <<<