1142399Swpaul/*- 2142399Swpaul * Copyright (c) 2005 3142415Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4142399Swpaul * 5142399Swpaul * Redistribution and use in source and binary forms, with or without 6142399Swpaul * modification, are permitted provided that the following conditions 7142399Swpaul * are met: 8142399Swpaul * 1. Redistributions of source code must retain the above copyright 9142399Swpaul * notice, this list of conditions and the following disclaimer. 10142399Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11142399Swpaul * notice, this list of conditions and the following disclaimer in the 12142399Swpaul * documentation and/or other materials provided with the distribution. 13142399Swpaul * 3. All advertising materials mentioning features or use of this software 14142399Swpaul * must display the following acknowledgement: 15142399Swpaul * This product includes software developed by Bill Paul. 16142399Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17142399Swpaul * may be used to endorse or promote products derived from this software 18142399Swpaul * without specific prior written permission. 19142399Swpaul * 20142399Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21142399Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22142399Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23142399Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24142399Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25142399Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26142399Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27142399Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28142399Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29142399Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30142399Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31142399Swpaul */ 32142399Swpaul 33142399Swpaul#include <sys/cdefs.h> 34142399Swpaul__FBSDID("$FreeBSD: releng/10.3/sys/dev/if_ndis/if_ndis_usb.c 227843 2011-11-22 21:28:20Z marius $"); 35142399Swpaul 36142399Swpaul#include <sys/param.h> 37142399Swpaul#include <sys/systm.h> 38142399Swpaul#include <sys/sockio.h> 39145485Swpaul#include <sys/module.h> 40142399Swpaul#include <sys/malloc.h> 41142399Swpaul#include <sys/kernel.h> 42142399Swpaul#include <sys/socket.h> 43142399Swpaul#include <sys/sysctl.h> 44142399Swpaul 45142399Swpaul#include <net/if.h> 46142399Swpaul#include <net/if_arp.h> 47142399Swpaul#include <net/ethernet.h> 48142399Swpaul#include <net/if_dl.h> 49142399Swpaul#include <net/if_media.h> 50142399Swpaul 51142399Swpaul#include <net/bpf.h> 52142399Swpaul 53142399Swpaul#include <sys/bus.h> 54142399Swpaul#include <machine/bus.h> 55189488Sweongyo#include <dev/usb/usb.h> 56194677Sthompsa#include <dev/usb/usbdi.h> 57142399Swpaul 58142399Swpaul#include <net80211/ieee80211_var.h> 59142399Swpaul 60142399Swpaul#include <compat/ndis/pe_var.h> 61145485Swpaul#include <compat/ndis/cfg_var.h> 62142399Swpaul#include <compat/ndis/resource_var.h> 63142399Swpaul#include <compat/ndis/ntoskrnl_var.h> 64142399Swpaul#include <compat/ndis/ndis_var.h> 65186507Sweongyo#include <compat/ndis/usbd_var.h> 66142399Swpaul#include <dev/if_ndis/if_ndisvar.h> 67142399Swpaul 68186507SweongyoSYSCTL_NODE(_hw, OID_AUTO, ndisusb, CTLFLAG_RD, 0, "NDIS USB driver parameters"); 69186507Sweongyo 70142399SwpaulMODULE_DEPEND(ndis, usb, 1, 1, 1); 71142399Swpaul 72170934Simpstatic device_probe_t ndisusb_match; 73170934Simpstatic device_attach_t ndisusb_attach; 74186507Sweongyostatic device_detach_t ndisusb_detach; 75170934Simpstatic bus_get_resource_list_t ndis_get_resource_list; 76142399Swpaul 77142399Swpaulextern int ndisdrv_modevent (module_t, int, void *); 78142399Swpaulextern int ndis_attach (device_t); 79142399Swpaulextern int ndis_shutdown (device_t); 80142399Swpaulextern int ndis_detach (device_t); 81142399Swpaulextern int ndis_suspend (device_t); 82142399Swpaulextern int ndis_resume (device_t); 83142399Swpaul 84142399Swpaulextern unsigned char drv_data[]; 85142399Swpaul 86162102Smjacobstatic device_method_t ndis_methods[] = { 87142399Swpaul /* Device interface */ 88142399Swpaul DEVMETHOD(device_probe, ndisusb_match), 89142399Swpaul DEVMETHOD(device_attach, ndisusb_attach), 90186507Sweongyo DEVMETHOD(device_detach, ndisusb_detach), 91142399Swpaul DEVMETHOD(device_shutdown, ndis_shutdown), 92142399Swpaul 93142399Swpaul /* bus interface */ 94142399Swpaul DEVMETHOD(bus_get_resource_list, ndis_get_resource_list), 95142399Swpaul 96227843Smarius DEVMETHOD_END 97142399Swpaul}; 98142399Swpaul 99162102Smjacobstatic driver_t ndis_driver = { 100142399Swpaul "ndis", 101142399Swpaul ndis_methods, 102142399Swpaul sizeof(struct ndis_softc) 103142399Swpaul}; 104142399Swpaul 105162102Smjacobstatic devclass_t ndis_devclass; 106142399Swpaul 107142399SwpaulDRIVER_MODULE(ndis, uhub, ndis_driver, ndis_devclass, ndisdrv_modevent, 0); 108142399Swpaul 109170934Simpstatic int 110186507Sweongyondisusb_devcompare(interface_type bustype, struct ndis_usb_type *t, device_t dev) 111186507Sweongyo{ 112192984Sthompsa struct usb_attach_arg *uaa; 113186507Sweongyo 114186507Sweongyo if (bustype != PNPBus) 115186507Sweongyo return (FALSE); 116186507Sweongyo 117186507Sweongyo uaa = device_get_ivars(dev); 118186507Sweongyo 119186507Sweongyo while (t->ndis_name != NULL) { 120189488Sweongyo if ((uaa->info.idVendor == t->ndis_vid) && 121189488Sweongyo (uaa->info.idProduct == t->ndis_did)) { 122186507Sweongyo device_set_desc(dev, t->ndis_name); 123186507Sweongyo return (TRUE); 124186507Sweongyo } 125186507Sweongyo t++; 126186507Sweongyo } 127186507Sweongyo 128186507Sweongyo return (FALSE); 129186507Sweongyo} 130186507Sweongyo 131186507Sweongyostatic int 132170934Simpndisusb_match(device_t self) 133142399Swpaul{ 134186507Sweongyo struct drvdb_ent *db; 135192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 136142399Swpaul 137192505Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 138189488Sweongyo return (ENXIO); 139189488Sweongyo if (uaa->info.bConfigIndex != NDISUSB_CONFIG_NO) 140189488Sweongyo return (ENXIO); 141189488Sweongyo if (uaa->info.bIfaceIndex != NDISUSB_IFACE_INDEX) 142189488Sweongyo return (ENXIO); 143189488Sweongyo 144142804Swpaul if (windrv_lookup(0, "USB Bus") == NULL) 145189488Sweongyo return (ENXIO); 146142399Swpaul 147186507Sweongyo db = windrv_match((matchfuncptr)ndisusb_devcompare, self); 148186507Sweongyo if (db == NULL) 149189488Sweongyo return (ENXIO); 150193742Sthompsa uaa->driver_ivar = db; 151186507Sweongyo 152189488Sweongyo return (0); 153142399Swpaul} 154142399Swpaul 155170934Simpstatic int 156170934Simpndisusb_attach(device_t self) 157142399Swpaul{ 158189488Sweongyo const struct drvdb_ent *db; 159170934Simp struct ndisusb_softc *dummy = device_get_softc(self); 160192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(self); 161142399Swpaul struct ndis_softc *sc; 162186507Sweongyo struct ndis_usb_type *t; 163142408Swpaul driver_object *drv; 164186507Sweongyo int devidx = 0; 165142399Swpaul 166200824Sthompsa device_set_usb_desc(self); 167193742Sthompsa db = uaa->driver_ivar; 168142399Swpaul sc = (struct ndis_softc *)dummy; 169142399Swpaul sc->ndis_dev = self; 170189719Sweongyo mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF); 171186507Sweongyo sc->ndis_dobj = db->windrv_object; 172186507Sweongyo sc->ndis_regvals = db->windrv_regvals; 173186507Sweongyo sc->ndis_iftype = PNPBus; 174189488Sweongyo sc->ndisusb_dev = uaa->device; 175142399Swpaul 176142408Swpaul /* Create PDO for this device instance */ 177142408Swpaul 178142804Swpaul drv = windrv_lookup(0, "USB Bus"); 179142408Swpaul windrv_create_pdo(drv, self); 180142408Swpaul 181186507Sweongyo /* Figure out exactly which device we matched. */ 182186507Sweongyo 183186507Sweongyo t = db->windrv_devlist; 184186507Sweongyo 185186507Sweongyo while (t->ndis_name != NULL) { 186189488Sweongyo if ((uaa->info.idVendor == t->ndis_vid) && 187189488Sweongyo (uaa->info.idProduct == t->ndis_did)) { 188186507Sweongyo sc->ndis_devidx = devidx; 189186507Sweongyo break; 190186507Sweongyo } 191186507Sweongyo t++; 192186507Sweongyo devidx++; 193186507Sweongyo } 194186507Sweongyo 195142399Swpaul if (ndis_attach(self) != 0) 196198786Srpaulo return (ENXIO); 197142399Swpaul 198198786Srpaulo return (0); 199142399Swpaul} 200142399Swpaul 201186507Sweongyostatic int 202186507Sweongyondisusb_detach(device_t self) 203186507Sweongyo{ 204186507Sweongyo int i; 205186507Sweongyo struct ndis_softc *sc = device_get_softc(self); 206201758Smbr struct ndisusb_ep *ne; 207186507Sweongyo 208186507Sweongyo sc->ndisusb_status |= NDISUSB_STATUS_DETACH; 209186507Sweongyo 210189719Sweongyo ndis_pnpevent_nic(self, NDIS_PNP_EVENT_SURPRISE_REMOVED); 211189719Sweongyo 212189950Sweongyo if (sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP) { 213194228Sthompsa usbd_transfer_unsetup(sc->ndisusb_dread_ep.ne_xfer, 1); 214194228Sthompsa usbd_transfer_unsetup(sc->ndisusb_dwrite_ep.ne_xfer, 1); 215189950Sweongyo } 216186507Sweongyo for (i = 0; i < NDISUSB_ENDPT_MAX; i++) { 217189488Sweongyo ne = &sc->ndisusb_ep[i]; 218194228Sthompsa usbd_transfer_unsetup(ne->ne_xfer, 1); 219186507Sweongyo } 220186507Sweongyo 221189719Sweongyo (void)ndis_detach(self); 222186507Sweongyo 223189719Sweongyo mtx_destroy(&sc->ndisusb_mtx); 224189719Sweongyo return (0); 225186507Sweongyo} 226186507Sweongyo 227142399Swpaulstatic struct resource_list * 228170934Simpndis_get_resource_list(device_t dev, device_t child) 229142399Swpaul{ 230142399Swpaul struct ndis_softc *sc; 231142399Swpaul 232142399Swpaul sc = device_get_softc(dev); 233142399Swpaul return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev)); 234142399Swpaul} 235