if_ndis_usb.c revision 192505
1214501Srpaulo/*- 2214501Srpaulo * Copyright (c) 2005 3281806Srpaulo * Bill Paul <wpaul@windriver.com>. All rights reserved. 4214501Srpaulo * 5252726Srpaulo * Redistribution and use in source and binary forms, with or without 6252726Srpaulo * modification, are permitted provided that the following conditions 7214501Srpaulo * are met: 8214501Srpaulo * 1. Redistributions of source code must retain the above copyright 9214501Srpaulo * notice, this list of conditions and the following disclaimer. 10214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11214501Srpaulo * notice, this list of conditions and the following disclaimer in the 12281806Srpaulo * documentation and/or other materials provided with the distribution. 13281806Srpaulo * 3. All advertising materials mentioning features or use of this software 14214501Srpaulo * must display the following acknowledgement: 15214501Srpaulo * This product includes software developed by Bill Paul. 16214501Srpaulo * 4. Neither the name of the author nor the names of any co-contributors 17214501Srpaulo * may be used to endorse or promote products derived from this software 18214501Srpaulo * without specific prior written permission. 19214501Srpaulo * 20281806Srpaulo * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23214501Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24281806Srpaulo * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25281806Srpaulo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26281806Srpaulo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27252726Srpaulo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28252726Srpaulo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29252726Srpaulo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30252726Srpaulo * THE POSSIBILITY OF SUCH DAMAGE. 31252726Srpaulo */ 32252726Srpaulo 33252726Srpaulo#include <sys/cdefs.h> 34252726Srpaulo__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_usb.c 192505 2009-05-21 02:09:12Z thompsa $"); 35252726Srpaulo 36252726Srpaulo#include <sys/param.h> 37252726Srpaulo#include <sys/systm.h> 38252726Srpaulo#include <sys/sockio.h> 39214501Srpaulo#include <sys/module.h> 40214501Srpaulo#include <sys/malloc.h> 41281806Srpaulo#include <sys/kernel.h> 42214501Srpaulo#include <sys/socket.h> 43214501Srpaulo#include <sys/sysctl.h> 44214501Srpaulo 45214501Srpaulo#include <net/if.h> 46214501Srpaulo#include <net/if_arp.h> 47214501Srpaulo#include <net/ethernet.h> 48214501Srpaulo#include <net/if_dl.h> 49214501Srpaulo#include <net/if_media.h> 50214501Srpaulo 51214501Srpaulo#include <net/bpf.h> 52214501Srpaulo 53214501Srpaulo#include <sys/bus.h> 54214501Srpaulo#include <machine/bus.h> 55252726Srpaulo#include <dev/usb/usb.h> 56252726Srpaulo#include <dev/usb/usb_core.h> 57252726Srpaulo 58252726Srpaulo#include <net80211/ieee80211_var.h> 59252726Srpaulo 60252726Srpaulo#include <compat/ndis/pe_var.h> 61252726Srpaulo#include <compat/ndis/cfg_var.h> 62214501Srpaulo#include <compat/ndis/resource_var.h> 63214501Srpaulo#include <compat/ndis/ntoskrnl_var.h> 64214501Srpaulo#include <compat/ndis/ndis_var.h> 65214501Srpaulo#include <compat/ndis/usbd_var.h> 66214501Srpaulo#include <dev/if_ndis/if_ndisvar.h> 67214501Srpaulo 68214501SrpauloSYSCTL_NODE(_hw, OID_AUTO, ndisusb, CTLFLAG_RD, 0, "NDIS USB driver parameters"); 69214501Srpaulo 70214501SrpauloMODULE_DEPEND(ndis, usb, 1, 1, 1); 71214501Srpaulo 72214501Srpaulostatic device_probe_t ndisusb_match; 73214501Srpaulostatic device_attach_t ndisusb_attach; 74214501Srpaulostatic device_detach_t ndisusb_detach; 75281806Srpaulostatic bus_get_resource_list_t ndis_get_resource_list; 76214501Srpaulo 77214501Srpauloextern int ndisdrv_modevent (module_t, int, void *); 78214501Srpauloextern int ndis_attach (device_t); 79214501Srpauloextern int ndis_shutdown (device_t); 80214501Srpauloextern int ndis_detach (device_t); 81214501Srpauloextern int ndis_suspend (device_t); 82214501Srpauloextern int ndis_resume (device_t); 83214501Srpaulo 84214501Srpauloextern unsigned char drv_data[]; 85214501Srpaulo 86214501Srpaulostatic device_method_t ndis_methods[] = { 87214501Srpaulo /* Device interface */ 88214501Srpaulo DEVMETHOD(device_probe, ndisusb_match), 89214501Srpaulo DEVMETHOD(device_attach, ndisusb_attach), 90214501Srpaulo DEVMETHOD(device_detach, ndisusb_detach), 91214501Srpaulo DEVMETHOD(device_shutdown, ndis_shutdown), 92214501Srpaulo 93214501Srpaulo /* bus interface */ 94214501Srpaulo DEVMETHOD(bus_print_child, bus_generic_print_child), 95214501Srpaulo DEVMETHOD(bus_driver_added, bus_generic_driver_added), 96214501Srpaulo DEVMETHOD(bus_get_resource_list, ndis_get_resource_list), 97214501Srpaulo 98214501Srpaulo { 0, 0 } 99214501Srpaulo}; 100214501Srpaulo 101214501Srpaulostatic driver_t ndis_driver = { 102214501Srpaulo "ndis", 103214501Srpaulo ndis_methods, 104214501Srpaulo sizeof(struct ndis_softc) 105214501Srpaulo}; 106214501Srpaulo 107214501Srpaulostatic devclass_t ndis_devclass; 108214501Srpaulo 109214501SrpauloDRIVER_MODULE(ndis, uhub, ndis_driver, ndis_devclass, ndisdrv_modevent, 0); 110214501Srpaulo 111214501Srpaulostatic int 112214501Srpaulondisusb_devcompare(interface_type bustype, struct ndis_usb_type *t, device_t dev) 113214501Srpaulo{ 114214501Srpaulo struct usb2_attach_arg *uaa; 115214501Srpaulo 116214501Srpaulo if (bustype != PNPBus) 117214501Srpaulo return (FALSE); 118214501Srpaulo 119214501Srpaulo uaa = device_get_ivars(dev); 120214501Srpaulo 121214501Srpaulo while (t->ndis_name != NULL) { 122214501Srpaulo if ((uaa->info.idVendor == t->ndis_vid) && 123281806Srpaulo (uaa->info.idProduct == t->ndis_did)) { 124281806Srpaulo device_set_desc(dev, t->ndis_name); 125281806Srpaulo return (TRUE); 126281806Srpaulo } 127281806Srpaulo t++; 128281806Srpaulo } 129281806Srpaulo 130281806Srpaulo return (FALSE); 131281806Srpaulo} 132281806Srpaulo 133281806Srpaulostatic int 134281806Srpaulondisusb_match(device_t self) 135281806Srpaulo{ 136281806Srpaulo struct drvdb_ent *db; 137281806Srpaulo struct usb2_attach_arg *uaa = device_get_ivars(self); 138281806Srpaulo 139214501Srpaulo if (uaa->usb_mode != USB_MODE_HOST) 140214501Srpaulo return (ENXIO); 141214501Srpaulo if (uaa->info.bConfigIndex != NDISUSB_CONFIG_NO) 142214501Srpaulo return (ENXIO); 143214501Srpaulo if (uaa->info.bIfaceIndex != NDISUSB_IFACE_INDEX) 144214501Srpaulo return (ENXIO); 145214501Srpaulo 146214501Srpaulo if (windrv_lookup(0, "USB Bus") == NULL) 147214501Srpaulo return (ENXIO); 148214501Srpaulo 149214501Srpaulo db = windrv_match((matchfuncptr)ndisusb_devcompare, self); 150214501Srpaulo if (db == NULL) 151214501Srpaulo return (ENXIO); 152214501Srpaulo uaa->driver_info = db; 153281806Srpaulo 154281806Srpaulo return (0); 155214501Srpaulo} 156214501Srpaulo 157214501Srpaulostatic int 158214501Srpaulondisusb_attach(device_t self) 159214501Srpaulo{ 160214501Srpaulo const struct drvdb_ent *db; 161214501Srpaulo struct ndisusb_softc *dummy = device_get_softc(self); 162214501Srpaulo struct usb2_attach_arg *uaa = device_get_ivars(self); 163214501Srpaulo struct ndis_softc *sc; 164214501Srpaulo struct ndis_usb_type *t; 165214501Srpaulo driver_object *drv; 166252726Srpaulo int devidx = 0; 167252726Srpaulo 168214501Srpaulo db = uaa->driver_info; 169214501Srpaulo sc = (struct ndis_softc *)dummy; 170214501Srpaulo sc->ndis_dev = self; 171214501Srpaulo mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF); 172214501Srpaulo sc->ndis_dobj = db->windrv_object; 173214501Srpaulo sc->ndis_regvals = db->windrv_regvals; 174214501Srpaulo sc->ndis_iftype = PNPBus; 175214501Srpaulo sc->ndisusb_dev = uaa->device; 176214501Srpaulo 177214501Srpaulo /* Create PDO for this device instance */ 178214501Srpaulo 179214501Srpaulo drv = windrv_lookup(0, "USB Bus"); 180214501Srpaulo windrv_create_pdo(drv, self); 181214501Srpaulo 182214501Srpaulo /* Figure out exactly which device we matched. */ 183214501Srpaulo 184214501Srpaulo t = db->windrv_devlist; 185214501Srpaulo 186214501Srpaulo while (t->ndis_name != NULL) { 187214501Srpaulo if ((uaa->info.idVendor == t->ndis_vid) && 188214501Srpaulo (uaa->info.idProduct == t->ndis_did)) { 189214501Srpaulo sc->ndis_devidx = devidx; 190214501Srpaulo break; 191214501Srpaulo } 192214501Srpaulo t++; 193214501Srpaulo devidx++; 194214501Srpaulo } 195214501Srpaulo 196252726Srpaulo if (ndis_attach(self) != 0) 197214501Srpaulo return ENXIO; 198252726Srpaulo 199252726Srpaulo return 0; 200252726Srpaulo} 201252726Srpaulo 202252726Srpaulostatic int 203252726Srpaulondisusb_detach(device_t self) 204252726Srpaulo{ 205214501Srpaulo int i; 206214501Srpaulo struct ndis_softc *sc = device_get_softc(self); 207214501Srpaulo struct ndisusb_ep *ne;; 208214501Srpaulo 209214501Srpaulo sc->ndisusb_status |= NDISUSB_STATUS_DETACH; 210214501Srpaulo 211214501Srpaulo ndis_pnpevent_nic(self, NDIS_PNP_EVENT_SURPRISE_REMOVED); 212252726Srpaulo 213214501Srpaulo if (sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP) { 214214501Srpaulo usb2_transfer_unsetup(sc->ndisusb_dread_ep.ne_xfer, 1); 215214501Srpaulo usb2_transfer_unsetup(sc->ndisusb_dwrite_ep.ne_xfer, 1); 216214501Srpaulo } 217214501Srpaulo for (i = 0; i < NDISUSB_ENDPT_MAX; i++) { 218214501Srpaulo ne = &sc->ndisusb_ep[i]; 219214501Srpaulo usb2_transfer_unsetup(ne->ne_xfer, 1); 220252726Srpaulo } 221214501Srpaulo 222214501Srpaulo (void)ndis_detach(self); 223214501Srpaulo 224214501Srpaulo mtx_destroy(&sc->ndisusb_mtx); 225214501Srpaulo return (0); 226214501Srpaulo} 227214501Srpaulo 228214501Srpaulostatic struct resource_list * 229214501Srpaulondis_get_resource_list(device_t dev, device_t child) 230214501Srpaulo{ 231214501Srpaulo struct ndis_softc *sc; 232214501Srpaulo 233281806Srpaulo sc = device_get_softc(dev); 234214501Srpaulo return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev)); 235214501Srpaulo} 236214501Srpaulo