Subject: Re: NE2000 Compatible PCMCIA Ethernet Card
To: Rene Hexel <rh@idle.trapdoor.vip.at>
From: Dan Winship <danw@MIT.EDU>
List: tech-net
Date: 03/13/1999 19:41:59
> what is the recommended way of finding out the correct value here (I
> didn't find anything useful in the PCMCIA information provided by
> the card)?

I was trying to do this recently too, and the answer I got was "well,
you just sort of try all the common values until one works". That grew
old fast, so I wrote some code, which didn't work. But from looking at
the Linux code, I think my card (Netgear FA410TX) is weird about where
it puts its hw addr, so I think this code may actually be right, just
not useful for that particular card...

*** if_ne_pcmcia.c.orig	Sat Mar 13 14:37:38 1999
--- if_ne_pcmcia.c	Sat Mar 13 14:38:17 1999
***************
*** 63,68 ****
--- 63,73 ----
  int	ne_pcmcia_enable __P((struct dp8390_softc *));
  void	ne_pcmcia_disable __P((struct dp8390_softc *));
  
+ #ifdef NE_PCMCIA_DEBUG
+ int	ne_pcmcia_find_address __P((char *, struct pcmcia_function *,
+ 				    unsigned char *, int *));
+ #endif
+ 
  struct ne_pcmcia_softc {
  	struct ne2000_softc sc_ne2000;		/* real "ne2000" softc */
  
***************
*** 449,455 ****
  	for (i = 0; i < NE2000_NDEVS; i++) {
  		if ((ne_dev = ne2000_match(pa->card, pa->pf->number, i))
  		    != NULL) {
! 			if (ne_dev->enet_maddr >= 0) {
  				if (pcmcia_mem_alloc(pa->pf,
  				    ETHER_ADDR_LEN * 2, &pcmh)) {
  					printf("%s: can't alloc mem for"
--- 454,467 ----
  	for (i = 0; i < NE2000_NDEVS; i++) {
  		if ((ne_dev = ne2000_match(pa->card, pa->pf->number, i))
  		    != NULL) {
! #ifdef NE_PCMCIA_DEBUG
! 			if (ne_dev->enet_maddr == 0) {
! 				ne_pcmcia_find_address(dsc->sc_dev.dv_xname,
! 				    pa->pf, ne_dev->enet_vendor,
! 				    &ne_dev->enet_maddr);
! 			}
! #endif
! 			if (ne_dev->enet_maddr > 0) {
  				if (pcmcia_mem_alloc(pa->pf,
  				    ETHER_ADDR_LEN * 2, &pcmh)) {
  					printf("%s: can't alloc mem for"
***************
*** 522,527 ****
--- 534,586 ----
  
  	pcmcia_function_disable(pa->pf);
  }
+ 
+ #ifdef NE_PCMCIA_DEBUG
+ 
+ #define PCMCIA_MEM_ATTR_END 0xffff
+ #define BLOCK_SIZE 0x1000
+ 
+ int
+ ne_pcmcia_find_address(name, pf, vendor, addr)
+ 	char *name;
+ 	struct pcmcia_function *pf;
+ 	unsigned char *vendor;
+ 	int *addr;
+ {
+ 	struct pcmcia_mem_handle pcmh;
+ 	bus_addr_t offset;
+ 	int base, mwindow, i;
+ 
+ 	if (pcmcia_mem_alloc(pf, BLOCK_SIZE, &pcmh)) {
+ 		printf("%s: can't alloc mem to find enet addr\n", name);
+ 		return;
+ 	}
+ 
+ 	for (base = 0; base < PCMCIA_MEM_ATTR_END && !*addr;
+ 	     base += BLOCK_SIZE) {
+ 		if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, base,
+ 		    BLOCK_SIZE, &pcmh, &offset, &mwindow)) {
+ 			printf("%s: can't map mem to find enet addr\n", name);
+ 			return;
+ 		}
+ 		for (i = 0; i < BLOCK_SIZE - 6; i++) {
+ 			if (bus_space_read_1(pcmh.memt, pcmh.memh,
+ 			    offset + i * 2) == vendor[0] &&
+ 			    bus_space_read_1(pcmh.memt, pcmh.memh,
+ 			    offset + i * 2 + 2) == vendor[1] &&
+ 			    bus_space_read_1(pcmh.memt, pcmh.memh,
+ 			    offset + i * 2 + 4) == vendor[2]) {
+ 				printf("%s: found enet addr at %x\n",
+ 				    name, base + i);
+ 				*addr = base + i;
+ 				break;
+ 			}
+ 		}
+ 		pcmcia_mem_unmap(pf, mwindow);
+ 	}
+ 	pcmcia_mem_free(pf, &pcmh);
+ }
+ #endif
  
  int
  ne_pcmcia_detach(self, flags)