1145485Swpaul/*-
2145485Swpaul * Copyright (c) 2005
3145485Swpaul *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
4145485Swpaul *
5145485Swpaul * Redistribution and use in source and binary forms, with or without
6145485Swpaul * modification, are permitted provided that the following conditions
7145485Swpaul * are met:
8145485Swpaul * 1. Redistributions of source code must retain the above copyright
9145485Swpaul *    notice, this list of conditions and the following disclaimer.
10145485Swpaul * 2. Redistributions in binary form must reproduce the above copyright
11145485Swpaul *    notice, this list of conditions and the following disclaimer in the
12145485Swpaul *    documentation and/or other materials provided with the distribution.
13145485Swpaul * 3. All advertising materials mentioning features or use of this software
14145485Swpaul *    must display the following acknowledgement:
15145485Swpaul *      This product includes software developed by Bill Paul.
16145485Swpaul * 4. Neither the name of the author nor the names of any co-contributors
17145485Swpaul *    may be used to endorse or promote products derived from this software
18145485Swpaul *    without specific prior written permission.
19145485Swpaul *
20145485Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21145485Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22145485Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23145485Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24145485Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25145485Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26145485Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27145485Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28145485Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29145485Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30145485Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
31145485Swpaul */
32145485Swpaul
33145485Swpaul#include <sys/cdefs.h>
34145485Swpaul__FBSDID("$FreeBSD$");
35145485Swpaul
36145485Swpaul#include <sys/param.h>
37145485Swpaul#include <sys/systm.h>
38145485Swpaul#include <sys/kernel.h>
39145485Swpaul#include <sys/module.h>
40145485Swpaul#include <sys/conf.h>
41145485Swpaul
42145485Swpaul#include <machine/bus.h>
43145485Swpaul#include <machine/resource.h>
44145485Swpaul#include <sys/bus.h>
45145485Swpaul
46145485Swpaul#define NDIS_REGVALS
47145485Swpaul
48145485Swpaulstruct ndis_cfg {
49145485Swpaul	char			*nc_cfgkey;
50145485Swpaul	char			*nc_cfgdesc;
51145485Swpaul	char			nc_val[256];
52145485Swpaul	int			nc_idx;
53145485Swpaul};
54145485Swpaul
55145485Swpaultypedef struct ndis_cfg ndis_cfg;
56145485Swpaul
57145485Swpaul#include "windrv.h"
58145485Swpaul
59145485Swpaulstruct ndis_pci_type {
60145485Swpaul        uint16_t                ndis_vid;
61145485Swpaul        uint16_t                ndis_did;
62145485Swpaul        uint32_t                ndis_subsys;
63145485Swpaul        char                    *ndis_name;
64145485Swpaul};
65145485Swpaul
66145485Swpaulstruct ndis_pccard_type {
67145485Swpaul        const char              *ndis_vid;
68145485Swpaul        const char              *ndis_did;
69145485Swpaul        char                    *ndis_name;
70145485Swpaul};
71145485Swpaul
72186507Sweongyostruct ndis_usb_type {
73186507Sweongyo	uint16_t		ndis_vid;
74186507Sweongyo	uint16_t		ndis_did;
75186507Sweongyo	char			*ndis_name;
76186507Sweongyo};
77145485Swpaul
78145485Swpaul#ifdef NDIS_PCI_DEV_TABLE
79146015Swpaulstatic struct ndis_pci_type ndis_devs_pci[] = {
80145485Swpaul        NDIS_PCI_DEV_TABLE
81145485Swpaul        { 0, 0, 0, NULL }
82145485Swpaul};
83145485Swpaul#endif
84145485Swpaul
85145485Swpaul#ifdef NDIS_PCMCIA_DEV_TABLE
86146015Swpaulstatic struct ndis_pccard_type ndis_devs_pccard[] = {
87145485Swpaul        NDIS_PCMCIA_DEV_TABLE
88145485Swpaul        { NULL, NULL, NULL }
89145485Swpaul};
90145485Swpaul#endif
91145485Swpaul
92186507Sweongyo#ifdef NDIS_USB_DEV_TABLE
93186507Sweongyostatic struct ndis_usb_type ndis_devs_usb[] = {
94186507Sweongyo	NDIS_USB_DEV_TABLE
95186507Sweongyo	{ 0, 0, NULL }
96186507Sweongyo};
97186507Sweongyo#endif
98186507Sweongyo
99145485Swpaulenum interface_type {
100145485Swpaul	InterfaceTypeUndefined = -1,
101145485Swpaul	Internal,
102145485Swpaul	Isa,
103145485Swpaul	Eisa,
104145485Swpaul	MicroChannel,
105145485Swpaul	TurboChannel,
106145485Swpaul	PCIBus,
107145485Swpaul	VMEBus,
108145485Swpaul	NuBus,
109145485Swpaul	PCMCIABus,
110145485Swpaul	CBus,
111145485Swpaul	MPIBus,
112145485Swpaul	MPSABus,
113145485Swpaul	ProcessorInternal,
114145485Swpaul	InternalPowerBus,
115145485Swpaul	PNPISABus,
116145485Swpaul	PNPBus,
117145485Swpaul	MaximumInterfaceType
118145485Swpaul};
119145485Swpaul
120145485Swpaultypedef enum interface_type interface_type;
121145485Swpaul
122145485Swpaul/*
123145485Swpaul * XXX
124145485Swpaul * Ordinarily, device_probe_desc is defined in device_if.h, which
125145485Swpaul * is created from device_if.m. The problem is, the latter file
126145485Swpaul * is only available if you have the kernel source code installed,
127145485Swpaul * and not all users choose to install it. I'd like to let people
128145485Swpaul * load Windows driver modules with the minimal amount of hassle
129145485Swpaul * and dependencies. <sys/bus.h> wants both device_if.h and bus_if.h
130145485Swpaul * to be defined, but it turns out the only thing we really need
131145485Swpaul * to get this module compiled is device_probe_desc, so we define
132145485Swpaul * that here, and let the build script create empty copies of
133145485Swpaul * device_if.h and bus_if.h to make the compiler happy.
134145485Swpaul */
135145485Swpaul
136145485Swpaulextern struct kobjop_desc device_probe_desc;
137145485Swpaultypedef int device_probe_t(device_t dev);
138145485Swpaul
139145485Swpaulextern int windrv_load(module_t, vm_offset_t, size_t,
140145485Swpaul	interface_type, void *, void *);
141145485Swpaulextern int windrv_unload(module_t, vm_offset_t, size_t);
142145485Swpaul
143145485Swpaul#ifndef DRV_DATA_START
144145485Swpaul#define DRV_DATA_START UNDEF_START
145145485Swpaul#endif
146145485Swpaul
147145485Swpaul#ifndef DRV_DATA_END
148145485Swpaul#define DRV_DATA_END UNDEF_END
149145485Swpaul#endif
150145485Swpaul
151145485Swpaul#ifndef DRV_NAME
152145485Swpaul#define DRV_NAME UNDEF_NAME
153145485Swpaul#endif
154145485Swpaul
155145485Swpaulextern uint8_t DRV_DATA_START;
156145485Swpaulextern uint8_t DRV_DATA_END;
157145485Swpaul
158145485Swpaul/*
159145485Swpaul * The following is stub code that makes it look as though we want
160145485Swpaul * to be a child device of all the buses that our supported devices
161145485Swpaul * might want to attach to. Our probe routine always fails. The
162145485Swpaul * reason we need this code is so that loading an ELF-ified Windows
163145485Swpaul * driver module will trigger a bus reprobe.
164145485Swpaul */
165145485Swpaul
166145485Swpaul#define MODULE_DECL(x)				\
167145485Swpaul	MODULE_DEPEND(x, ndisapi, 1, 1, 1);	\
168145485Swpaul	MODULE_DEPEND(x, ndis, 1, 1, 1)
169145485Swpaul
170145485SwpaulMODULE_DECL(DRV_NAME);
171145485Swpaul
172145485Swpaulstatic int windrv_probe(device_t);
173145485Swpaulstatic int windrv_modevent(module_t, int, void *);
174145485Swpaulstatic int windrv_loaded = 0;
175145485Swpaul
176145485Swpaulstatic device_method_t windrv_methods[] = {
177145485Swpaul	/* Device interface */
178145485Swpaul	DEVMETHOD(device_probe,         windrv_probe),
179145485Swpaul
180145485Swpaul	{ 0, 0 }
181145485Swpaul};
182145485Swpaul
183145485Swpaulstatic driver_t windrv_driver = {
184145485Swpaul	"windrv_stub",
185145485Swpaul	windrv_methods,
186145485Swpaul	0
187145485Swpaul};
188145485Swpaul
189145485Swpaulstatic devclass_t windrv_devclass;
190145485Swpaul
191145485Swpaul#define DRIVER_DECL(x)					\
192145485Swpaul	DRIVER_MODULE(x, pci, windrv_driver,		\
193145485Swpaul	    windrv_devclass, windrv_modevent, NULL);	\
194145485Swpaul	DRIVER_MODULE(x, cardbus, windrv_driver,	\
195145485Swpaul	    windrv_devclass, windrv_modevent, NULL);	\
196145485Swpaul	DRIVER_MODULE(x, pccard, windrv_driver,		\
197145485Swpaul	    windrv_devclass, windrv_modevent, NULL);	\
198145485Swpaul	DRIVER_MODULE(x, uhub, windrv_driver,		\
199145485Swpaul	    windrv_devclass, windrv_modevent, NULL);	\
200145485Swpaul	MODULE_VERSION(x, 1)
201145485Swpaul
202145485SwpaulDRIVER_DECL(DRV_NAME);
203145485Swpaul
204145485Swpaulstatic int
205145485Swpaulwindrv_probe(dev)
206145485Swpaul	device_t		dev;
207145485Swpaul{
208145485Swpaul	return (ENXIO);
209145485Swpaul}
210145485Swpaul
211145485Swpaulstatic int
212145485Swpaulwindrv_modevent(mod, cmd, arg)
213145485Swpaul	module_t		mod;
214145485Swpaul	int			cmd;
215145485Swpaul	void			*arg;
216145485Swpaul{
217145485Swpaul	int			drv_data_len;
218145485Swpaul	int			error = 0;
219145485Swpaul	vm_offset_t		drv_data_start;
220145485Swpaul	vm_offset_t		drv_data_end;
221145485Swpaul
222145485Swpaul	drv_data_start = (vm_offset_t)&DRV_DATA_START;
223145485Swpaul	drv_data_end = (vm_offset_t)&DRV_DATA_END;
224145485Swpaul
225145485Swpaul	drv_data_len = drv_data_end - drv_data_start;
226145485Swpaul	switch (cmd) {
227145485Swpaul	case MOD_LOAD:
228145485Swpaul		windrv_loaded++;
229145485Swpaul		if (windrv_loaded > 1)
230145485Swpaul			break;
231146015Swpaul#ifdef NDIS_PCI_DEV_TABLE
232146015Swpaul		windrv_load(mod, drv_data_start, drv_data_len, PCIBus,
233146015Swpaul		    ndis_devs_pci, &ndis_regvals);
234146015Swpaul#endif
235146015Swpaul#ifdef NDIS_PCMCIA_DEV_TABLE
236146015Swpaul		windrv_load(mod, drv_data_start, drv_data_len, PCMCIABus,
237146015Swpaul		    ndis_devs_pccard, &ndis_regvals);
238146015Swpaul#endif
239186507Sweongyo#ifdef NDIS_USB_DEV_TABLE
240186507Sweongyo		windrv_load(mod, drv_data_start, drv_data_len, PNPBus,
241186507Sweongyo		   ndis_devs_usb, &ndis_regvals);
242186507Sweongyo#endif
243145485Swpaul		break;
244145485Swpaul	case MOD_UNLOAD:
245145485Swpaul		windrv_loaded--;
246145485Swpaul		if (windrv_loaded > 0)
247145485Swpaul			break;
248146015Swpaul#ifdef NDIS_PCI_DEV_TABLE
249145485Swpaul		windrv_unload(mod, drv_data_start, drv_data_len);
250146015Swpaul#endif
251146015Swpaul#ifdef NDIS_PCMCIA_DEV_TABLE
252146015Swpaul		windrv_unload(mod, drv_data_start, drv_data_len);
253146015Swpaul#endif
254186507Sweongyo#ifdef NDIS_USB_DEV_TABLE
255186507Sweongyo		windrv_unload(mod, drv_data_start, drv_data_len);
256186507Sweongyo#endif
257145485Swpaul		break;
258145485Swpaul	case MOD_SHUTDOWN:
259145485Swpaul		break;
260145485Swpaul	default:
261145485Swpaul		error = EINVAL;
262145485Swpaul		break;
263145485Swpaul	}
264145485Swpaul
265145485Swpaul	return (error);
266145485Swpaul}
267