/* * RTEMS driver for TULIP based Ethernet Controller * * Copyright (C) 1999 Emmanuel Raguet. raguet@crf.canon.fr * * The license and distribution terms for this file may be * found in found in the file LICENSE in this distribution or at * http://www.OARcorp.com/rtems/license.html. * * $Id$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef malloc #undef malloc #endif #ifdef free #undef free #endif #define DEC_DEBUG #define PCI_INVALID_VENDORDEVICEID 0xffffffff #define PCI_VENDOR_ID_DEC 0x1011 #define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009 #define IO_MASK 0x3 #define MEM_MASK 0xF #define MASK_OFFSET 0xF /* command and status registers, 32-bit access, only if IO-ACCESS */ #define ioCSR0 0x00 /* bus mode register */ #define ioCSR1 0x08 /* transmit poll demand */ #define ioCSR2 0x10 /* receive poll demand */ #define ioCSR3 0x18 /* receive list base address */ #define ioCSR4 0x20 /* transmit list base address */ #define ioCSR5 0x28 /* status register */ #define ioCSR6 0x30 /* operation mode register */ #define ioCSR7 0x38 /* interrupt mask register */ #define ioCSR8 0x40 /* missed frame counter */ #define ioCSR9 0x48 /* Ethernet ROM register */ #define ioCSR10 0x50 /* reserved */ #define ioCSR11 0x58 /* full-duplex register */ #define ioCSR12 0x60 /* SIA status register */ #define ioCSR13 0x68 #define ioCSR14 0x70 #define ioCSR15 0x78 /* SIA general register */ /* command and status registers, 32-bit access, only if MEMORY-ACCESS */ #define memCSR0 0x00 /* bus mode register */ #define memCSR1 0x02 /* transmit poll demand */ #define memCSR2 0x04 /* receive poll demand */ #define memCSR3 0x06 /* receive list base address */ #define memCSR4 0x08 /* transmit list base address */ #define memCSR5 0x0A /* status register */ #define memCSR6 0x0C /* operation mode register */ #define memCSR7 0x0E /* interrupt mask register */ #define memCSR8 0x10 /* missed frame counter */ #define memCSR9 0x12 /* Ethernet ROM register */ #define memCSR10 0x14 /* reserved */ #define memCSR11 0x16 /* full-duplex register */ #define memCSR12 0x18 /* SIA status register */ #define memCSR13 0x1A #define memCSR14 0x1C #define memCSR15 0x1E /* SIA general register */ #define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */ #define RESET_CHIP 0x00000001 #define CSR0_MODE 0x01b08000 /* 01a08000 */ #define ROM_ADDRESS 0x00004800 #define CSR6_INIT 0x020c0000 /* 020c0000 */ #define CSR6_TX 0x00002000 #define CSR6_TXRX 0x00002002 #define IT_SETUP 0x00010040 /* 0001ebef */ #define CLEAR_IT 0xFFFFFFFF #define NO_IT 0x00000000 #define NRXBUFS 7 /* number of receive buffers */ #define NTXBUFS 1 /* number of transmit buffers */ /* message descriptor entry */ struct MD { volatile unsigned long status; volatile unsigned long counts; volatile unsigned char *buf1, *buf2; }; /* * Number of WDs supported by this driver */ #define NDECDRIVER 1 /* * Receive buffer size -- Allow for a full ethernet packet including CRC */ #define RBUF_SIZE 1536 #define ET_MINLEN 60 /* minimum message length */ /* * RTEMS event used by interrupt handler to signal driver tasks. * This must not be any of the events used by the network task synchronization. */ #define INTERRUPT_EVENT RTEMS_EVENT_1 /* * RTEMS event used to start transmit daemon. * This must not be the same as INTERRUPT_EVENT. */ #define START_TRANSMIT_EVENT RTEMS_EVENT_2 #if (MCLBYTES < RBUF_SIZE) # error "Driver must have MCLBYTES > RBUF_SIZE" #endif /* * Per-device data */ struct dec21140_softc { struct arpcom arpcom; rtems_irq_connect_data irqInfo; volatile struct MD *MDbase; volatile unsigned char *bufferBase; int acceptBroadcast; int rxBdCount; int txBdCount; rtems_id rxDaemonTid; rtems_id txDaemonTid; unsigned int port; volatile unsigned int *base; unsigned long bpar; /* * Statistics */ unsigned long rxInterrupts; unsigned long rxNotFirst; unsigned long rxNotLast; unsigned long rxGiant; unsigned long rxNonOctet; unsigned long rxRunt; unsigned long rxBadCRC; unsigned long rxOverrun; unsigned long rxCollision; unsigned long txInterrupts; unsigned long txDeferred; unsigned long txHeartbeat; unsigned long txLateCollision; unsigned long txRetryLimit; unsigned long txUnderrun; unsigned long txLostCarrier; unsigned long txRawWait; }; static struct dec21140_softc dec21140_softc[NDECDRIVER]; /* * DEC21140 interrupt handler */ static rtems_isr dec21140Enet_interrupt_handler (rtems_vector_number v) { volatile unsigned int *tbase; unsigned long status; unsigned int sc; tbase = dec21140_softc[0].base ; /* * Read status */ st_le32((tbase+memCSR7), NO_IT); status = ld_le32(tbase+memCSR5); st_le32((tbase+memCSR5), CLEAR_IT); /* * Frame received? */ if (status & 0x00000040){ dec21140_softc[0].rxInterrupts++; sc = rtems_event_send (dec21140_softc[0].rxDaemonTid, INTERRUPT_EVENT); } } static void nopOn(const rtems_irq_connect_data* notUsed) { /* * code should be moved from dec21140Enet_initialize_hardware * to this location */ } static int dec21140IsOn(const rtems_irq_connect_data* irq) { return BSP_irq_enabled_at_i8259s (irq->name); } /* * Read and write the MII registers using software-generated serial * MDIO protocol. */ #define MDIO_SHIFT_CLK 0x10000 #define MDIO_DATA_WRITE0 0x00000 #define MDIO_DATA_WRITE1 0x20000 #define MDIO_ENB 0x00000 #define MDIO_ENB_IN 0x40000 #define MDIO_DATA_READ 0x80000 static int mdio_read(volatile unsigned int *ioaddr, int phy_id, int location) { int i, i3; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned short retval = 0; /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1); for(i3=0; i3<1000; i3++); st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); for(i3=0; i3<1000; i3++); } /* Shift the read command bits out. */ for (i = 17; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; st_le32(ioaddr, dataval); for(i3=0; i3<1000; i3++); st_le32(ioaddr, dataval | MDIO_SHIFT_CLK); for(i3=0; i3<1000; i3++); st_le32(ioaddr, dataval); for(i3=0; i3<1000; i3++); } st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); for(i3=0; i3<1000; i3++); st_le32(ioaddr, MDIO_ENB_IN); for (i = 16; i > 0; i--) { st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); for(i3=0; i3<1000; i3++); retval = (retval << 1) | ((ld_le32(ioaddr) & MDIO_DATA_READ) ? 1 : 0); st_le32(ioaddr, MDIO_ENB_IN); for(i3=0; i3<1000; i3++); } /* Clear out extra bits. */ for (i = 16; i > 0; i--) { st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); for(i3=0; i3<1000; i3++); st_le32(ioaddr, MDIO_ENB_IN); for(i3=0; i3<1000; i3++); } return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); } static int mdio_write(volatile unsigned int *ioaddr, int phy_id, int location, int value) { int i, i3; int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1); for(i3=0; i3<1000; i3++); st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); for(i3=0; i3<1000; i3++); } /* Shift the read command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; st_le32(ioaddr, dataval); for(i3=0; i3<1000; i3++); st_le32(ioaddr, dataval | MDIO_SHIFT_CLK); for(i3=0; i3<1000; i3++); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { st_le32(ioaddr, MDIO_ENB_IN); for(i3=0; i3<1000; i3++); st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); for(i3=0; i3<1000; i3++); } return 0; } /* * This routine reads a word (16 bits) from the serial EEPROM. */ /* EEPROM_Ctrl bits. */ #define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ #define EE_CS 0x01 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ #define EE_WRITE_0 0x01 #define EE_WRITE_1 0x05 #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ #define EE_ENB (0x4800 | EE_CS) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5 << 6) #define EE_READ_CMD (6 << 6) #define EE_ERASE_CMD (7 << 6) static int eeget16(volatile unsigned int *ioaddr, int location) { int i, i3; unsigned short retval = 0; int read_cmd = location | EE_READ_CMD; st_le32(ioaddr, EE_ENB & ~EE_CS); st_le32(ioaddr, EE_ENB); /* Shift the read command bits out. */ for (i = 10; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; st_le32(ioaddr, EE_ENB | dataval); for (i3=0; i3<1000; i3++) ; st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK); for (i3=0; i3<1000; i3++) ; st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */ for (i3=0; i3<1000; i3++) ; } st_le32(ioaddr, EE_ENB); for (i = 16; i > 0; i--) { st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK); for (i3=0; i3<1000; i3++) ; retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0); st_le32(ioaddr, EE_ENB); for (i3=0; i3<1000; i3++) ; } /* Terminate the EEPROM access. */ st_le32(ioaddr, EE_ENB & ~EE_CS); return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); } /* * Initialize the ethernet hardware */ static void dec21140Enet_initialize_hardware (struct dec21140_softc *sc) { rtems_status_code st; volatile unsigned int *tbase; union {char c[64]; unsigned short s[32];} rombuf; int i, i2, i3; volatile unsigned char *cp, direction, *setup_frm, *eaddrs; unsigned long csr12_val, mii_reg0; volatile unsigned char *buffer; volatile struct MD *rmd; tbase = sc->base; /* * WARNING : First write in CSR6 * Then Reset the chip ( 1 in CSR0) */ st_le32( (tbase+memCSR6), CSR6_INIT); st_le32( (tbase+memCSR0), RESET_CHIP); for(i3=0; i3<1000; i3++); /* * Init CSR0 */ st_le32( (tbase+memCSR0), CSR0_MODE); csr12_val = ld_le32( (tbase+memCSR8) ); for (i=0; i<32; i++){ rombuf.s[i] = eeget16(tbase+memCSR9, i); } memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN); mii_reg0 = mdio_read(tbase+memCSR9, 0, 0); mdio_write(tbase+memCSR9, 0, 0, mii_reg0 | 0x1000); #ifdef DEC_DEBUG printk("DC21140 %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n", sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1], sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3], sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5], sc->irqInfo.name, sc->port, (unsigned) sc->base); #endif /* * Init RX ring */ sc->rxBdCount = 0; cp = (volatile unsigned char *)malloc((NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE) + PPC_CACHE_ALIGNMENT); sc->bufferBase = cp; if ((unsigned int)cp & (PPC_CACHE_ALIGNMENT-1)) cp = (volatile unsigned char *) (((unsigned int)cp + PPC_CACHE_ALIGNMENT) & ~(PPC_CACHE_ALIGNMENT-1)); #ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA if (_CPU_is_paging_enabled()) _CPU_change_memory_mapping_attribute (NULL, cp, (NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE), PTE_CACHE_DISABLE | PTE_WRITABLE); #endif rmd = (volatile struct MD*)cp; sc->MDbase = rmd; buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD)); st_le32( (tbase+memCSR3), (long)((long)(sc->MDbase) + PREP_PCI_DRAM_OFFSET)); for (i=0 ; ibuf2 = (volatile unsigned char *) 0; rmd->buf1 = (buffer + (i*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET); rmd->counts = 0xfcc00000 | (RBUF_SIZE); rmd->status = 0x80000000; rmd++; } /* * mark last RX buffer. */ sc->MDbase [NRXBUFS-1].counts = 0xfec00000 | (RBUF_SIZE); /* * Init TX ring */ sc->txBdCount = 0; st_le32( (tbase+memCSR4), (long)(((long)(rmd)) + PREP_PCI_DRAM_OFFSET)); rmd->buf2 = (volatile unsigned char *) 0; rmd->buf1 = buffer + (NRXBUFS*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET; rmd->counts = 0x62000000; rmd->status = 0x0; /* * Set up interrupts */ st_le32( (tbase+memCSR5), IT_SETUP); st_le32( (tbase+memCSR7), IT_SETUP); sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler; sc->irqInfo.on = nopOn; sc->irqInfo.off = nopOn; sc->irqInfo.isOn = dec21140IsOn; st = BSP_install_rtems_irq_handler (&sc->irqInfo); if (!st) rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n", sc->irqInfo.name); /* * Start TX for setup frame */ st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX); /* * Build setup frame */ setup_frm = rmd->buf1 - PREP_PCI_DRAM_OFFSET; eaddrs = (char *)(sc->arpcom.ac_enaddr); /* Fill the buffer with our physical address. */ for (i = 1; i < 16; i++) { *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[3]; *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[3]; *setup_frm++ = eaddrs[4]; *setup_frm++ = eaddrs[5]; *setup_frm++ = eaddrs[4]; *setup_frm++ = eaddrs[5]; } /* Add the broadcast address when doing perfect filtering */ memset((void*) setup_frm, 0xff, 12); rmd->counts = 0x0a000000 | 192 ; rmd->status = 0x80000000; st_le32( (tbase+memCSR1), 1); while (rmd->status != 0x7fffffff); /* * Enable RX and TX */ st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX); /* * Set up PHY */ i = rombuf.c[27]; i+=2; direction = rombuf.c[i]; i +=4; st_le32( (tbase+memCSR12), direction | 0x100); for (i2 = 0; i2 < rombuf.c[(i+2) + rombuf.c[i+1]]; i2++){ st_le32( (tbase + memCSR12), rombuf.c[(i+3) + rombuf.c[i+1] + i2]); } for (i2 = 0; i2 < rombuf.c[i+1]; i2++){ st_le32( (tbase + memCSR12), rombuf.c[(i+2) + i2]); } } static void dec21140_rxDaemon (void *arg) { volatile unsigned int *tbase; struct ether_header *eh; struct dec21140_softc *dp = (struct dec21140_softc *)&dec21140_softc[0]; struct ifnet *ifp = &dp->arpcom.ac_if; struct mbuf *m; volatile struct MD *rmd; unsigned int len; char *temp; rtems_event_set events; int nbMD; tbase = dec21140_softc[0].base ; for (;;){ rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT|RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); rmd = dec21140_softc[0].MDbase; nbMD = 0; while (nbMD < NRXBUFS){ if ( (rmd->status & 0x80000000) == 0){ len = (rmd->status >> 16) & 0x7ff; MGETHDR (m, M_WAIT, MT_DATA); MCLGET (m, M_WAIT); m->m_pkthdr.rcvif = ifp; temp = m->m_data; m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); memcpy(temp, (void*) (rmd->buf1-PREP_PCI_DRAM_OFFSET), len); rmd->status = 0x80000000; eh = mtod (m, struct ether_header *); m->m_data += sizeof(struct ether_header); ether_input (ifp, eh, m); } rmd++; nbMD++; } st_le32( (tbase+memCSR7), IT_SETUP); } } static void sendpacket (struct ifnet *ifp, struct mbuf *m) { struct dec21140_softc *dp = ifp->if_softc; volatile struct MD *tmd; volatile unsigned char *temp; struct mbuf *n; unsigned int len; volatile unsigned int *tbase; tbase = dp->base; /* * Waiting for Transmitter ready */ tmd = dec21140_softc[0].MDbase + NRXBUFS; while ( (tmd->status & 0x80000000) != 0 ); len = 0; n = m; temp = tmd->buf1-PREP_PCI_DRAM_OFFSET; for (;;){ len += m->m_len; memcpy((void*) temp, (char *)m->m_data, m->m_len); temp += m->m_len ; if ((m = m->m_next) == NULL) break; } if (len < ET_MINLEN) len = ET_MINLEN; tmd->counts = 0xe2000000 | len; tmd->status = 0x80000000; st_le32( (tbase+memCSR1), 0x1); m_freem(n); } /* * Driver transmit daemon */ void dec21140_txDaemon (void *arg) { struct dec21140_softc *sc = (struct dec21140_softc *)arg; struct ifnet *ifp = &sc->arpcom.ac_if; struct mbuf *m; rtems_event_set events; for (;;) { /* * Wait for packet */ rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); /* * Send packets till queue is empty */ for (;;) { /* * Get the next mbuf chain to transmit. */ IF_DEQUEUE(&ifp->if_snd, m); if (!m) break; sendpacket (ifp, m); } ifp->if_flags &= ~IFF_OACTIVE; } } static void dec21140_start (struct ifnet *ifp) { struct dec21140_softc *sc = ifp->if_softc; rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); ifp->if_flags |= IFF_OACTIVE; } /* * Initialize and start the device */ static void dec21140_init (void *arg) { struct dec21140_softc *sc = arg; struct ifnet *ifp = &sc->arpcom.ac_if; if (sc->txDaemonTid == 0) { /* * Set up DEC21140 hardware */ dec21140Enet_initialize_hardware (sc); /* * Start driver tasks */ sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096, dec21140_rxDaemon, sc); sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, dec21140_txDaemon, sc); } /* * Tell the world that we're running. */ ifp->if_flags |= IFF_RUNNING; } /* * Stop the device */ static void dec21140_stop (struct dec21140_softc *sc) { volatile unsigned int *tbase; struct ifnet *ifp = &sc->arpcom.ac_if; ifp->if_flags &= ~IFF_RUNNING; /* * Stop the transmitter */ tbase=dec21140_softc[0].base ; st_le32( (tbase+memCSR7), NO_IT); st_le32( (tbase+memCSR6), CSR6_INIT); free((void*)sc->bufferBase); } /* * Show interface statistics */ static void dec21140_stats (struct dec21140_softc *sc) { printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); printf (" Not First:%-8lu", sc->rxNotFirst); printf (" Not Last:%-8lu\n", sc->rxNotLast); printf (" Giant:%-8lu", sc->rxGiant); printf (" Runt:%-8lu", sc->rxRunt); printf (" Non-octet:%-8lu\n", sc->rxNonOctet); printf (" Bad CRC:%-8lu", sc->rxBadCRC); printf (" Overrun:%-8lu", sc->rxOverrun); printf (" Collision:%-8lu\n", sc->rxCollision); printf (" Tx Interrupts:%-8lu", sc->txInterrupts); printf (" Deferred:%-8lu", sc->txDeferred); printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat); printf (" No Carrier:%-8lu", sc->txLostCarrier); printf ("Retransmit Limit:%-8lu", sc->txRetryLimit); printf (" Late Collision:%-8lu\n", sc->txLateCollision); printf (" Underrun:%-8lu", sc->txUnderrun); printf (" Raw output wait:%-8lu\n", sc->txRawWait); } /* * Driver ioctl handler */ static int dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data) { struct dec21140_softc *sc = ifp->if_softc; int error = 0; switch (command) { case SIOCGIFADDR: case SIOCSIFADDR: ether_ioctl (ifp, command, data); break; case SIOCSIFFLAGS: switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { case IFF_RUNNING: dec21140_stop (sc); break; case IFF_UP: dec21140_init (sc); break; case IFF_UP | IFF_RUNNING: dec21140_stop (sc); dec21140_init (sc); break; default: break; } break; case SIO_RTEMS_SHOW_STATS: dec21140_stats (sc); break; /* * FIXME: All sorts of multicast commands need to be added here! */ default: error = EINVAL; break; } return error; } /* * Attach an DEC21140 driver to the system */ int rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config) { struct dec21140_softc *sc; struct ifnet *ifp; int mtu; int i; unsigned char ucSlotNumber, ucFnNumber; unsigned int ulDeviceID, lvalue, tmp; unsigned char cvalue; /* * First, find a DEC board */ for(ucSlotNumber=0;ucSlotNumberarpcom.ac_if; if (ifp->if_softc == NULL) break; } if (i >= NDECDRIVER) { printk ("Too many DEC drivers.\n"); return 0; } /* * Process options */ (void)pci_read_config_dword(0, ucSlotNumber, ucFnNumber, PCI_BASE_ADDRESS_0, &lvalue); sc->port = lvalue & (unsigned int)(~IO_MASK); (void)pci_read_config_dword(0, ucSlotNumber, ucFnNumber, PCI_BASE_ADDRESS_1 , &lvalue); tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK)) + (unsigned int)PREP_ISA_MEM_BASE; sc->base = (unsigned int *)(tmp); (void)pci_read_config_byte(0, ucSlotNumber, ucFnNumber, PCI_INTERRUPT_LINE, &cvalue); sc->irqInfo.name = (rtems_irq_symbolic_name)cvalue; if (config->hardware_address) { memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); } else { memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN); } if (config->mtu) mtu = config->mtu; else mtu = ETHERMTU; sc->acceptBroadcast = !config->ignore_broadcast; /* * Set up network interface values */ ifp->if_softc = sc; ifp->if_unit = i + 1; ifp->if_name = "dc"; ifp->if_mtu = mtu; ifp->if_init = dec21140_init; ifp->if_ioctl = dec21140_ioctl; ifp->if_start = dec21140_start; ifp->if_output = ether_output; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; /* * Attach the interface */ if_attach (ifp); ether_ifattach (ifp); return 1; };