if_ndis_usb.c revision 189719
1184989Srafan/*-
266963Speter * Copyright (c) 2005
3176187Srafan *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
466963Speter *
566963Speter * Redistribution and use in source and binary forms, with or without
666963Speter * modification, are permitted provided that the following conditions
766963Speter * are met:
866963Speter * 1. Redistributions of source code must retain the above copyright
966963Speter *    notice, this list of conditions and the following disclaimer.
1066963Speter * 2. Redistributions in binary form must reproduce the above copyright
1166963Speter *    notice, this list of conditions and the following disclaimer in the
1266963Speter *    documentation and/or other materials provided with the distribution.
1366963Speter * 3. All advertising materials mentioning features or use of this software
1466963Speter *    must display the following acknowledgement:
1566963Speter *      This product includes software developed by Bill Paul.
1666963Speter * 4. Neither the name of the author nor the names of any co-contributors
1766963Speter *    may be used to endorse or promote products derived from this software
1866963Speter *    without specific prior written permission.
1966963Speter *
2066963Speter * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2166963Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2266963Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2366963Speter * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2466963Speter * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2566963Speter * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2666963Speter * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2766963Speter * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2866963Speter * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2966963Speter * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3066963Speter * THE POSSIBILITY OF SUCH DAMAGE.
3166963Speter */
3266963Speter
3366963Speter#include <sys/cdefs.h>
3466963Speter__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_usb.c 189719 2009-03-12 02:51:55Z weongyo $");
3566963Speter
3666963Speter#include <sys/param.h>
3766963Speter#include <sys/systm.h>
3897049Speter#include <sys/sockio.h>
3997049Speter#include <sys/module.h>
4066963Speter#include <sys/malloc.h>
4166963Speter#include <sys/kernel.h>
4266963Speter#include <sys/socket.h>
4366963Speter#include <sys/sysctl.h>
4466963Speter
4566963Speter#include <net/if.h>
46166124Srafan#include <net/if_arp.h>
47166124Srafan#include <net/ethernet.h>
4866963Speter#include <net/if_dl.h>
49176187Srafan#include <net/if_media.h>
50176187Srafan
5166963Speter#include <net/bpf.h>
5266963Speter
5366963Speter#include <sys/bus.h>
54166124Srafan#include <machine/bus.h>
5566963Speter#include <dev/usb/usb.h>
56166124Srafan#include <dev/usb/usb_core.h>
57166124Srafan
5866963Speter#include <net80211/ieee80211_var.h>
5966963Speter
6066963Speter#include <compat/ndis/pe_var.h>
61166124Srafan#include <compat/ndis/cfg_var.h>
6297049Speter#include <compat/ndis/resource_var.h>
63184989Srafan#include <compat/ndis/ntoskrnl_var.h>
64176187Srafan#include <compat/ndis/ndis_var.h>
6566963Speter#include <compat/ndis/usbd_var.h>
6666963Speter#include <dev/if_ndis/if_ndisvar.h>
67166124Srafan
68166124SrafanSYSCTL_NODE(_hw, OID_AUTO, ndisusb, CTLFLAG_RD, 0, "NDIS USB driver parameters");
6966963Speter
7066963SpeterMODULE_DEPEND(ndis, usb, 1, 1, 1);
7166963Speter
72174993Srafanstatic device_probe_t ndisusb_match;
7366963Speterstatic device_attach_t ndisusb_attach;
7466963Speterstatic device_detach_t ndisusb_detach;
75166124Srafanstatic bus_get_resource_list_t ndis_get_resource_list;
76166124Srafan
7766963Speterextern int ndisdrv_modevent     (module_t, int, void *);
7866963Speterextern int ndis_attach          (device_t);
7966963Speterextern int ndis_shutdown        (device_t);
8066963Speterextern int ndis_detach          (device_t);
8166963Speterextern int ndis_suspend         (device_t);
82166124Srafanextern int ndis_resume          (device_t);
8366963Speter
8466963Speterextern unsigned char drv_data[];
8566963Speter
8666963Speterstatic device_method_t ndis_methods[] = {
8766963Speter        /* Device interface */
88166124Srafan	DEVMETHOD(device_probe,		ndisusb_match),
89166124Srafan	DEVMETHOD(device_attach,	ndisusb_attach),
90166124Srafan	DEVMETHOD(device_detach,	ndisusb_detach),
91184989Srafan	DEVMETHOD(device_shutdown,	ndis_shutdown),
92184989Srafan
93166124Srafan        /* bus interface */
9466963Speter	DEVMETHOD(bus_print_child,	bus_generic_print_child),
9566963Speter	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
96166124Srafan	DEVMETHOD(bus_get_resource_list, ndis_get_resource_list),
97166124Srafan
9866963Speter	{ 0, 0 }
9966963Speter};
10066963Speter
10166963Speterstatic driver_t ndis_driver = {
10266963Speter	"ndis",
103166124Srafan	ndis_methods,
104166124Srafan	sizeof(struct ndis_softc)
105166124Srafan};
10666963Speter
10766963Speterstatic devclass_t ndis_devclass;
10866963Speter
10966963SpeterDRIVER_MODULE(ndis, uhub, ndis_driver, ndis_devclass, ndisdrv_modevent, 0);
11066963Speter
111166124Srafanstatic int
112166124Srafanndisusb_devcompare(interface_type bustype, struct ndis_usb_type *t, device_t dev)
11366963Speter{
11466963Speter	struct usb2_attach_arg *uaa;
11566963Speter
116166124Srafan	if (bustype != PNPBus)
11766963Speter		return (FALSE);
11866963Speter
11966963Speter	uaa = device_get_ivars(dev);
12066963Speter
121166124Srafan	while (t->ndis_name != NULL) {
122166124Srafan		if ((uaa->info.idVendor == t->ndis_vid) &&
12366963Speter		    (uaa->info.idProduct == t->ndis_did)) {
12466963Speter			device_set_desc(dev, t->ndis_name);
12566963Speter			return (TRUE);
12666963Speter		}
12766963Speter		t++;
12866963Speter	}
12966963Speter
13066963Speter	return (FALSE);
13166963Speter}
13266963Speter
13366963Speterstatic int
13466963Speterndisusb_match(device_t self)
13566963Speter{
13666963Speter	struct drvdb_ent *db;
13766963Speter	struct usb2_attach_arg *uaa = device_get_ivars(self);
138166124Srafan
13966963Speter	if (uaa->usb2_mode != USB_MODE_HOST)
14066963Speter		return (ENXIO);
141166124Srafan	if (uaa->info.bConfigIndex != NDISUSB_CONFIG_NO)
142166124Srafan		return (ENXIO);
143166124Srafan	if (uaa->info.bIfaceIndex != NDISUSB_IFACE_INDEX)
144166124Srafan		return (ENXIO);
145166124Srafan
14666963Speter	if (windrv_lookup(0, "USB Bus") == NULL)
14766963Speter		return (ENXIO);
148166124Srafan
14966963Speter	db = windrv_match((matchfuncptr)ndisusb_devcompare, self);
15097049Speter	if (db == NULL)
15166963Speter		return (ENXIO);
15266963Speter	uaa->driver_info = db;
15366963Speter
15466963Speter	return (0);
15566963Speter}
15666963Speter
15766963Speterstatic int
158184989Srafanndisusb_attach(device_t self)
159184989Srafan{
160166124Srafan	const struct drvdb_ent	*db;
161166124Srafan	struct ndisusb_softc *dummy = device_get_softc(self);
162166124Srafan	struct usb2_attach_arg *uaa = device_get_ivars(self);
163166124Srafan	struct ndis_softc	*sc;
16466963Speter	struct ndis_usb_type	*t;
16566963Speter	driver_object		*drv;
16697049Speter	int			devidx = 0;
16766963Speter
168174993Srafan	db = uaa->driver_info;
16966963Speter	sc = (struct ndis_softc *)dummy;
170166124Srafan	sc->ndis_dev = self;
17166963Speter	mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF);
17266963Speter	sc->ndis_dobj = db->windrv_object;
17397049Speter	sc->ndis_regvals = db->windrv_regvals;
17466963Speter	sc->ndis_iftype = PNPBus;
17566963Speter	sc->ndisusb_dev = uaa->device;
17666963Speter
17766963Speter	/* Create PDO for this device instance */
17866963Speter
17966963Speter	drv = windrv_lookup(0, "USB Bus");
18066963Speter	windrv_create_pdo(drv, self);
18166963Speter
18266963Speter	/* Figure out exactly which device we matched. */
18366963Speter
18497049Speter	t = db->windrv_devlist;
18597049Speter
18666963Speter	while (t->ndis_name != NULL) {
18766963Speter		if ((uaa->info.idVendor == t->ndis_vid) &&
18866963Speter		    (uaa->info.idProduct == t->ndis_did)) {
18966963Speter			sc->ndis_devidx = devidx;
19066963Speter			break;
19166963Speter		}
192166124Srafan		t++;
19366963Speter		devidx++;
194166124Srafan	}
19566963Speter
19666963Speter	if (ndis_attach(self) != 0)
19766963Speter		return ENXIO;
19866963Speter
199174993Srafan	return 0;
20066963Speter}
20166963Speter
20266963Speterstatic int
20366963Speterndisusb_detach(device_t self)
204166124Srafan{
20597049Speter	int i;
206184989Srafan	struct ndis_softc       *sc = device_get_softc(self);
20766963Speter	struct ndisusb_ep	*ne;;
20866963Speter
209	sc->ndisusb_status |= NDISUSB_STATUS_DETACH;
210
211	ndis_pnpevent_nic(self, NDIS_PNP_EVENT_SURPRISE_REMOVED);
212
213	for (i = 0; i < NDISUSB_ENDPT_MAX; i++) {
214		ne = &sc->ndisusb_ep[i];
215		usb2_transfer_unsetup(ne->ne_xfer, 1);
216	}
217
218	(void)ndis_detach(self);
219
220	mtx_destroy(&sc->ndisusb_mtx);
221	return (0);
222}
223
224static struct resource_list *
225ndis_get_resource_list(device_t dev, device_t child)
226{
227	struct ndis_softc       *sc;
228
229	sc = device_get_softc(dev);
230	return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev));
231}
232