In if_ndis.c:ndis_attach(), temporarily set the IFF_UP flag while
calling the haltfunc. If an interrupt is triggered by the init or halt func, the IFF_UP flag must be set in order for us to be able to service it. In kern_ndis.c: implement a handler for NdisMSendResourcesAvailable() (currently does nothing since we don't really need it). In subr_ndis.c: - Correct ndis_init_string() and ndis_unicode_to_ansi(), which were both horribly broken. - Implement NdisImmediateReadPciSlotInformation() and NdisImmediateWritePciSlotInformation(). - Implement NdisBufferLength(). - Work around my first confirmed NDIS driver bug. The SMC 9462 gigE driver (natsemi 83820-based copper) incorrectly creates a spinlock in its DriverEntry() routine and then destroys it in its MiniportHalt() handler. This is wrong: spinlocks should be created in MiniportInit(). In a Windows environment, this is often not a problem because DriverEntry()/MiniportInit() are called once when the system boots and MiniportHalt() or the shutdown handler is called when the system halts. With this stuff in place, this driver now seems to work: ndis0: <SMC EZ Card 1000> port 0xe000-0xe0ff mem 0xda000000-0xda000fff irq 10 at device 9.0 on pci0 ndis0: assign PCI resources... ndis_open_file("FLASH9.hex", 18446744073709551615) ndis0: Ethernet address: 00:04:e2:0e:d3:f0
This commit is contained in:
parent
7e277e1fcb
commit
3f4ea6aea4
@ -83,6 +83,7 @@ __stdcall static void ndis_statusdone_func(ndis_handle);
|
||||
__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
|
||||
__stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
|
||||
__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
|
||||
__stdcall static void ndis_sendrsrcavail_func(ndis_handle);
|
||||
|
||||
static uma_zone_t ndis_packet_zone, ndis_buffer_zone;
|
||||
|
||||
@ -122,6 +123,13 @@ DEV_MODULE(ndisapi, ndis_modevent, NULL);
|
||||
MODULE_VERSION(ndisapi, 1);
|
||||
|
||||
|
||||
__stdcall static void
|
||||
ndis_sendrsrcavail_func(adapter)
|
||||
ndis_handle adapter;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__stdcall static void
|
||||
ndis_status_func(adapter, status, sbuf, slen)
|
||||
ndis_handle adapter;
|
||||
@ -1162,6 +1170,7 @@ ndis_load_driver(img, arg)
|
||||
block->nmb_status_func = ndis_status_func;
|
||||
block->nmb_statusdone_func = ndis_statusdone_func;
|
||||
block->nmb_resetdone_func = ndis_resetdone_func;
|
||||
block->nmb_sendrsrc_func = ndis_sendrsrcavail_func;
|
||||
|
||||
block->nmb_ifp = &sc->arpcom.ac_if;
|
||||
block->nmb_dev = sc->ndis_dev;
|
||||
|
@ -186,6 +186,7 @@ __stdcall static void ndis_free_bufpool(ndis_handle);
|
||||
__stdcall static void ndis_alloc_buf(ndis_status *, ndis_buffer **,
|
||||
ndis_handle, void *, uint32_t);
|
||||
__stdcall static void ndis_release_buf(ndis_buffer *);
|
||||
__stdcall static uint32_t ndis_buflen(ndis_buffer *);
|
||||
__stdcall static void ndis_query_buf(ndis_buffer *, void **, uint32_t *);
|
||||
__stdcall static void ndis_query_buf_safe(ndis_buffer *, void **,
|
||||
uint32_t *, uint32_t);
|
||||
@ -228,7 +229,7 @@ __stdcall static uint8_t ndis_sync_with_intr(ndis_miniport_interrupt *,
|
||||
void *, void *);
|
||||
__stdcall static void ndis_time(uint64_t *);
|
||||
__stdcall static void ndis_uptime(uint32_t *);
|
||||
__stdcall static void ndis_init_string(ndis_unicode_string **, char *);
|
||||
__stdcall static void ndis_init_string(ndis_unicode_string *, char *);
|
||||
__stdcall static void ndis_init_ansi_string(ndis_ansi_string *, char *);
|
||||
__stdcall static void ndis_init_unicode_string(ndis_unicode_string *,
|
||||
uint16_t *);
|
||||
@ -318,12 +319,11 @@ ndis_unicode_to_ascii(unicode, ulen, ascii)
|
||||
int i;
|
||||
|
||||
if (*ascii == NULL)
|
||||
*ascii = malloc(ulen, M_DEVBUF, M_WAITOK);
|
||||
|
||||
*ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_WAITOK|M_ZERO);
|
||||
if (*ascii == NULL)
|
||||
return(ENOMEM);
|
||||
astr = *ascii;
|
||||
for (i = 0; i < ulen; i++) {
|
||||
for (i = 0; i < ulen / 2; i++) {
|
||||
*astr = (uint8_t)unicode[i];
|
||||
astr++;
|
||||
}
|
||||
@ -526,6 +526,11 @@ ndis_read_cfg(status, parm, cfg, key, type)
|
||||
block = (ndis_miniport_block *)cfg;
|
||||
sc = (struct ndis_softc *)block->nmb_ifp;
|
||||
|
||||
if (key->nus_len == 0 || key->nus_buf == NULL) {
|
||||
*status = NDIS_STATUS_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
ndis_unicode_to_ascii(key->nus_buf, key->nus_len, &keystr);
|
||||
|
||||
*parm = &block->nmb_replyparm;
|
||||
@ -682,6 +687,7 @@ ndis_destroy_lock(lock)
|
||||
ndis_mtx = (struct mtx *)lock->nsl_spinlock;
|
||||
mtx_destroy(ndis_mtx);
|
||||
free(ndis_mtx, M_DEVBUF);
|
||||
lock->nsl_spinlock = 0xdeadf00d; /* XXX */
|
||||
|
||||
return;
|
||||
}
|
||||
@ -692,6 +698,28 @@ ndis_lock(lock)
|
||||
{
|
||||
if (lock == NULL)
|
||||
return;
|
||||
/*
|
||||
* Workaround for certain broken NDIS drivers. I have
|
||||
* encountered one case where a driver creates a spinlock
|
||||
* within its DriverEntry() routine, which is then destroyed
|
||||
* in its MiniportHalt() routine. This is a bug, because
|
||||
* MiniportHalt() is meant to only destroy what MiniportInit()
|
||||
* creates. This leads to the following problem:
|
||||
* DriverEntry() <- spinlock created
|
||||
* MiniportInit() <- NIC initialized
|
||||
* MiniportHalt() <- NIC halted, spinlock destroyed
|
||||
* MiniportInit() <- NIC initialized, spinlock not recreated
|
||||
* NdisAcquireSpinLock(boguslock) <- panic
|
||||
* To work around this, we poison the spinlock on destroy, and
|
||||
* if we try to re-acquire the poison pill^Wspinlock, we init
|
||||
* it again so subsequent calls will work.
|
||||
*
|
||||
* Drivers that behave in this way are likely not officially
|
||||
* certified by Microsoft, since their I would expect the
|
||||
* Microsoft NDIS test tool to catch mistakes like this.
|
||||
*/
|
||||
if (lock->nsl_spinlock == 0xdeadf00d)
|
||||
ndis_create_lock(lock);
|
||||
mtx_lock((struct mtx *)lock->nsl_spinlock);
|
||||
|
||||
return;
|
||||
@ -1681,6 +1709,15 @@ ndis_release_buf(buf)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Aw c'mon. */
|
||||
|
||||
__stdcall static uint32_t
|
||||
ndis_buflen(buf)
|
||||
ndis_buffer *buf;
|
||||
{
|
||||
return(buf->nb_bytecount);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the virtual address and length of a buffer.
|
||||
* Note: the vaddr argument is optional.
|
||||
@ -1958,6 +1995,7 @@ ndis_sleep(usecs)
|
||||
tv.tv_usec = usecs;
|
||||
|
||||
tsleep(&dummy, PPAUSE|PCATCH, "ndis", tvtohz(&tv));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2122,19 +2160,14 @@ ndis_uptime(tval)
|
||||
|
||||
__stdcall static void
|
||||
ndis_init_string(dst, src)
|
||||
ndis_unicode_string **dst;
|
||||
ndis_unicode_string *dst;
|
||||
char *src;
|
||||
{
|
||||
ndis_unicode_string *u;
|
||||
|
||||
u = malloc(sizeof(ndis_unicode_string), M_DEVBUF, M_NOWAIT);
|
||||
if (u == NULL)
|
||||
u = dst;
|
||||
if (ndis_ascii_to_unicode(src, &u->nus_buf))
|
||||
return;
|
||||
u->nus_buf = NULL;
|
||||
if (ndis_ascii_to_unicode(src, &u->nus_buf)) {
|
||||
free(u, M_DEVBUF);
|
||||
return;
|
||||
}
|
||||
u->nus_len = u->nus_maxlen = strlen(src) * 2;
|
||||
return;
|
||||
}
|
||||
@ -2355,6 +2388,8 @@ image_patch_table ndis_functbl[] = {
|
||||
{ "NdisFreeMemory", (FUNC)ndis_free },
|
||||
{ "NdisReadPciSlotInformation", (FUNC)ndis_read_pci },
|
||||
{ "NdisWritePciSlotInformation",(FUNC)ndis_write_pci },
|
||||
{ "NdisImmediateReadPciSlotInformation", (FUNC)ndis_read_pci },
|
||||
{ "NdisImmediateWritePciSlotInformation", (FUNC)ndis_write_pci },
|
||||
{ "NdisWriteErrorLogEntry", (FUNC)ndis_syslog },
|
||||
{ "NdisMStartBufferPhysicalMapping", (FUNC)ndis_vtophys_load },
|
||||
{ "NdisMCompleteBufferPhysicalMapping", (FUNC)ndis_vtophys_unload },
|
||||
@ -2386,6 +2421,7 @@ image_patch_table ndis_functbl[] = {
|
||||
{ "NdisAllocateBuffer", (FUNC)ndis_alloc_buf },
|
||||
{ "NdisQueryBuffer", (FUNC)ndis_query_buf },
|
||||
{ "NdisQueryBufferSafe", (FUNC)ndis_query_buf_safe },
|
||||
{ "NdisBufferLength", (FUNC)ndis_buflen },
|
||||
{ "NdisFreeBuffer", (FUNC)ndis_release_buf },
|
||||
{ "NdisFreeBufferPool", (FUNC)ndis_free_bufpool },
|
||||
{ "NdisInterlockedIncrement", (FUNC)ndis_interlock_inc },
|
||||
|
@ -222,7 +222,7 @@ ndis_attach(dev)
|
||||
{
|
||||
u_char eaddr[ETHER_ADDR_LEN];
|
||||
struct ndis_softc *sc;
|
||||
struct ifnet *ifp;
|
||||
struct ifnet *ifp = NULL;
|
||||
int unit, error = 0, rid, len;
|
||||
void *img;
|
||||
struct ndis_type *t;
|
||||
@ -588,7 +588,9 @@ ndis_attach(dev)
|
||||
ndis_detach(dev);
|
||||
|
||||
/* We're done talking to the NIC for now; halt it. */
|
||||
ifp->if_flags |= IFF_UP;
|
||||
ndis_halt_nic(sc);
|
||||
ifp->if_flags &= ~IFF_UP;
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user