summaryrefslogtreecommitdiffstats
path: root/sys/dev/if_ndis
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2005-02-08 17:23:25 +0000
committerwpaul <wpaul@FreeBSD.org>2005-02-08 17:23:25 +0000
commitdf89b626983fe6b8b3366ad0147e35b1a6a8fd37 (patch)
tree508b01687ab62847ee4114b92f273c0cdbd4da49 /sys/dev/if_ndis
parent81617011cd4fc0a322fee7174006255fc9f5e82c (diff)
downloadFreeBSD-src-df89b626983fe6b8b3366ad0147e35b1a6a8fd37.zip
FreeBSD-src-df89b626983fe6b8b3366ad0147e35b1a6a8fd37.tar.gz
Next step on the road to IRPs: create and use an imitation of the
Windows DRIVER_OBJECT and DEVICE_OBJECT mechanism so that we can simulate driver stacking. In Windows, each loaded driver image is attached to a DRIVER_OBJECT structure. Windows uses the registry to match up a given vendor/device ID combination with a corresponding DRIVER_OBJECT. When a driver image is first loaded, its DriverEntry() routine is invoked, which sets up the AddDevice() function pointer in the DRIVER_OBJECT and creates a dispatch table (based on IRP major codes). When a Windows bus driver detects a new device, it creates a Physical Device Object (PDO) for it. This is a DEVICE_OBJECT structure, with semantics analagous to that of a device_t in FreeBSD. The Windows PNP manager will invoke the driver's AddDevice() function and pass it pointers to the DRIVER_OBJECT and the PDO. The AddDevice() function then creates a new DRIVER_OBJECT structure of its own. This is known as the Functional Device Object (FDO) and corresponds roughly to a private softc instance. The driver uses IoAttachDeviceToDeviceStack() to add this device object to the driver stack for this PDO. Subsequent drivers (called filter drivers in Windows-speak) can be loaded which add themselves to the stack. When someone issues an IRP to a device, it travel along the stack passing through several possible filter drivers until it reaches the functional driver (which actually knows how to talk to the hardware) at which point it will be completed. This is how Windows achieves driver layering. Project Evil now simulates most of this. if_ndis now has a modevent handler which will use MOD_LOAD and MOD_UNLOAD events to drive the creation and destruction of DRIVER_OBJECTs. (The load event also does the relocation/dynalinking of the image.) We don't have a registry, so the DRIVER_OBJECTS are stored in a linked list for now. Eventually, the list entry will contain the vendor/device ID list extracted from the .INF file. When ndis_probe() is called and detectes a supported device, it will create a PDO for the device instance and attach it to the DRIVER_OBJECT just as in Windows. ndis_attach() will then call our NdisAddDevice() handler to create the FDO. The NDIS miniport block is now a device extension hung off the FDO, just as it is in Windows. The miniport characteristics table is now an extension hung off the DRIVER_OBJECT as well (the characteristics are the same for all devices handled by a given driver, so they don't need to be per-instance.) We also do an IoAttachDeviceToDeviceStack() to put the FDO on the stack for the PDO. There are a couple of fake bus drivers created for the PCI and pccard buses. Eventually, there will be one for USB, which will actually accept USB IRP.s Things should still work just as before, only now we do things in the proper order and maintain the correct framework to support passing IRPs between drivers. Various changes: - corrected the comments about IRQL handling in subr_hal.c to more accurately reflect reality - update ndiscvt to make the drv_data symbol in ndis_driver_data.h a global so that if_ndis_pci.o and/or if_ndis_pccard.o can see it. - Obtain the softc pointer from the miniport block by referencing the PDO rather than a private pointer of our own (nmb_ifp is no longer used) - implement IoAttachDeviceToDeviceStack(), IoDetachDevice(), IoGetAttachedDevice(), IoAllocateDriverObjectExtension(), IoGetDriverObjectExtension(), IoCreateDevice(), IoDeleteDevice(), IoAllocateIrp(), IoReuseIrp(), IoMakeAssociatedIrp(), IoFreeIrp(), IoInitializeIrp() - fix a few mistakes in the driver_object and device_object definitions - add a new module, kern_windrv.c, to handle the driver registration and relocation/dynalinkign duties (which don't really belong in kern_ndis.c). - made ndis_block and ndis_chars in the ndis_softc stucture pointers and modified all references to it - fixed NdisMRegisterMiniport() and NdisInitializeWrapper() so they work correctly with the new driver_object mechanism - changed ndis_attach() to call NdisAddDevice() instead of ndis_load_driver() (which is now deprecated) - used ExAllocatePoolWithTag()/ExFreePool() in lookaside list routines instead of kludged up alloc/free routines - added kern_windrv.c to sys/modules/ndis/Makefile and files.i386.
Diffstat (limited to 'sys/dev/if_ndis')
-rw-r--r--sys/dev/if_ndis/if_ndis.c112
-rw-r--r--sys/dev/if_ndis/if_ndis_pccard.c17
-rw-r--r--sys/dev/if_ndis/if_ndis_pci.c22
-rw-r--r--sys/dev/if_ndis/if_ndisvar.h7
4 files changed, 122 insertions, 36 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c
index c6223db..aed5e4b 100644
--- a/sys/dev/if_ndis/if_ndis.c
+++ b/sys/dev/if_ndis/if_ndis.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/queue.h>
+#include <sys/module.h>
#if __FreeBSD_version < 502113
#include <sys/sysctl.h>
#endif
@@ -90,6 +91,8 @@ int ndis_suspend (device_t);
int ndis_resume (device_t);
void ndis_shutdown (device_t);
+int ndisdrv_modevent (module_t, int, void *);
+
static __stdcall void ndis_txeof (ndis_handle,
ndis_packet *, ndis_status);
static __stdcall void ndis_rxeof (ndis_handle,
@@ -123,7 +126,45 @@ static void ndis_setmulti (struct ndis_softc *);
static void ndis_map_sclist (void *, bus_dma_segment_t *,
int, bus_size_t, int);
-extern struct mtx_pool *ndis_mtxpool;
+static int ndisdrv_loaded = 0;
+
+/*
+ * This routine should call windrv_load() once for each driver
+ * image. This will do the relocation and dynalinking for the
+ * image, and create a Windows driver object which will be
+ * saved in our driver database.
+ */
+
+int
+ndisdrv_modevent(mod, cmd, arg)
+ module_t mod;
+ int cmd;
+ void *arg;
+{
+ int error = 0;
+
+ switch (cmd) {
+ case MOD_LOAD:
+ ndisdrv_loaded++;
+ if (ndisdrv_loaded > 1)
+ break;
+ windrv_load(mod, (vm_offset_t)drv_data, 0);
+ break;
+ case MOD_UNLOAD:
+ ndisdrv_loaded--;
+ if (ndisdrv_loaded > 0)
+ break;
+ windrv_unload(mod, (vm_offset_t)drv_data, 0);
+ break;
+ case MOD_SHUTDOWN:
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
/*
* Program the 64-bit multicast hash filter.
@@ -364,6 +405,8 @@ ndis_attach(dev)
{
u_char eaddr[ETHER_ADDR_LEN];
struct ndis_softc *sc;
+ driver_object *drv;
+ device_object *pdo;
struct ifnet *ifp = NULL;
void *img;
int error = 0, len;
@@ -407,21 +450,32 @@ ndis_attach(dev)
/* Create sysctl registry nodes */
ndis_create_sysctls(sc);
- /* Set up driver image in memory. */
+ /*
+ * Create a new functional device object for this
+ * device. This is what creates the miniport block
+ * for this device instance.
+ */
+
img = drv_data;
- ndis_load_driver((vm_offset_t)img, sc);
+ drv = windrv_lookup((vm_offset_t)img);
+ pdo = windrv_find_pdo(drv, dev);
+ if (NdisAddDevice(drv, pdo) != STATUS_SUCCESS) {
+ device_printf(dev, "failed to create FDO!\n");
+ error = ENXIO;
+ goto fail;
+ }
/* Tell the user what version of the API the driver is using. */
device_printf(dev, "NDIS API version: %d.%d\n",
- sc->ndis_chars.nmc_version_major,
- sc->ndis_chars.nmc_version_minor);
+ sc->ndis_chars->nmc_version_major,
+ sc->ndis_chars->nmc_version_minor);
/* Do resource conversion. */
ndis_convert_res(sc);
/* Install our RX and TX interrupt handlers. */
- sc->ndis_block.nmb_senddone_func = ndis_txeof;
- sc->ndis_block.nmb_pktind_func = ndis_rxeof;
+ sc->ndis_block->nmb_senddone_func = ndis_txeof;
+ sc->ndis_block->nmb_pktind_func = ndis_rxeof;
/* Call driver's init routine. */
if (ndis_init_nic(sc)) {
@@ -443,8 +497,8 @@ ndis_attach(dev)
* with this driver, and if so, how many.
*/
- if (sc->ndis_chars.nmc_sendsingle_func &&
- sc->ndis_chars.nmc_sendmulti_func == NULL) {
+ if (sc->ndis_chars->nmc_sendsingle_func &&
+ sc->ndis_chars->nmc_sendmulti_func == NULL) {
sc->ndis_maxpkts = 1;
} else {
len = sizeof(sc->ndis_maxpkts);
@@ -692,8 +746,8 @@ nonettypes:
}
/* Override the status handler so we can detect link changes. */
- sc->ndis_block.nmb_status_func = ndis_linksts;
- sc->ndis_block.nmb_statusdone_func = ndis_linksts_done;
+ sc->ndis_block->nmb_status_func = ndis_linksts;
+ sc->ndis_block->nmb_statusdone_func = ndis_linksts_done;
fail:
if (error)
ndis_detach(dev);
@@ -717,6 +771,7 @@ ndis_detach(dev)
{
struct ndis_softc *sc;
struct ifnet *ifp;
+ driver_object *drv;
sc = device_get_softc(dev);
KASSERT(mtx_initialized(&sc->ndis_mtx),
@@ -767,6 +822,13 @@ ndis_detach(dev)
ndis_unload_driver(sc);
+ /* Destroy the PDO for this device. */
+
+ drv = windrv_lookup((vm_offset_t)drv_data);
+ if (drv == NULL)
+ panic("couldn't find driver object");
+ windrv_destroy_pdo(drv, dev);
+
if (sc->ndis_iftype == PCIBus)
bus_dma_tag_destroy(sc->ndis_parent_tag);
@@ -849,8 +911,8 @@ ndis_rxeof(adapter, packets, pktcnt)
int i;
block = (ndis_miniport_block *)adapter;
- sc = (struct ndis_softc *)(block->nmb_ifp->if_softc);
- ifp = block->nmb_ifp;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+ ifp = &sc->arpcom.ac_if;
for (i = 0; i < pktcnt; i++) {
p = packets[i];
@@ -927,8 +989,8 @@ ndis_txeof(adapter, packet, status)
struct mbuf *m;
block = (ndis_miniport_block *)adapter;
- sc = (struct ndis_softc *)block->nmb_ifp->if_softc;
- ifp = block->nmb_ifp;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+ ifp = &sc->arpcom.ac_if;
m = packet->np_m0;
idx = packet->np_txidx;
@@ -979,8 +1041,8 @@ ndis_linksts_done(adapter)
struct ifnet *ifp;
block = adapter;
- ifp = block->nmb_ifp;
- sc = ifp->if_softc;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+ ifp = &sc->arpcom.ac_if;
NDIS_LOCK(sc);
if (!NDIS_INITIALIZED(sc)) {
@@ -1038,11 +1100,11 @@ ndis_intr(arg)
sc = arg;
ifp = &sc->arpcom.ac_if;
- if (sc->ndis_block.nmb_miniportadapterctx == NULL)
+ if (sc->ndis_block->nmb_miniportadapterctx == NULL)
return;
mtx_lock(&sc->ndis_intrmtx);
- if (sc->ndis_block.nmb_interrupt->ni_isrreq == TRUE)
+ if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
ndis_isr(sc, &is_our_intr, &call_isr);
else {
ndis_disable_intr(sc);
@@ -1068,7 +1130,7 @@ ndis_tick(xsc)
ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
sc->ndis_stat_ch = timeout(ndis_tick, sc, hz *
- sc->ndis_block.nmb_checkforhangsecs);
+ sc->ndis_block->nmb_checkforhangsecs);
mtx_lock(&Giant);
@@ -1087,10 +1149,10 @@ ndis_ticktask(xsc)
sc = xsc;
- hangfunc = sc->ndis_chars.nmc_checkhang_func;
+ hangfunc = sc->ndis_chars->nmc_checkhang_func;
if (hangfunc != NULL) {
- rval = hangfunc(sc->ndis_block.nmb_miniportadapterctx);
+ rval = hangfunc(sc->ndis_block->nmb_miniportadapterctx);
if (rval == TRUE) {
ndis_reset_nic(sc);
return;
@@ -1391,11 +1453,11 @@ ndis_init(xsc)
* drivers, exactly 2 seconds is too fast.
*/
- if (sc->ndis_block.nmb_checkforhangsecs == 0)
- sc->ndis_block.nmb_checkforhangsecs = 3;
+ if (sc->ndis_block->nmb_checkforhangsecs == 0)
+ sc->ndis_block->nmb_checkforhangsecs = 3;
sc->ndis_stat_ch = timeout(ndis_tick, sc,
- hz * sc->ndis_block.nmb_checkforhangsecs);
+ hz * sc->ndis_block->nmb_checkforhangsecs);
return;
}
diff --git a/sys/dev/if_ndis/if_ndis_pccard.c b/sys/dev/if_ndis/if_ndis_pccard.c
index 0786b01..c3c42eb 100644
--- a/sys/dev/if_ndis/if_ndis_pccard.c
+++ b/sys/dev/if_ndis/if_ndis_pccard.c
@@ -87,13 +87,14 @@ static int ndis_probe_pccard (device_t);
static int ndis_attach_pccard (device_t);
static struct resource_list *ndis_get_resource_list
(device_t, device_t);
+extern int ndisdrv_modevent (module_t, int, void *);
extern int ndis_attach (device_t);
extern int ndis_shutdown (device_t);
extern int ndis_detach (device_t);
extern int ndis_suspend (device_t);
extern int ndis_resume (device_t);
-extern struct mtx_pool *ndis_mtxpool;
+extern unsigned char drv_data[];
static device_method_t ndis_methods[] = {
/* Device interface */
@@ -130,10 +131,11 @@ static devclass_t ndis_devclass;
#ifdef NDIS_MODNAME
#define NDIS_MODNAME_OVERRIDE_PCMCIA(x) \
- DRIVER_MODULE(x, pccard, ndis_driver, ndis_devclass, 0, 0)
+ DRIVER_MODULE(x, pccard, ndis_driver, ndis_devclass, \
+ ndisdrv_modevent, 0)
NDIS_MODNAME_OVERRIDE_PCMCIA(NDIS_MODNAME);
#else
-DRIVER_MODULE(ndis, pccard, ndis_driver, ndis_devclass, 0, 0);
+DRIVER_MODULE(ndis, pccard, ndis_driver, ndis_devclass, ndisdrv_modevent, 0);
#endif
/*
@@ -147,6 +149,13 @@ ndis_probe_pccard(dev)
struct ndis_pccard_type *t;
const char *prodstr, *vendstr;
int error;
+ driver_object *drv;
+ vm_offset_t img;
+
+ img = (vm_offset_t)drv_data;
+ drv = windrv_lookup(img);
+ if (drv == NULL)
+ return(ENXIO);
t = ndis_devs;
@@ -161,6 +170,8 @@ ndis_probe_pccard(dev)
if (ndis_strcasecmp(vendstr, t->ndis_vid) == 0 &&
ndis_strcasecmp(prodstr, t->ndis_did) == 0) {
device_set_desc(dev, t->ndis_name);
+ /* Create PDO for this device instance */
+ windrv_create_pdo(drv, dev);
return(0);
}
t++;
diff --git a/sys/dev/if_ndis/if_ndis_pci.c b/sys/dev/if_ndis/if_ndis_pci.c
index 8af48f4..f24ec70 100644
--- a/sys/dev/if_ndis/if_ndis_pci.c
+++ b/sys/dev/if_ndis/if_ndis_pci.c
@@ -86,13 +86,14 @@ static int ndis_probe_pci (device_t);
static int ndis_attach_pci (device_t);
static struct resource_list *ndis_get_resource_list
(device_t, device_t);
+extern int ndisdrv_modevent (module_t, int, void *);
extern int ndis_attach (device_t);
extern int ndis_shutdown (device_t);
extern int ndis_detach (device_t);
extern int ndis_suspend (device_t);
extern int ndis_resume (device_t);
-extern struct mtx_pool *ndis_mtxpool;
+extern unsigned char drv_data[];
static device_method_t ndis_methods[] = {
/* Device interface */
@@ -123,14 +124,15 @@ static devclass_t ndis_devclass;
#ifdef NDIS_MODNAME
#define NDIS_MODNAME_OVERRIDE_PCI(x) \
- DRIVER_MODULE(x, pci, ndis_driver, ndis_devclass, 0, 0)
+ DRIVER_MODULE(x, pci, ndis_driver, ndis_devclass, ndisdrv_modevent, 0)
#define NDIS_MODNAME_OVERRIDE_CARDBUS(x) \
- DRIVER_MODULE(x, cardbus, ndis_driver, ndis_devclass, 0, 0)
+ DRIVER_MODULE(x, cardbus, ndis_driver, ndis_devclass, \
+ ndisdrv_modevent, 0)
NDIS_MODNAME_OVERRIDE_PCI(NDIS_MODNAME);
NDIS_MODNAME_OVERRIDE_CARDBUS(NDIS_MODNAME);
#else
-DRIVER_MODULE(ndis, pci, ndis_driver, ndis_devclass, 0, 0);
-DRIVER_MODULE(ndis, cardbus, ndis_driver, ndis_devclass, 0, 0);
+DRIVER_MODULE(ndis, pci, ndis_driver, ndis_devclass, ndisdrv_modevent, 0);
+DRIVER_MODULE(ndis, cardbus, ndis_driver, ndis_devclass, ndisdrv_modevent, 0);
#endif
/*
@@ -142,8 +144,15 @@ ndis_probe_pci(dev)
device_t dev;
{
struct ndis_pci_type *t;
+ driver_object *drv;
+ vm_offset_t img;
t = ndis_devs;
+ img = (vm_offset_t)drv_data;
+ drv = windrv_lookup(img);
+
+ if (drv == NULL)
+ return(ENXIO);
while(t->ndis_name != NULL) {
if ((pci_get_vendor(dev) == t->ndis_vid) &&
@@ -151,6 +160,9 @@ ndis_probe_pci(dev)
((pci_read_config(dev, PCIR_SUBVEND_0, 4) ==
t->ndis_subsys) || t->ndis_subsys == 0)) {
device_set_desc(dev, t->ndis_name);
+
+ /* Create PDO for this device instance */
+ windrv_create_pdo(drv, dev);
return(0);
}
t++;
diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h
index 8da9b39..6736024 100644
--- a/sys/dev/if_ndis/if_ndisvar.h
+++ b/sys/dev/if_ndis/if_ndisvar.h
@@ -62,7 +62,7 @@ struct ndis_cfglist {
TAILQ_HEAD(nch, ndis_cfglist);
-#define NDIS_INITIALIZED(sc) (sc->ndis_block.nmb_miniportadapterctx != NULL)
+#define NDIS_INITIALIZED(sc) (sc->ndis_block->nmb_miniportadapterctx != NULL)
#define NDIS_INC(x) \
(x)->ndis_txidx = ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts
@@ -97,8 +97,8 @@ struct ndis_softc {
struct mtx ndis_intrmtx;
device_t ndis_dev;
int ndis_unit;
- ndis_miniport_block ndis_block;
- ndis_miniport_characteristics ndis_chars;
+ ndis_miniport_block *ndis_block;
+ ndis_miniport_characteristics *ndis_chars;
interface_type ndis_type;
struct callout_handle ndis_stat_ch;
int ndis_maxpkts;
@@ -130,6 +130,7 @@ struct ndis_softc {
bus_dmamap_t *ndis_mmaps;
bus_dmamap_t *ndis_tmaps;
int ndis_mmapcnt;
+ device_object *ndis_pdo;
};
#define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx)
OpenPOWER on IntegriCloud