if_ndis_usb.c revision 227843
11558Srgrimes/*-
21558Srgrimes * Copyright (c) 2005
31558Srgrimes *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
13128085Sbde * 3. All advertising materials mentioning features or use of this software
141558Srgrimes *    must display the following acknowledgement:
151558Srgrimes *      This product includes software developed by Bill Paul.
161558Srgrimes * 4. Neither the name of the author nor the names of any co-contributors
171558Srgrimes *    may be used to endorse or promote products derived from this software
181558Srgrimes *    without specific prior written permission.
191558Srgrimes *
201558Srgrimes * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
241558Srgrimes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
251558Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
261558Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
271558Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
281558Srgrimes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
291558Srgrimes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
301558Srgrimes * THE POSSIBILITY OF SUCH DAMAGE.
3136997Scharnier */
3223672Speter
3336997Scharnier#include <sys/cdefs.h>
3436997Scharnier__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_usb.c 227843 2011-11-22 21:28:20Z marius $");
3550476Speter
361558Srgrimes#include <sys/param.h>
371558Srgrimes#include <sys/systm.h>
381558Srgrimes#include <sys/sockio.h>
391558Srgrimes#include <sys/module.h>
401558Srgrimes#include <sys/malloc.h>
411558Srgrimes#include <sys/kernel.h>
421558Srgrimes#include <sys/socket.h>
431558Srgrimes#include <sys/sysctl.h>
441558Srgrimes
451558Srgrimes#include <net/if.h>
4619239Sfenner#include <net/if_arp.h>
4719239Sfenner#include <net/ethernet.h>
4836115Sfenner#include <net/if_dl.h>
491558Srgrimes#include <net/if_media.h>
501558Srgrimes
511558Srgrimes#include <net/bpf.h>
521558Srgrimes
531558Srgrimes#include <sys/bus.h>
541558Srgrimes#include <machine/bus.h>
551558Srgrimes#include <dev/usb/usb.h>
56103949Smike#include <dev/usb/usbdi.h>
5759216Simp
581558Srgrimes#include <net80211/ieee80211_var.h>
591558Srgrimes
601558Srgrimes#include <compat/ndis/pe_var.h>
611558Srgrimes#include <compat/ndis/cfg_var.h>
621558Srgrimes#include <compat/ndis/resource_var.h>
631558Srgrimes#include <compat/ndis/ntoskrnl_var.h>
641558Srgrimes#include <compat/ndis/ndis_var.h>
651558Srgrimes#include <compat/ndis/usbd_var.h>
661558Srgrimes#include <dev/if_ndis/if_ndisvar.h>
671558Srgrimes
681558SrgrimesSYSCTL_NODE(_hw, OID_AUTO, ndisusb, CTLFLAG_RD, 0, "NDIS USB driver parameters");
691558Srgrimes
701558SrgrimesMODULE_DEPEND(ndis, usb, 1, 1, 1);
711558Srgrimes
7292837Simpstatic device_probe_t ndisusb_match;
7392837Simpstatic device_attach_t ndisusb_attach;
7492837Simpstatic device_detach_t ndisusb_detach;
7592837Simpstatic bus_get_resource_list_t ndis_get_resource_list;
7692837Simp
7792837Simpextern int ndisdrv_modevent     (module_t, int, void *);
7892837Simpextern int ndis_attach          (device_t);
791558Srgrimesextern int ndis_shutdown        (device_t);
8019300Sfennerextern int ndis_detach          (device_t);
811558Srgrimesextern int ndis_suspend         (device_t);
821558Srgrimesextern int ndis_resume          (device_t);
831558Srgrimes
8492837Simpextern unsigned char drv_data[];
851558Srgrimes
861558Srgrimesstatic device_method_t ndis_methods[] = {
8792837Simp        /* Device interface */
8892837Simp	DEVMETHOD(device_probe,		ndisusb_match),
8992837Simp	DEVMETHOD(device_attach,	ndisusb_attach),
901558Srgrimes	DEVMETHOD(device_detach,	ndisusb_detach),
911558Srgrimes	DEVMETHOD(device_shutdown,	ndis_shutdown),
921558Srgrimes
931558Srgrimes        /* bus interface */
941558Srgrimes	DEVMETHOD(bus_get_resource_list, ndis_get_resource_list),
951558Srgrimes
961558Srgrimes	DEVMETHOD_END
971558Srgrimes};
9892837Simp
991558Srgrimesstatic driver_t ndis_driver = {
10019300Sfenner	"ndis",
10119300Sfenner	ndis_methods,
10219300Sfenner	sizeof(struct ndis_softc)
10319300Sfenner};
1041558Srgrimes
10519300Sfennerstatic devclass_t ndis_devclass;
10619300Sfenner
10719300SfennerDRIVER_MODULE(ndis, uhub, ndis_driver, ndis_devclass, ndisdrv_modevent, 0);
10819300Sfenner
10919300Sfennerstatic int
11019300Sfennerndisusb_devcompare(interface_type bustype, struct ndis_usb_type *t, device_t dev)
11119300Sfenner{
11219300Sfenner	struct usb_attach_arg *uaa;
11319300Sfenner
11419300Sfenner	if (bustype != PNPBus)
11519300Sfenner		return (FALSE);
11619300Sfenner
11719300Sfenner	uaa = device_get_ivars(dev);
11819300Sfenner
11919300Sfenner	while (t->ndis_name != NULL) {
12019300Sfenner		if ((uaa->info.idVendor == t->ndis_vid) &&
12119300Sfenner		    (uaa->info.idProduct == t->ndis_did)) {
1221558Srgrimes			device_set_desc(dev, t->ndis_name);
1231558Srgrimes			return (TRUE);
1241558Srgrimes		}
12592837Simp		t++;
1261558Srgrimes	}
12786473Siedowse
12886473Siedowse	return (FALSE);
1291558Srgrimes}
1301558Srgrimes
1311558Srgrimesstatic int
1321558Srgrimesndisusb_match(device_t self)
13319239Sfenner{
13436115Sfenner	struct drvdb_ent *db;
1351558Srgrimes	struct usb_attach_arg *uaa = device_get_ivars(self);
1361558Srgrimes
137114452Smarkm	if (uaa->usb_mode != USB_MODE_HOST)
1381558Srgrimes		return (ENXIO);
139114452Smarkm	if (uaa->info.bConfigIndex != NDISUSB_CONFIG_NO)
14037635Sjkoshy		return (ENXIO);
1411558Srgrimes	if (uaa->info.bIfaceIndex != NDISUSB_IFACE_INDEX)
1421558Srgrimes		return (ENXIO);
1431558Srgrimes
14419300Sfenner	if (windrv_lookup(0, "USB Bus") == NULL)
14537635Sjkoshy		return (ENXIO);
1461558Srgrimes
1471558Srgrimes	db = windrv_match((matchfuncptr)ndisusb_devcompare, self);
14823672Speter	if (db == NULL)
1491558Srgrimes		return (ENXIO);
1501558Srgrimes	uaa->driver_ivar = db;
1511558Srgrimes
15237635Sjkoshy	return (0);
1531558Srgrimes}
1541558Srgrimes
1551558Srgrimesstatic int
15612377Sjoergndisusb_attach(device_t self)
15712377Sjoerg{
158122669Sjohan	const struct drvdb_ent	*db;
159114452Smarkm	struct ndisusb_softc *dummy = device_get_softc(self);
160114452Smarkm	struct usb_attach_arg *uaa = device_get_ivars(self);
16119300Sfenner	struct ndis_softc	*sc;
16219300Sfenner	struct ndis_usb_type	*t;
16319239Sfenner	driver_object		*drv;
16419300Sfenner	int			devidx = 0;
16519317Sfenner
1661558Srgrimes	device_set_usb_desc(self);
1671558Srgrimes	db = uaa->driver_ivar;
1681558Srgrimes	sc = (struct ndis_softc *)dummy;
1691558Srgrimes	sc->ndis_dev = self;
1701558Srgrimes	mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF);
1711558Srgrimes	sc->ndis_dobj = db->windrv_object;
1721558Srgrimes	sc->ndis_regvals = db->windrv_regvals;
1731558Srgrimes	sc->ndis_iftype = PNPBus;
1741558Srgrimes	sc->ndisusb_dev = uaa->device;
17519239Sfenner
17619239Sfenner	/* Create PDO for this device instance */
17719239Sfenner
17819239Sfenner	drv = windrv_lookup(0, "USB Bus");
17936115Sfenner	windrv_create_pdo(drv, self);
1801558Srgrimes
1811558Srgrimes	/* Figure out exactly which device we matched. */
1821558Srgrimes
1831558Srgrimes	t = db->windrv_devlist;
1841558Srgrimes
18592837Simp	while (t->ndis_name != NULL) {
1861558Srgrimes		if ((uaa->info.idVendor == t->ndis_vid) &&
18792837Simp		    (uaa->info.idProduct == t->ndis_did)) {
18886473Siedowse			sc->ndis_devidx = devidx;
1891558Srgrimes			break;
1901558Srgrimes		}
1911558Srgrimes		t++;
1921558Srgrimes		devidx++;
19319300Sfenner	}
1941558Srgrimes
1951558Srgrimes	if (ndis_attach(self) != 0)
1961558Srgrimes		return (ENXIO);
1971558Srgrimes
1981558Srgrimes	return (0);
1991558Srgrimes}
2001558Srgrimes
20192837Simpstatic int
2021558Srgrimesndisusb_detach(device_t self)
2031558Srgrimes{
2041558Srgrimes	int i;
20521409Simp	struct ndis_softc       *sc = device_get_softc(self);
2061558Srgrimes	struct ndisusb_ep	*ne;
2071558Srgrimes
2081558Srgrimes	sc->ndisusb_status |= NDISUSB_STATUS_DETACH;
2091558Srgrimes
2101558Srgrimes	ndis_pnpevent_nic(self, NDIS_PNP_EVENT_SURPRISE_REMOVED);
21192837Simp
2121558Srgrimes	if (sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP) {
2131558Srgrimes		usbd_transfer_unsetup(sc->ndisusb_dread_ep.ne_xfer, 1);
2141558Srgrimes		usbd_transfer_unsetup(sc->ndisusb_dwrite_ep.ne_xfer, 1);
2151558Srgrimes	}
2161558Srgrimes	for (i = 0; i < NDISUSB_ENDPT_MAX; i++) {
2171558Srgrimes		ne = &sc->ndisusb_ep[i];
2181558Srgrimes		usbd_transfer_unsetup(ne->ne_xfer, 1);
2191558Srgrimes	}
2201558Srgrimes
22192837Simp	(void)ndis_detach(self);
2221558Srgrimes
2231558Srgrimes	mtx_destroy(&sc->ndisusb_mtx);
2241558Srgrimes	return (0);
2251558Srgrimes}
22621409Simp
2271558Srgrimesstatic struct resource_list *
22839256Sgibbsndis_get_resource_list(device_t dev, device_t child)
22939256Sgibbs{
23039256Sgibbs	struct ndis_softc       *sc;
2311558Srgrimes
2321558Srgrimes	sc = device_get_softc(dev);
23339256Sgibbs	return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev));
23492837Simp}
2351558Srgrimes