1433d6423SLionel Sambuc /* 2433d6423SLionel Sambuc ** File: 3c501.c Jan. 14, 1997 3433d6423SLionel Sambuc ** 4433d6423SLionel Sambuc ** Author: Giovanni Falzoni <gfalzoni@inwind.it> 5433d6423SLionel Sambuc ** 6433d6423SLionel Sambuc ** This file contains specific implementation of the ethernet 7433d6423SLionel Sambuc ** device driver for 3Com Etherlink (3c501) boards. This is a 8433d6423SLionel Sambuc ** very old board and its performances are very poor for today 9433d6423SLionel Sambuc ** network environments. 10433d6423SLionel Sambuc */ 11433d6423SLionel Sambuc 12433d6423SLionel Sambuc #include <minix/drivers.h> 13*91c4db25SDavid van Moolenbroek #include <minix/netdriver.h> 14433d6423SLionel Sambuc #include <net/gen/ether.h> 15433d6423SLionel Sambuc #include <net/gen/eth_io.h> 16433d6423SLionel Sambuc #include "dp.h" 17433d6423SLionel Sambuc 18433d6423SLionel Sambuc #if (ENABLE_3C501 == 1) 19433d6423SLionel Sambuc 20433d6423SLionel Sambuc #include "3c501.h" 21433d6423SLionel Sambuc 22433d6423SLionel Sambuc static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,}; 23433d6423SLionel Sambuc static buff_t *TxBuff = NULL; 24433d6423SLionel Sambuc 25433d6423SLionel Sambuc /* 26*91c4db25SDavid van Moolenbroek ** Name: el1_getstats 27433d6423SLionel Sambuc ** Function: Reads statistics counters from board. 28433d6423SLionel Sambuc **/ 29433d6423SLionel Sambuc static void el1_getstats(dpeth_t * dep) 30433d6423SLionel Sambuc { 31433d6423SLionel Sambuc 32*91c4db25SDavid van Moolenbroek /* Nothing to do */ 33433d6423SLionel Sambuc } 34433d6423SLionel Sambuc 35433d6423SLionel Sambuc /* 36*91c4db25SDavid van Moolenbroek ** Name: el1_reset 37433d6423SLionel Sambuc ** Function: Reset function specific for Etherlink hardware. 38433d6423SLionel Sambuc */ 39433d6423SLionel Sambuc static void el1_reset(dpeth_t * dep) 40433d6423SLionel Sambuc { 41433d6423SLionel Sambuc int ix; 42433d6423SLionel Sambuc 43433d6423SLionel Sambuc for (ix = 0; ix < 8; ix += 1) /* Resets the board */ 44433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RESET); 45433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 46433d6423SLionel Sambuc 47433d6423SLionel Sambuc /* Set Ethernet Address on controller */ 48433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_LOOP); /* Loopback mode */ 49433d6423SLionel Sambuc for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1) 50433d6423SLionel Sambuc outb_el1(dep, ix, StationAddress[ix]); 51433d6423SLionel Sambuc 52433d6423SLionel Sambuc /* Enable DMA/Interrupt, gain control of Buffer */ 53433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 54433d6423SLionel Sambuc /* Clear RX packet area */ 55433d6423SLionel Sambuc outw_el1(dep, EL1_RECVPTR, 0); 56433d6423SLionel Sambuc /* Enable transmit/receive configuration and flush pending interrupts */ 57433d6423SLionel Sambuc outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER); 58433d6423SLionel Sambuc outb_el1(dep, EL1_RECV, dep->de_recv_mode); 59433d6423SLionel Sambuc inb_el1(dep, EL1_RECV); 60433d6423SLionel Sambuc inb_el1(dep, EL1_XMIT); 61433d6423SLionel Sambuc dep->de_flags &= NOT(DEF_XMIT_BUSY); 62433d6423SLionel Sambuc } 63433d6423SLionel Sambuc 64433d6423SLionel Sambuc /* 65*91c4db25SDavid van Moolenbroek ** Name: el1_dumpstats 66433d6423SLionel Sambuc ** Function: Dumps counter on screen (support for console display). 67433d6423SLionel Sambuc */ 68433d6423SLionel Sambuc static void el1_dumpstats(dpeth_t * UNUSED(dep)) 69433d6423SLionel Sambuc { 70433d6423SLionel Sambuc 71433d6423SLionel Sambuc } 72433d6423SLionel Sambuc 73433d6423SLionel Sambuc /* 74*91c4db25SDavid van Moolenbroek ** Name: el1_mode_init 75433d6423SLionel Sambuc ** Function: Initializes receicer mode 76433d6423SLionel Sambuc */ 77433d6423SLionel Sambuc static void el1_mode_init(dpeth_t * dep) 78433d6423SLionel Sambuc { 79433d6423SLionel Sambuc 80433d6423SLionel Sambuc if (dep->de_flags & DEF_BROAD) { 81433d6423SLionel Sambuc dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK; 82433d6423SLionel Sambuc 83433d6423SLionel Sambuc } else if (dep->de_flags & DEF_PROMISC) { 84433d6423SLionel Sambuc dep->de_recv_mode = ERSR_ALL | ERSR_RMASK; 85433d6423SLionel Sambuc 86433d6423SLionel Sambuc } else if (dep->de_flags & DEF_MULTI) { 87433d6423SLionel Sambuc dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK; 88433d6423SLionel Sambuc 89433d6423SLionel Sambuc } else { 90433d6423SLionel Sambuc dep->de_recv_mode = ERSR_NONE | ERSR_RMASK; 91433d6423SLionel Sambuc } 92433d6423SLionel Sambuc outb_el1(dep, EL1_RECV, dep->de_recv_mode); 93433d6423SLionel Sambuc inb_el1(dep, EL1_RECV); 94433d6423SLionel Sambuc } 95433d6423SLionel Sambuc 96433d6423SLionel Sambuc /* 97*91c4db25SDavid van Moolenbroek ** Name: el1_recv 98433d6423SLionel Sambuc ** Function: Receive function. Called from interrupt handler to 99433d6423SLionel Sambuc ** unload recv. buffer or from main (packet to client) 100433d6423SLionel Sambuc */ 101*91c4db25SDavid van Moolenbroek static ssize_t el1_recv(dpeth_t *dep, struct netdriver_data *data, size_t max) 102433d6423SLionel Sambuc { 103433d6423SLionel Sambuc buff_t *rxptr; 104*91c4db25SDavid van Moolenbroek size_t size; 105433d6423SLionel Sambuc 106*91c4db25SDavid van Moolenbroek if ((rxptr = dep->de_recvq_head) == NULL) 107*91c4db25SDavid van Moolenbroek return SUSPEND; 108433d6423SLionel Sambuc 109433d6423SLionel Sambuc /* Remove buffer from queue and free buffer */ 110433d6423SLionel Sambuc if (dep->de_recvq_tail == dep->de_recvq_head) 111433d6423SLionel Sambuc dep->de_recvq_head = dep->de_recvq_tail = NULL; 112433d6423SLionel Sambuc else 113433d6423SLionel Sambuc dep->de_recvq_head = rxptr->next; 114433d6423SLionel Sambuc 115433d6423SLionel Sambuc /* Copy buffer to user area */ 116*91c4db25SDavid van Moolenbroek size = MIN(rxptr->size, max); 117433d6423SLionel Sambuc 118*91c4db25SDavid van Moolenbroek netdriver_copyout(data, 0, rxptr->buffer, size); 119433d6423SLionel Sambuc 120433d6423SLionel Sambuc /* Return buffer to the idle pool */ 121433d6423SLionel Sambuc free_buff(dep, rxptr); 122*91c4db25SDavid van Moolenbroek 123*91c4db25SDavid van Moolenbroek return size; 124433d6423SLionel Sambuc } 125433d6423SLionel Sambuc 126433d6423SLionel Sambuc /* 127*91c4db25SDavid van Moolenbroek ** Name: el1_send 128*91c4db25SDavid van Moolenbroek ** Function: Send function. 129433d6423SLionel Sambuc */ 130*91c4db25SDavid van Moolenbroek static int el1_send(dpeth_t *dep, struct netdriver_data *data, size_t size) 131433d6423SLionel Sambuc { 132433d6423SLionel Sambuc buff_t *txbuff; 133433d6423SLionel Sambuc clock_t now; 134433d6423SLionel Sambuc 135*91c4db25SDavid van Moolenbroek if (dep->de_flags & DEF_XMIT_BUSY) { 136433d6423SLionel Sambuc getticks(&now); 137433d6423SLionel Sambuc if ((now - dep->de_xmit_start) > 4) { 138433d6423SLionel Sambuc /* Transmitter timed out */ 139433d6423SLionel Sambuc DEBUG(printf("3c501: transmitter timed out ... \n")); 140433d6423SLionel Sambuc dep->de_stat.ets_sendErr += 1; 141433d6423SLionel Sambuc dep->de_flags &= NOT(DEF_XMIT_BUSY); 142*91c4db25SDavid van Moolenbroek /* Try sending anyway. */ 143*91c4db25SDavid van Moolenbroek } else 144*91c4db25SDavid van Moolenbroek return SUSPEND; 145433d6423SLionel Sambuc } 146433d6423SLionel Sambuc 147*91c4db25SDavid van Moolenbroek /* Since we may have to retransmit, we need a local copy. */ 148*91c4db25SDavid van Moolenbroek if ((txbuff = alloc_buff(dep, size + sizeof(buff_t))) == NULL) 149*91c4db25SDavid van Moolenbroek panic("out of memory"); 150*91c4db25SDavid van Moolenbroek 151*91c4db25SDavid van Moolenbroek /* Fill transmit buffer from user area */ 152*91c4db25SDavid van Moolenbroek txbuff->next = NULL; 153*91c4db25SDavid van Moolenbroek txbuff->size = size; 154*91c4db25SDavid van Moolenbroek 155*91c4db25SDavid van Moolenbroek netdriver_copyin(data, 0, txbuff->buffer, size); 156*91c4db25SDavid van Moolenbroek 157433d6423SLionel Sambuc /* Save for retransmission */ 158433d6423SLionel Sambuc TxBuff = txbuff; 159*91c4db25SDavid van Moolenbroek dep->de_flags |= DEF_XMIT_BUSY; 160433d6423SLionel Sambuc 161433d6423SLionel Sambuc /* Setup board for packet loading */ 162433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 163433d6423SLionel Sambuc inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */ 164433d6423SLionel Sambuc inb_el1(dep, EL1_XMIT); 165433d6423SLionel Sambuc outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */ 166433d6423SLionel Sambuc 167433d6423SLionel Sambuc /* Loads packet */ 168*91c4db25SDavid van Moolenbroek outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size)); 169*91c4db25SDavid van Moolenbroek outsb(dep->de_data_port, txbuff->buffer, size); 170433d6423SLionel Sambuc /* Starts transmitter */ 171*91c4db25SDavid van Moolenbroek outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size)); 172433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */ 173433d6423SLionel Sambuc 174433d6423SLionel Sambuc getticks(&dep->de_xmit_start); 175*91c4db25SDavid van Moolenbroek 176*91c4db25SDavid van Moolenbroek return OK; 177433d6423SLionel Sambuc } 178433d6423SLionel Sambuc 179433d6423SLionel Sambuc /* 180*91c4db25SDavid van Moolenbroek ** Name: el1_stop 181433d6423SLionel Sambuc ** Function: Stops board and disable interrupts. 182433d6423SLionel Sambuc */ 183433d6423SLionel Sambuc static void el1_stop(dpeth_t * dep) 184433d6423SLionel Sambuc { 185433d6423SLionel Sambuc int ix; 186433d6423SLionel Sambuc 187433d6423SLionel Sambuc DEBUG(printf("%s: stopping Etherlink ....\n", dep->de_name)); 188433d6423SLionel Sambuc for (ix = 0; ix < 8; ix += 1) /* Reset board */ 189433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RESET); 190433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_SYS); 191433d6423SLionel Sambuc sys_irqdisable(&dep->de_hook); /* Disable interrupt */ 192433d6423SLionel Sambuc } 193433d6423SLionel Sambuc 194433d6423SLionel Sambuc /* 195*91c4db25SDavid van Moolenbroek ** Name: el1_interrupt 196433d6423SLionel Sambuc ** Function: Interrupt handler. Acknwledges transmit interrupts 197433d6423SLionel Sambuc ** or unloads receive buffer to memory queue. 198433d6423SLionel Sambuc */ 199433d6423SLionel Sambuc static void el1_interrupt(dpeth_t * dep) 200433d6423SLionel Sambuc { 201433d6423SLionel Sambuc u16_t csr, isr; 202433d6423SLionel Sambuc int pktsize; 203433d6423SLionel Sambuc buff_t *rxptr; 204433d6423SLionel Sambuc 205433d6423SLionel Sambuc csr = inb_el1(dep, EL1_CSR); 206433d6423SLionel Sambuc if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) { 207433d6423SLionel Sambuc 208433d6423SLionel Sambuc /* Got a transmit interrupt */ 209433d6423SLionel Sambuc isr = inb_el1(dep, EL1_XMIT); 210433d6423SLionel Sambuc if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) { 211433d6423SLionel Sambuc DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr)); 212433d6423SLionel Sambuc if (isr & EXSR_JAM) { 213433d6423SLionel Sambuc /* Sending, packet got a collision */ 214433d6423SLionel Sambuc dep->de_stat.ets_collision += 1; 215433d6423SLionel Sambuc /* Put pointer back to beginning of packet */ 216433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 217433d6423SLionel Sambuc outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size)); 218433d6423SLionel Sambuc /* And retrigger transmission */ 219433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); 220433d6423SLionel Sambuc return; 221433d6423SLionel Sambuc 222433d6423SLionel Sambuc } else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) { 223433d6423SLionel Sambuc dep->de_stat.ets_sendErr += 1; 224433d6423SLionel Sambuc 225433d6423SLionel Sambuc } else if (isr & EXSR_UNDER) { 226433d6423SLionel Sambuc dep->de_stat.ets_fifoUnder += 1; 227433d6423SLionel Sambuc } 228433d6423SLionel Sambuc DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr)); 229433d6423SLionel Sambuc el1_reset(dep); 230433d6423SLionel Sambuc } else { 231433d6423SLionel Sambuc /** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/ 232433d6423SLionel Sambuc /* Packet transmitted successfully */ 233433d6423SLionel Sambuc dep->de_stat.ets_packetT += 1; 234433d6423SLionel Sambuc dep->bytes_Tx += (long) (TxBuff->size); 235433d6423SLionel Sambuc free_buff(dep, TxBuff); 236433d6423SLionel Sambuc dep->de_flags &= NOT(DEF_XMIT_BUSY); 237*91c4db25SDavid van Moolenbroek netdriver_send(); 238*91c4db25SDavid van Moolenbroek if (dep->de_flags & DEF_XMIT_BUSY) 239433d6423SLionel Sambuc return; 240433d6423SLionel Sambuc } 241433d6423SLionel Sambuc 242433d6423SLionel Sambuc } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) { 243433d6423SLionel Sambuc 244433d6423SLionel Sambuc /* Got a receive interrupt */ 245433d6423SLionel Sambuc isr = inb_el1(dep, EL1_RECV); 246433d6423SLionel Sambuc pktsize = inw_el1(dep, EL1_RECVPTR); 247433d6423SLionel Sambuc if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) { 248433d6423SLionel Sambuc DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize)); 249433d6423SLionel Sambuc dep->de_stat.ets_recvErr += 1; 250433d6423SLionel Sambuc 251433d6423SLionel Sambuc } else if (pktsize < ETH_MIN_PACK_SIZE || pktsize > ETH_MAX_PACK_SIZE) { 252433d6423SLionel Sambuc DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize)); 253433d6423SLionel Sambuc dep->de_stat.ets_recvErr += 1; 254433d6423SLionel Sambuc 255433d6423SLionel Sambuc } else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) { 256433d6423SLionel Sambuc /* Memory not available. Drop packet */ 257433d6423SLionel Sambuc dep->de_stat.ets_fifoOver += 1; 258433d6423SLionel Sambuc 259433d6423SLionel Sambuc } else if (isr & (ERSR_GOOD | ERSR_ANY)) { 260433d6423SLionel Sambuc /* Got a good packet. Read it from buffer */ 261433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 262433d6423SLionel Sambuc outw_el1(dep, EL1_XMITPTR, 0); 263*91c4db25SDavid van Moolenbroek insb(dep->de_data_port, rxptr->buffer, pktsize); 264433d6423SLionel Sambuc rxptr->next = NULL; 265433d6423SLionel Sambuc rxptr->size = pktsize; 266433d6423SLionel Sambuc dep->de_stat.ets_packetR += 1; 267433d6423SLionel Sambuc dep->bytes_Rx += (long) pktsize; 268*91c4db25SDavid van Moolenbroek /* Queue packet to receive queue */ 269433d6423SLionel Sambuc if (dep->de_recvq_head == NULL) 270433d6423SLionel Sambuc dep->de_recvq_head = rxptr; 271433d6423SLionel Sambuc else 272433d6423SLionel Sambuc dep->de_recvq_tail->next = rxptr; 273433d6423SLionel Sambuc dep->de_recvq_tail = rxptr; 274433d6423SLionel Sambuc 275433d6423SLionel Sambuc /* Reply to pending Receive requests, if any */ 276*91c4db25SDavid van Moolenbroek netdriver_recv(); 277433d6423SLionel Sambuc } 278433d6423SLionel Sambuc } else { /* Nasty condition, should never happen */ 279433d6423SLionel Sambuc DEBUG( 280433d6423SLionel Sambuc printf("3c501: got interrupt with status 0x%02X\n" 281433d6423SLionel Sambuc " de_flags=0x%04X XSR=0x%02X RSR=0x%02X \n" 282433d6423SLionel Sambuc " xmit buffer = 0x%4X recv buffer = 0x%4X\n", 283433d6423SLionel Sambuc csr, dep->de_flags, 284433d6423SLionel Sambuc inb_el1(dep, EL1_RECV), 285433d6423SLionel Sambuc inb_el1(dep, EL1_XMIT), 286433d6423SLionel Sambuc inw_el1(dep, EL1_XMITPTR), 287433d6423SLionel Sambuc inw_el1(dep, EL1_RECVPTR)) 288433d6423SLionel Sambuc ); 289433d6423SLionel Sambuc el1_reset(dep); 290433d6423SLionel Sambuc } 291433d6423SLionel Sambuc 292433d6423SLionel Sambuc /* Move into receive mode */ 293433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV); 294433d6423SLionel Sambuc outw_el1(dep, EL1_RECVPTR, 0); 295433d6423SLionel Sambuc /* Be sure that interrupts are cleared */ 296433d6423SLionel Sambuc inb_el1(dep, EL1_RECV); 297433d6423SLionel Sambuc inb_el1(dep, EL1_XMIT); 298433d6423SLionel Sambuc } 299433d6423SLionel Sambuc 300433d6423SLionel Sambuc /* 301*91c4db25SDavid van Moolenbroek ** Name: el1_init 302433d6423SLionel Sambuc ** Function: Initalizes board hardware and driver data structures. 303433d6423SLionel Sambuc */ 304433d6423SLionel Sambuc static void el1_init(dpeth_t * dep) 305433d6423SLionel Sambuc { 306433d6423SLionel Sambuc int ix; 307433d6423SLionel Sambuc 308433d6423SLionel Sambuc dep->de_irq &= NOT(DEI_DEFAULT); /* Strip the default flag. */ 309433d6423SLionel Sambuc dep->de_offset_page = 0; 310433d6423SLionel Sambuc dep->de_data_port = dep->de_base_port + EL1_DATAPORT; 311433d6423SLionel Sambuc 312433d6423SLionel Sambuc el1_reset(dep); /* Reset and initialize board */ 313433d6423SLionel Sambuc 314433d6423SLionel Sambuc /* Start receiver (default mode) */ 315433d6423SLionel Sambuc outw_el1(dep, EL1_RECVPTR, 0); 316433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV); 317433d6423SLionel Sambuc 318433d6423SLionel Sambuc /* Initializes buffer pool */ 319433d6423SLionel Sambuc init_buff(dep, NULL); 320433d6423SLionel Sambuc el1_mode_init(dep); 321433d6423SLionel Sambuc 322433d6423SLionel Sambuc printf("%s: Etherlink (%s) at %X:%d - ", 323433d6423SLionel Sambuc dep->de_name, "3c501", dep->de_base_port, dep->de_irq); 324433d6423SLionel Sambuc for (ix = 0; ix < SA_ADDR_LEN; ix += 1) 325433d6423SLionel Sambuc printf("%02X%c", (dep->de_address.ea_addr[ix] = StationAddress[ix]), 326433d6423SLionel Sambuc ix < SA_ADDR_LEN - 1 ? ':' : '\n'); 327433d6423SLionel Sambuc 328433d6423SLionel Sambuc /* Device specific functions */ 329433d6423SLionel Sambuc dep->de_recvf = el1_recv; 330433d6423SLionel Sambuc dep->de_sendf = el1_send; 331433d6423SLionel Sambuc dep->de_flagsf = el1_mode_init; 332433d6423SLionel Sambuc dep->de_resetf = el1_reset; 333433d6423SLionel Sambuc dep->de_getstatsf = el1_getstats; 334433d6423SLionel Sambuc dep->de_dumpstatsf = el1_dumpstats; 335433d6423SLionel Sambuc dep->de_interruptf = el1_interrupt; 336433d6423SLionel Sambuc } 337433d6423SLionel Sambuc 338433d6423SLionel Sambuc /* 339*91c4db25SDavid van Moolenbroek ** Name: el1_probe 340433d6423SLionel Sambuc ** Function: Checks for presence of the board. 341433d6423SLionel Sambuc */ 342433d6423SLionel Sambuc int el1_probe(dpeth_t * dep) 343433d6423SLionel Sambuc { 344433d6423SLionel Sambuc int ix; 345433d6423SLionel Sambuc 346433d6423SLionel Sambuc for (ix = 0; ix < 8; ix += 1) /* Reset the board */ 347433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_RESET); 348433d6423SLionel Sambuc outb_el1(dep, EL1_CSR, ECSR_SYS); /* Leaves buffer to system */ 349433d6423SLionel Sambuc 350433d6423SLionel Sambuc /* Check station address */ 351433d6423SLionel Sambuc for (ix = 0; ix < SA_ADDR_LEN; ix += 1) { 352433d6423SLionel Sambuc outw_el1(dep, EL1_XMITPTR, ix); 353433d6423SLionel Sambuc StationAddress[ix] = inb_el1(dep, EL1_SAPROM); 354433d6423SLionel Sambuc } 355433d6423SLionel Sambuc if (StationAddress[0] != 0x02 || /* Etherlink Station address */ 356433d6423SLionel Sambuc StationAddress[1] != 0x60 || /* MUST be 02:60:8c:xx:xx:xx */ 357433d6423SLionel Sambuc StationAddress[2] != 0x8C) 358433d6423SLionel Sambuc return FALSE; /* No Etherlink board at this address */ 359433d6423SLionel Sambuc 360433d6423SLionel Sambuc dep->de_ramsize = 0; /* RAM size is meaningless */ 361433d6423SLionel Sambuc dep->de_linmem = 0L; /* Access is via I/O port */ 362433d6423SLionel Sambuc 363433d6423SLionel Sambuc /* Device specific functions */ 364433d6423SLionel Sambuc dep->de_initf = el1_init; 365433d6423SLionel Sambuc dep->de_stopf = el1_stop; 366433d6423SLionel Sambuc 367433d6423SLionel Sambuc return TRUE; /* Etherlink board found */ 368433d6423SLionel Sambuc } 369433d6423SLionel Sambuc 370433d6423SLionel Sambuc #endif /* ENABLE_3C501 */ 371433d6423SLionel Sambuc 372433d6423SLionel Sambuc /** 3c501.c **/ 373