📄 3c509.c
字号:
* **********************************************************************************/static void _3c509_rxDaemon (void *arg){ struct ep_softc *dp = (struct ep_softc *)&ep_softc[ 0 ]; rtems_event_set events; printf ("3C509: RX Daemon is starting.\n"); for( ;; ) { /* printk( "R-" ); */ rtems_bsdnet_event_receive( INTERRUPT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events ); /* printk( "R+" ); */ ep_intr( dp ); epstart( &dp->arpcom.ac_if ); } printf ("3C509: RX Daemon is finishing.\n");}/********************************************************************************** * * DESCRIPTION: Driver transmit daemon * * RETURNS: * **********************************************************************************/static void _3c509_txDaemon (void *arg){ struct ep_softc *sc = (struct ep_softc *)&ep_softc[0]; struct ifnet *ifp = &sc->arpcom.ac_if; rtems_event_set events; printf ("3C509: TX Daemon is starting.\n"); for( ;; ) { /* * Wait for packet */ /* printk( "T-\n" ); */ rtems_bsdnet_event_receive( START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events ); /* printk( "T+\n" ); */ epstart( ifp ); while( ifp->if_flags & IFF_OACTIVE ) epstart( ifp ); } printf ("3C509: TX Daemon is finishing.\n");}/********************************************************************************** * * DESCRIPTION: Activates the trabsmitter task... * * RETURNS: nothing. * **********************************************************************************/static void _3c509_start (struct ifnet *ifp){ struct ep_softc *sc = ifp->if_softc; /* printk ("S"); */ ifp->if_flags |= IFF_OACTIVE; rtems_event_send( sc->txDaemonTid, START_TRANSMIT_EVENT );}/********************************************************************************** * * DESCRIPTION: Initialize and start the device * * RETURNS: * **********************************************************************************/static void _3c509_init (void *arg){ struct ep_softc *sc = arg; struct ifnet *ifp = &sc->arpcom.ac_if; printf ("3C509: Initialization called.\n"); if (sc->txDaemonTid == 0) { /* * Set up WD hardware */ _3c509_initialize_hardware (sc); printf ("3C509: starting network driver tasks..\n"); /* * Start driver tasks */ sc->txDaemonTid = rtems_bsdnet_newproc ("APtx", 4096, _3c509_txDaemon, sc); sc->rxDaemonTid = rtems_bsdnet_newproc ("APrx", 4096, _3c509_rxDaemon, sc); } /* * Tell the world that we're running. */ ifp->if_flags |= IFF_RUNNING;}/********************************************************************************** * * DESCRIPTION: Stop the device * * RETURNS: * **********************************************************************************/static void _3c509_stop (struct ep_softc *sc){ struct ifnet *ifp = &sc->arpcom.ac_if; ifp->if_flags &= ~IFF_RUNNING; printf ("3C509: stop() called.\n"); /* * Stop the transmitter */ outw(BASE + EP_COMMAND, RX_DISABLE); outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); outw(BASE + EP_COMMAND, TX_DISABLE); outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); outw(BASE + EP_COMMAND, RX_RESET); outw(BASE + EP_COMMAND, TX_RESET); while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); outw(BASE + EP_COMMAND, C_INTR_LATCH); outw(BASE + EP_COMMAND, SET_RD_0_MASK); outw(BASE + EP_COMMAND, SET_INTR_MASK); outw(BASE + EP_COMMAND, SET_RX_FILTER);}/********************************************************************************** * * DESCRIPTION: Show interface statistics * * RETURNS: nothing. * **********************************************************************************/static void _3c509_stats (struct ep_softc *sc){ struct ifnet *ifp = &sc->arpcom.ac_if; printf ("3C509: stats() called.\n"); printf("\tStat: %x\n", sc->stat); printf("\tIpackets=%ld, Opackets=%ld\n", ifp->if_ipackets, ifp->if_opackets); printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n", sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf, sc->rx_overrunl, sc->tx_underrun );}/********************************************************************************** * * DESCRIPTION: Driver ioctl handler * * RETURNS: * **********************************************************************************/static int _3c509_ioctl (struct ifnet *ifp, int command, caddr_t data){ struct ep_softc *sc = ifp->if_softc; int error = 0; printf ("3C509: ioctl() called.\n"); 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: _3c509_stop (sc); break; case IFF_UP: _3c509_init (sc); break; case IFF_UP | IFF_RUNNING: _3c509_stop (sc); _3c509_init (sc); break; default: break; } break; case SIO_RTEMS_SHOW_STATS: _3c509_stats( sc ); break; /* * FIXME: All sorts of multicast commands need to be added here! */ default: error = EINVAL; break; } return error;}/********************************************************************************** * * DESCRIPTION: * Attaches this network driver to the system. This function is called by the network * interface during the initialization of the system. * * RETURNS: - 1 - success; 0 - fail to initialize * **********************************************************************************/int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *config ){ struct ep_softc *sc; struct ifnet *ifp; int mtu; int i; printf ("3C509: attach() called.\n"); /* * init some variables */ overrun = 0; resend = 0; ep_unit = 0; ep_boards = 0; /* * Find a free driver */ for (i = 0 ; i < NWDDRIVER ; i++) { sc = &ep_softc[i]; ifp = &sc->arpcom.ac_if; if (ifp->if_softc == NULL) break; } if (i >= NWDDRIVER) { printf ("Too many 3C509 drivers.\n"); return 0; } /* * Process options */ if( config->hardware_address ) { memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); } else { /* set it to something ... */ memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN); } if (config->mtu) mtu = config->mtu; else mtu = ETHERMTU; if (config->irno) sc->irqInfo.name = config->irno; else sc->irqInfo.name = 10; if (config->port) sc->ep_io_addr = config->port; else sc->ep_io_addr = 0x300; sc->acceptBroadcast = !config->ignore_broadcast; printf ("3C509: isa_probe() looking for a card...\n"); if( !ep_isa_probe( &isa_dev[ 0 ] ) ) { printf ("3C509: isa_probe() fail to find a board.\n"); return 0; } /* A board has been found, so proceed with the installation of the driver */ ep_isa_attach( &isa_dev[ 0 ] ); /* * Set up network interface values */ ifp->if_softc = sc; ifp->if_unit = i; ifp->if_name = NET_DRIVER_NAME; ifp->if_mtu = mtu; ifp->if_init = _3c509_init; ifp->if_ioctl = _3c509_ioctl; ifp->if_start = _3c509_start; ifp->if_output = ether_output; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; if( ifp->if_snd.ifq_maxlen == 0 ) { ifp->if_snd.ifq_maxlen = ifqmaxlen; } /* * Attach the interface */ if_attach (ifp); ether_ifattach (ifp); printf ("3C509: attach() is complete.\n"); return 1;}/********************************************************************************** * * DESCRIPTION: * This function looks for a 3COM card 3c5x9 in an isa bus. If a board is found, it * returns a structure describing the caracteristics of the card. It returns zero when * card can not be found. * * RETURNS: 0 - fail - could not find a card... * <> description of the card. * **********************************************************************************/static struct ep_board *ep_look_for_board_at( struct isa_device *is ){ int data, i, j, id_port = ELINK_ID_PORT; int count = 0; if(ep_current_tag == (EP_LAST_TAG + 1) ) { /* Come here just one time */ ep_current_tag--; /* Look for the ISA boards. Init and leave them actived */ outb(id_port, 0); outb(id_port, 0); elink_idseq(0xCF); elink_reset(); Wait_X_ms( 10 ); /* RPS: assuming delay in miliseconds */ for (i = 0; i < EP_MAX_BOARDS; i++) { outb(id_port, 0); outb(id_port, 0); elink_idseq(0xCF); data = get_eeprom_data(id_port, EEPROM_MFG_ID); if (data != MFG_ID) break; /* resolve contention using the Ethernet address */ for (j = 0; j < 3; j++) get_eeprom_data(id_port, j); /* and save this address for later use */ for (j = 0; j < 3; j++) ep_board[ep_boards].eth_addr[j] = get_eeprom_data(id_port, j); ep_board[ep_boards].res_cfg = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); ep_board[ep_boards].prod_id = get_eeprom_data(id_port, EEPROM_PROD_ID); ep_board[ep_boards].epb_used = 0;#ifdef PC98 ep_board[ep_boards].epb_addr = (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x100 + 0x40d0;#else ep_board[ep_boards].epb_addr = (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; if (ep_board[ep_boards].epb_addr > 0x3E0) /* Board in EISA configuration mode */ continue;#endif /* PC98 */ outb(id_port, ep_current_tag); /* tags board */ outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); ep_boards++; count++; ep_current_tag--; } ep_board[ep_boards].epb_addr = 0; if( count ) { printf("%d 3C5x9 board(s) on ISA found at", count); for (j = 0; ep_board[j].epb_addr; j++) if( ep_board[j].epb_addr <= 0x3E0 ) printf(" 0x%x", ep_board[j].epb_addr ); printf("\n"); } } /* we have two cases: * * 1. Device was configured with 'port ?' * In this case we search for the first unused card in list * * 2. Device was configured with 'port xxx' * In this case we search for the unused card with that address * */ if (IS_BASE == -1) { /* port? */ for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_used; i++) ; if (ep_board[i].epb_addr == 0) return 0; IS_BASE = ep_board[i].epb_addr; ep_board[i].epb_used = 1; return &ep_board[ i ]; } else { for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; i++ ) ; if (ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE) return 0; if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE) { printf("ep%d: 3c5x9 at 0x%x in PnP mode. Disable PnP mode!\n", is->id_unit, IS_BASE ); } ep_board[i].epb_used = 1; return &ep_board[i]; }}/********************************************************************************** * * DESCRIPTION: * This routine checks if there card installed on the machine. * * RETURNS: 0 - no card founded. * 16 - size of the IO range for the card. * **********************************************************************************/static int ep_isa_probe( struct isa_device *is ){ struct ep_softc *sc; struct ep_board *epb; u_short k; /* try to find a 3COM 3c5x9 .... */ if( (epb = ep_look_for_board_at(is)) == 0 ) return (0); sc = &ep_softc[ 0 ]; sc->ep_io_addr = epb->epb_addr; sc->epb = epb; /* * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be * 0x9[0-f]50 (IBM-PC) * 0x9[0-f]5[0-f] (PC-98) */ GO_WINDOW(0); k = sc->epb->prod_id;#ifdef PC98 if ((k & 0xf0f0) != (PROD_ID & 0xf0f0)) {#else if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) {#endif printf("ep_isa_probe: ignoring model %04x\n", k );/* ep_unit--; */ return (0); } k = sc->epb->res_cfg; k >>= 12; /* Now we have two cases again: * * 1. Device was configured with 'irq?' * In this case we use irq read from the board * * 2. Device was configured with 'irq xxx' * In this case we set up the board to use specified interrupt * */ if (is->id_irq == 0) { /* irq? */ is->id_irq = ( k == 2 ) ? 9 : k; } sc->stat = 0; /* 16 bit access */ /* By now, the adapter is already activated */ return (EP_IOSIZE); /* 16 bytes of I/O space used. */}/********************************************************************************** * * DESCRIPTION: * This routine attaches this network driver and the network interface routines. * * RETURNS: 0 - failed to attach * 1 - success * **********************************************************************************/static int ep_isa_attach( struct isa_device *is ){ struct ep_softc *sc = &ep_softc[ 0 ]; u_short config; int irq; sc->ep_connectors = 0; config = inw( IS_BASE + EP_W0_CONFIG_CTRL ); if (config & IS_AUI) { sc->ep_connectors |= AUI; } if (config & IS_BNC) { sc->ep_connectors |= BNC; } if (config & IS_UTP) { sc->ep_connectors |= UTP; } if( !(sc->ep_connectors & 7) ) printf( "no connectors!" ); sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; /* * Write IRQ value to board */ irq = is->id_irq; /* update the interrupt line number to registered with kernel */ sc->irqInfo.name = irq; GO_WINDOW( 0 ); SET_IRQ( BASE, irq ); printf( "3C509: I/O=0x%x, IRQ=%d, CONNECTOR=%s, ", sc->ep_io_addr, sc->irqInfo.name,ep_conn_type[ sc->ep_connector ] ); ep_attach( sc ); return 1;}/********************************************************************************** *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -