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