]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/if_ndis/if_ndis_usb.c
MFH
[FreeBSD/FreeBSD.git] / sys / dev / if_ndis / if_ndis_usb.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2005
5  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/sockio.h>
41 #include <sys/module.h>
42 #include <sys/malloc.h>
43 #include <sys/kernel.h>
44 #include <sys/socket.h>
45 #include <sys/sysctl.h>
46
47 #include <net/if.h>
48 #include <net/if_var.h>
49 #include <net/if_arp.h>
50 #include <net/ethernet.h>
51 #include <net/if_dl.h>
52 #include <net/if_media.h>
53
54 #include <net/bpf.h>
55
56 #include <sys/bus.h>
57 #include <machine/bus.h>
58 #include <dev/usb/usb.h>
59 #include <dev/usb/usbdi.h>
60
61 #include <net80211/ieee80211_var.h>
62
63 #include <compat/ndis/pe_var.h>
64 #include <compat/ndis/cfg_var.h>
65 #include <compat/ndis/resource_var.h>
66 #include <compat/ndis/ntoskrnl_var.h>
67 #include <compat/ndis/ndis_var.h>
68 #include <compat/ndis/usbd_var.h>
69 #include <dev/if_ndis/if_ndisvar.h>
70
71 SYSCTL_NODE(_hw, OID_AUTO, ndisusb, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
72     "NDIS USB driver parameters");
73
74 MODULE_DEPEND(ndis, usb, 1, 1, 1);
75
76 static device_probe_t ndisusb_match;
77 static device_attach_t ndisusb_attach;
78 static device_detach_t ndisusb_detach;
79 static bus_get_resource_list_t ndis_get_resource_list;
80
81 extern int ndisdrv_modevent     (module_t, int, void *);
82 extern int ndis_attach          (device_t);
83 extern int ndis_shutdown        (device_t);
84 extern int ndis_detach          (device_t);
85 extern int ndis_suspend         (device_t);
86 extern int ndis_resume          (device_t);
87
88 extern unsigned char drv_data[];
89
90 static device_method_t ndis_methods[] = {
91         /* Device interface */
92         DEVMETHOD(device_probe,         ndisusb_match),
93         DEVMETHOD(device_attach,        ndisusb_attach),
94         DEVMETHOD(device_detach,        ndisusb_detach),
95         DEVMETHOD(device_shutdown,      ndis_shutdown),
96
97         /* bus interface */
98         DEVMETHOD(bus_get_resource_list, ndis_get_resource_list),
99
100         DEVMETHOD_END
101 };
102
103 static driver_t ndis_driver = {
104         "ndis",
105         ndis_methods,
106         sizeof(struct ndis_softc)
107 };
108
109 static devclass_t ndis_devclass;
110
111 DRIVER_MODULE(ndis, uhub, ndis_driver, ndis_devclass, ndisdrv_modevent, 0);
112
113 static int
114 ndisusb_devcompare(interface_type bustype, struct ndis_usb_type *t, device_t dev)
115 {
116         struct usb_attach_arg *uaa;
117
118         if (bustype != PNPBus)
119                 return (FALSE);
120
121         uaa = device_get_ivars(dev);
122
123         while (t->ndis_name != NULL) {
124                 if ((uaa->info.idVendor == t->ndis_vid) &&
125                     (uaa->info.idProduct == t->ndis_did)) {
126                         device_set_desc(dev, t->ndis_name);
127                         return (TRUE);
128                 }
129                 t++;
130         }
131
132         return (FALSE);
133 }
134
135 static int
136 ndisusb_match(device_t self)
137 {
138         struct drvdb_ent *db;
139         struct usb_attach_arg *uaa = device_get_ivars(self);
140
141         if (uaa->usb_mode != USB_MODE_HOST)
142                 return (ENXIO);
143         if (uaa->info.bConfigIndex != NDISUSB_CONFIG_NO)
144                 return (ENXIO);
145         if (uaa->info.bIfaceIndex != NDISUSB_IFACE_INDEX)
146                 return (ENXIO);
147
148         if (windrv_lookup(0, "USB Bus") == NULL)
149                 return (ENXIO);
150
151         db = windrv_match((matchfuncptr)ndisusb_devcompare, self);
152         if (db == NULL)
153                 return (ENXIO);
154         uaa->driver_ivar = db;
155
156         return (0);
157 }
158
159 static int
160 ndisusb_attach(device_t self)
161 {
162         const struct drvdb_ent  *db;
163         struct ndisusb_softc *dummy = device_get_softc(self);
164         struct usb_attach_arg *uaa = device_get_ivars(self);
165         struct ndis_softc       *sc;
166         struct ndis_usb_type    *t;
167         driver_object           *drv;
168         int                     devidx = 0;
169
170         device_set_usb_desc(self);
171         db = uaa->driver_ivar;
172         sc = (struct ndis_softc *)dummy;
173         sc->ndis_dev = self;
174         mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF);
175         sc->ndis_dobj = db->windrv_object;
176         sc->ndis_regvals = db->windrv_regvals;
177         sc->ndis_iftype = PNPBus;
178         sc->ndisusb_dev = uaa->device;
179
180         /* Create PDO for this device instance */
181
182         drv = windrv_lookup(0, "USB Bus");
183         windrv_create_pdo(drv, self);
184
185         /* Figure out exactly which device we matched. */
186
187         t = db->windrv_devlist;
188
189         while (t->ndis_name != NULL) {
190                 if ((uaa->info.idVendor == t->ndis_vid) &&
191                     (uaa->info.idProduct == t->ndis_did)) {
192                         sc->ndis_devidx = devidx;
193                         break;
194                 }
195                 t++;
196                 devidx++;
197         }
198
199         if (ndis_attach(self) != 0)
200                 return (ENXIO);
201
202         return (0);
203 }
204
205 static int
206 ndisusb_detach(device_t self)
207 {
208         int i;
209         struct ndis_softc       *sc = device_get_softc(self);
210         struct ndisusb_ep       *ne;
211
212         sc->ndisusb_status |= NDISUSB_STATUS_DETACH;
213
214         ndis_pnpevent_nic(self, NDIS_PNP_EVENT_SURPRISE_REMOVED);
215
216         if (sc->ndisusb_status & NDISUSB_STATUS_SETUP_EP) {
217                 usbd_transfer_unsetup(sc->ndisusb_dread_ep.ne_xfer, 1);
218                 usbd_transfer_unsetup(sc->ndisusb_dwrite_ep.ne_xfer, 1);
219         }
220         for (i = 0; i < NDISUSB_ENDPT_MAX; i++) {
221                 ne = &sc->ndisusb_ep[i];
222                 usbd_transfer_unsetup(ne->ne_xfer, 1);
223         }
224
225         (void)ndis_detach(self);
226
227         mtx_destroy(&sc->ndisusb_mtx);
228         return (0);
229 }
230
231 static struct resource_list *
232 ndis_get_resource_list(device_t dev, device_t child)
233 {
234         struct ndis_softc       *sc;
235
236         sc = device_get_softc(dev);
237         return (BUS_GET_RESOURCE_LIST(device_get_parent(sc->ndis_dev), dev));
238 }