if_ndis_usb.c revision 192505
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: head/sys/dev/if_ndis/if_ndis_usb.c 192505 2009-05-21 02:09:12Z thompsa $"); 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> 56189488Sweongyo#include <dev/usb/usb_core.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_print_child, bus_generic_print_child), 95142399Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 96142399Swpaul DEVMETHOD(bus_get_resource_list, ndis_get_resource_list), 97142399Swpaul 98142399Swpaul { 0, 0 } 99142399Swpaul}; 100142399Swpaul 101162102Smjacobstatic driver_t ndis_driver = { 102142399Swpaul "ndis", 103142399Swpaul ndis_methods, 104142399Swpaul sizeof(struct ndis_softc) 105142399Swpaul}; 106142399Swpaul 107162102Smjacobstatic devclass_t ndis_devclass; 108142399Swpaul 109142399SwpaulDRIVER_MODULE(ndis, uhub, ndis_driver, ndis_devclass, ndisdrv_modevent, 0); 110142399Swpaul 111170934Simpstatic int 112186507Sweongyondisusb_devcompare(interface_type bustype, struct ndis_usb_type *t, device_t dev) 113186507Sweongyo{ 114189488Sweongyo struct usb2_attach_arg *uaa; 115186507Sweongyo 116186507Sweongyo if (bustype != PNPBus) 117186507Sweongyo return (FALSE); 118186507Sweongyo 119186507Sweongyo uaa = device_get_ivars(dev); 120186507Sweongyo 121186507Sweongyo while (t->ndis_name != NULL) { 122189488Sweongyo if ((uaa->info.idVendor == t->ndis_vid) && 123189488Sweongyo (uaa->info.idProduct == t->ndis_did)) { 124186507Sweongyo device_set_desc(dev, t->ndis_name); 125186507Sweongyo return (TRUE); 126186507Sweongyo } 127186507Sweongyo t++; 128186507Sweongyo } 129186507Sweongyo 130186507Sweongyo return (FALSE); 131186507Sweongyo} 132186507Sweongyo 133186507Sweongyostatic int 134170934Simpndisusb_match(device_t self) 135142399Swpaul{ 136186507Sweongyo struct drvdb_ent *db; 137189488Sweongyo struct usb2_attach_arg *uaa = device_get_ivars(self); 138142399Swpaul 139192505Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 140189488Sweongyo return (ENXIO); 141189488Sweongyo if (uaa->info.bConfigIndex != NDISUSB_CONFIG_NO) 142189488Sweongyo return (ENXIO); 143189488Sweongyo if (uaa->info.bIfaceIndex != NDISUSB_IFACE_INDEX) 144189488Sweongyo return (ENXIO); 145189488Sweongyo 146142804Swpaul if (windrv_lookup(0, "USB Bus") == NULL) 147189488Sweongyo return (ENXIO); 148142399Swpaul 149186507Sweongyo db = windrv_match((matchfuncptr)ndisusb_devcompare, self); 150186507Sweongyo if (db == NULL) 151189488Sweongyo return (ENXIO); 152189488Sweongyo uaa->driver_info = db; 153186507Sweongyo 154189488Sweongyo return (0); 155142399Swpaul} 156142399Swpaul 157170934Simpstatic int 158170934Simpndisusb_attach(device_t self) 159142399Swpaul{ 160189488Sweongyo const struct drvdb_ent *db; 161170934Simp struct ndisusb_softc *dummy = device_get_softc(self); 162189488Sweongyo struct usb2_attach_arg *uaa = device_get_ivars(self); 163142399Swpaul struct ndis_softc *sc; 164186507Sweongyo struct ndis_usb_type *t; 165142408Swpaul driver_object *drv; 166186507Sweongyo int devidx = 0; 167142399Swpaul 168189488Sweongyo db = uaa->driver_info; 169142399Swpaul sc = (struct ndis_softc *)dummy; 170142399Swpaul sc->ndis_dev = self; 171189719Sweongyo mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF); 172186507Sweongyo sc->ndis_dobj = db->windrv_object; 173186507Sweongyo sc->ndis_regvals = db->windrv_regvals; 174186507Sweongyo sc->ndis_iftype = PNPBus; 175189488Sweongyo sc->ndisusb_dev = uaa->device; 176142399Swpaul 177142408Swpaul /* Create PDO for this device instance */ 178142408Swpaul 179142804Swpaul drv = windrv_lookup(0, "USB Bus"); 180142408Swpaul windrv_create_pdo(drv, self); 181142408Swpaul 182186507Sweongyo /* Figure out exactly which device we matched. */ 183186507Sweongyo 184186507Sweongyo t = db->windrv_devlist; 185186507Sweongyo 186186507Sweongyo while (t->ndis_name != NULL) { 187189488Sweongyo if ((uaa->info.idVendor == t->ndis_vid) && 188189488Sweongyo (uaa->info.idProduct == t->ndis_did)) { 189186507Sweongyo sc->ndis_devidx = devidx; 190186507Sweongyo break; 191186507Sweongyo } 192186507Sweongyo t++; 193186507Sweongyo devidx++; 194186507Sweongyo } 195186507Sweongyo 196142399Swpaul if (ndis_attach(self) != 0) 197170612Simp return ENXIO; 198142399Swpaul 199170612Simp return 0; 200142399Swpaul} 201142399Swpaul 202186507Sweongyostatic int 203186507Sweongyondisusb_detach(device_t self) 204186507Sweongyo{ 205186507Sweongyo int i; 206186507Sweongyo struct ndis_softc *sc = device_get_softc(self); 207189488Sweongyo struct ndisusb_ep *ne;; 208186507Sweongyo 209186507Sweongyo sc->ndisusb_status |= NDISUSB_STATUS_DETACH; 210186507Sweongyo 211189719Sweongyo ndis_pnpevent_nic(self, NDIS_PNP_EVENT_SURPRISE_REMOVED); 212189719Sweongyo 213189950Sweongyo if (sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP) { 214189950Sweongyo usb2_transfer_unsetup(sc->ndisusb_dread_ep.ne_xfer, 1); 215189950Sweongyo usb2_transfer_unsetup(sc->ndisusb_dwrite_ep.ne_xfer, 1); 216189950Sweongyo } 217186507Sweongyo for (i = 0; i < NDISUSB_ENDPT_MAX; i++) { 218189488Sweongyo ne = &sc->ndisusb_ep[i]; 219189488Sweongyo usb2_transfer_unsetup(ne->ne_xfer, 1); 220186507Sweongyo } 221186507Sweongyo 222189719Sweongyo (void)ndis_detach(self); 223186507Sweongyo 224189719Sweongyo mtx_destroy(&sc->ndisusb_mtx); 225189719Sweongyo return (0); 226186507Sweongyo} 227186507Sweongyo 228142399Swpaulstatic struct resource_list * 229170934Simpndis_get_resource_list(device_t dev, device_t child) 230142399Swpaul{ 231142399Swpaul struct ndis_softc *sc; 232142399Swpaul 233142399Swpaul sc = device_get_softc(dev); 234142399Swpaul return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev)); 235142399Swpaul} 236