if_atlas.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,055 行 · 第 1/2 页

C
1,055
字号
                unsigned long __base = spd->base;                SAA9730_EVM_IER_SW |= (SAA9730_EVM_LAN_INT|SAA9730_EVM_MASTER);                                SAA9730_EVM_IER |= (SAA9730_EVM_LAN_INT|SAA9730_EVM_MASTER);                SAA9730_EVM_ISR |= (SAA9730_EVM_LAN_INT|SAA9730_EVM_MASTER);            }#ifdef DEBUG	    db_printf(" **** Device enabled for I/O and Memory and Bus Master\n");#endif        } else {#ifdef DEBUG            db_printf("eth0 not found\n");#endif        }        saa9730_stop(sc);        	spd->active = 0;	initialized = 1;    }    // Fetch hardware address#if defined(CYGPKG_REDBOOT) && \    defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \    !defined(CYGSEM_MIPS_ATLAS_SET_ESA)    flash_get_config("atlas_esa", enaddr, CONFIG_ESA);#else#define CONFIG_ESA     6    CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,                                 "atlas_esa", enaddr, CONFIG_ESA );#ifdef DEBUG    db_printf("ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",              enaddr[0],enaddr[1],enaddr[2],enaddr[3],enaddr[4],enaddr[5]);#endif#endif    saa9730_reset(spd);    // Initialize upper level driver    (sc->funs->eth_drv->init)(sc, enaddr);    return true;}static voidsaa9730_stop(struct eth_drv_sc *sc){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;    unsigned long __base = spd->base;    // Stop DMA    SAA9730_DMACTL &= ~(SAA9730_DMACTL_ENRX | SAA9730_DMACTL_ENTX);    // Stop tx/rx    SAA9730_TXCTL &= ~SAA9730_TXCTL_ENTX;    SAA9730_RXCTL &= ~SAA9730_RXCTL_ENRX;    // Set DMA and MAC reset bits    SAA9730_DMATST |= SAA9730_DMATST_RESET;    SAA9730_MACCTL |= SAA9730_MACCTL_RESET;    spd->active = 0;}static void__do_start(struct saa9730_priv_data *spd){    unsigned long __base = spd->base;    int i;    spd->active = 1;    spd->tx_busy = 0;    for (i = 0; i < SAA9730_BUFFERS; i++)	spd->tx_used[i] = 0;    // for tx, turn on MAC first    SAA9730_TXCTL |= SAA9730_TXCTL_ENTX;    SAA9730_DMACTL |= SAA9730_DMACTL_ENTX;    // for rx, turn on DMA first    SAA9730_DMACTL |= SAA9730_DMACTL_ENRX;    SAA9730_RXCTL |= SAA9730_RXCTL_ENRX;    __select_buffer(spd, spd->next_rx_bindex);    }//// This function is called to "start up" the interface.  It may be called// multiple times, even when the hardware is already running.  It will be// called whenever something "hardware oriented" changes and should leave// the hardware ready to send/receive packets.//static voidsaa9730_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;    if (spd->active)	saa9730_stop(sc);    __do_start(spd);}//// This routine is called to perform special "control" opertions//static intsaa9730_control(struct eth_drv_sc *sc, unsigned long key,               void *data, int data_length){    switch (key) {    case ETH_DRV_SET_MAC_ADDRESS:        return 0;        break;    default:        return 1;        break;    }}//// This routine is called to see if it is possible to send another packet.// It will return non-zero if a transmit is possible, zero otherwise.//static intsaa9730_can_send(struct eth_drv_sc *sc){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;    unsigned long __base = spd->base;    __tx_poll(sc);    if (spd->next_tx_bindex == 0  && (SAA9730_OK2USE & SAA9730_OK2USE_TXA))        return 0;    if (spd->next_tx_bindex == 1  && (SAA9730_OK2USE & SAA9730_OK2USE_TXB))        return 0;    return 1;}static int tx_poll_count;//// This routine is called to send data to the hardware.static void saa9730_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,             int total_len, unsigned long key){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;    unsigned long __base = spd->base;    int bindex, pindex;    cyg_uint32 pktlen = total_len;    cyg_uint8  *pktdata, *to_p;    volatile cyg_uint32 *pktstat ;    struct eth_drv_sg *last_sg;#ifdef DEBUG    db_printf("saa9730_send: %d sg's, %d bytes, KEY %x\n",              sg_len, total_len, key );#endif    if (!spd->active)	return;    bindex = spd->next_tx_bindex;    pindex = spd->next_tx_pindex;    spd->next_tx_pindex++;    if (spd->next_tx_pindex >= SAA9730_TXPKTS_PER_BUFFER) {        spd->next_tx_pindex = 0;        spd->next_tx_bindex ^= 1;    }    pktstat = spd->tx_buffer[bindex][pindex];	    if (bindex == 0 && (SAA9730_OK2USE & SAA9730_OK2USE_TXA))        return;    if (bindex == 1 && (SAA9730_OK2USE & SAA9730_OK2USE_TXB))        return;    spd->tx_key[bindex][pindex] = key;    spd->tx_used[bindex] += 1;    pktdata = (cyg_uint8 *)((unsigned)pktstat + 4);    // Copy from the sglist into the tx buffer    to_p = pktdata;    for (last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++) {	cyg_uint8 *from_p;	int l;            	from_p = (cyg_uint8 *)(sg_list->buf);	l = sg_list->len;	if (l > total_len)	    l = total_len;	memcpy((unsigned char *)to_p, from_p, l);	to_p += l;	total_len -= l;	if (total_len < 0) 	    break; // Should exit via sg_last normally    }    // pad to minimum size    if (pktlen < SAA9730_MIN_PACKET_SIZE) {        memset(to_p, 0, SAA9730_MIN_PACKET_SIZE-pktlen);        pktlen = SAA9730_MIN_PACKET_SIZE;    }    // Set transmit status WORD for hardware (LAN-DMA-ENGINE)    *pktstat = CYG_CPU_TO_LE32(TX_READY | pktlen);    // start hardware    if (bindex == 0)        SAA9730_OK2USE |= SAA9730_OK2USE_TXA;    else         SAA9730_OK2USE |= SAA9730_OK2USE_TXB;    if (!spd->tx_busy) {	tx_poll_count = 0;	spd->tx_busy = bindex + 1;    }}static void__check_rxstate(struct saa9730_priv_data *spd){    unsigned long __base = spd->base;    cyg_uint32  status, flag, size;    cyg_uint32  *pkt;    int         i, j;#ifdef DEBUG    db_printf("__check_rxstate\n");        #endif#ifdef CYGPKG_REDBOOT    // Clear SAA9730 LAN interrupt and re-enable interrupts.    SAA9730_EVM_ISR = SAA9730_EVM_LAN_INT;    SAA9730_EVM_IER_SW |= (SAA9730_EVM_LAN_INT|SAA9730_EVM_MASTER);#endif        if ((SAA9730_DBGRXS & SAA9730_DBGRXS_RXDII_MASK) == SAA9730_DBGRXS_RXDII_ERROR) {        // re-init driver and controller#ifdef DEBUG        db_printf("DBGRXS: reset\n");#endif	saa9730_reset(spd);	__do_start(spd);	return;    }    // Check RX packet status    for (i = 0; i < SAA9730_BUFFERS; i++) {        for (j = 1; j < SAA9730_RXPKTS_PER_BUFFER; j++) {            pkt = spd->rx_buffer[i][j];            status = CYG_LE32_TO_CPU(*pkt);            size   = status & RXPACKET_STATUS_SIZE_MASK;            flag   = status & RXPACKET_STATUS_FLAG_MASK;            if (flag == RX_INVALID_STAT || size > 1514 || *(pkt - 1)) {		// re-init driver and controller#ifdef DEBUG                db_printf("rxpkt: reset\n");#endif		saa9730_reset(spd);		__do_start(spd);		return;            }        }    }}static void__tx_poll(struct eth_drv_sc *sc){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;    int	                 bindex, pindex;    volatile cyg_uint32 *pktstat;    cyg_uint32 status;    if (!spd->tx_busy)	return;    bindex = spd->tx_busy - 1;    pindex = spd->tx_used[bindex] - 1;  // watch last pkt in buffer    pktstat = spd->tx_buffer[bindex][pindex];    status = CYG_LE32_TO_CPU(*pktstat);    if ((status & TXPACKET_STATUS_FLAG_MASK) != TX_HWDONE) {	hal_delay_us(1000);	if (++tx_poll_count > 1000) {	    // reset	    for (pindex = 0; pindex < spd->tx_used[bindex]; pindex++)		(sc->funs->eth_drv->tx_done)(sc, spd->tx_key[bindex][pindex], 1);	    bindex ^= 1;	    for (pindex = 0; pindex < spd->tx_used[bindex]; pindex++)		(sc->funs->eth_drv->tx_done)(sc, spd->tx_key[bindex][pindex], 1);	    saa9730_reset(spd);	    __do_start(spd);	}	return;    }    for (pindex = 0; pindex < spd->tx_used[bindex]; pindex++) {	/* Check for error. */	pktstat = spd->tx_buffer[bindex][pindex];	status = CYG_LE32_TO_CPU(*pktstat);	if (status & TXPACKET_STATUS_ERROR) {	    if (status & TXPACKET_STATUS_EXDEFER)		db_printf("tx deferred\n");	    if (status & TXPACKET_STATUS_LATECOLLERR)		db_printf("tx late collision\n");	    if (status & TXPACKET_STATUS_LOSTCARRIER)		db_printf("tx no carrier\n");	    if (status & TXPACKET_STATUS_UNDERRUN)		db_printf("tx underrun\n");	    if (status & TXPACKET_STATUS_SQERR)		db_printf("tx sq\n");	}	/* free the space */	*pktstat = CYG_CPU_TO_LE32(TX_EMPTY);	(sc->funs->eth_drv->tx_done)(sc, spd->tx_key[bindex][pindex], 1 /* status */);    }    tx_poll_count = 0;    spd->tx_used[bindex] = 0;        bindex ^= 1;    if (spd->tx_used[bindex])	spd->tx_busy = bindex + 1;    else	spd->tx_busy = 0;}static void__rx_poll(struct eth_drv_sc *sc){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;    int	                 bindex, pindex, done;    volatile cyg_uint32 *pkt;    cyg_uint32           status, pktlen; #ifdef DEBUG    db_printf("__rx_poll\n");#endif    if (!spd->active)	return;    done = 0;    while (!done) {        // index of next packet buffer        bindex = spd->next_rx_bindex;        // index of next packet within buffer        pindex = spd->next_rx_pindex;        pkt = spd->rx_buffer[bindex][pindex];	// stop now if no more packets        if (((status = CYG_LE32_TO_CPU(*pkt)) & RXPACKET_STATUS_FLAG_MASK) == RX_READY)            break;#ifdef DEBUG        db_printf("__rx_poll pkt %08x status %08x\n",pkt,status);#endif	// if this is the first packet in a buffer, switch the SAA9730 to	// use the next buffer for subsequent incoming packets.	if (pindex == 0)	    __select_buffer(spd, bindex == 0);            	// check for good packet	if (status & RXPACKET_STATUS_GOOD) {	    pktlen = status & RXPACKET_STATUS_SIZE_MASK ;	    if (pktlen > 0) {		(sc->funs->eth_drv->recv)(sc, pktlen);		// done = 1;	    }	}#ifdef DEBUG        else            db_printf("rx bad: %08x %08x\n",pkt,status);#endif        	/* go to next packet in sequence */	spd->next_rx_pindex++;	if (spd->next_rx_pindex >= SAA9730_RXPKTS_PER_BUFFER) {	    spd->next_rx_pindex = 0;	    spd->next_rx_bindex++;	    if (spd->next_rx_bindex >= SAA9730_BUFFERS) 		spd->next_rx_bindex = 0;	}    }    if (((poll_count++) % 100) == 0)        __check_rxstate(spd);}static voidsaa9730_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;    volatile cyg_uint32 *pkt;    cyg_uint32          pktlen, status;    struct eth_drv_sg   *last_sg;    if (!spd->active)	return;    pkt = spd->rx_buffer[spd->next_rx_bindex][spd->next_rx_pindex];    status = CYG_LE32_TO_CPU(*pkt);    if (status & RXPACKET_STATUS_GOOD) {	// packet is good	pktlen = status & RXPACKET_STATUS_SIZE_MASK;	if (pktlen > 0) {	    int total_len;	    cyg_uint8 *from_p;	    // check we have memory to copy into; we would be called even if	    // caller was out of memory in order to maintain our state.	    if (0 == sg_len || 0 == sg_list)		return; // caller was out of mbufs	    total_len = pktlen;	    from_p = (cyg_uint8 *)((unsigned)pkt + 4);	    for (last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++) {		cyg_uint8 *to_p;		int l;            		to_p = (cyg_uint8 *)(sg_list->buf);		l = sg_list->len;		if (0 >= l || 0 == to_p)		    return; // caller was out of mbufs		if (l > total_len)		    l = total_len;		memcpy(to_p, (unsigned char *)from_p, l);		from_p += l;		total_len -= l;	    }	}    }}static inline void__do_deliver(struct eth_drv_sc *sc){    // First pass any rx data up the stack    __rx_poll(sc);    // Then scan for completed Txen and inform the stack    __tx_poll(sc);}static voidsaa9730_poll(struct eth_drv_sc *sc){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;#ifndef CYGPKG_REDBOOT    cyg_drv_interrupt_mask(spd->vector);#endif    (void)saa9730_isr(spd->vector, (cyg_addrword_t)spd);    __do_deliver(sc);    cyg_drv_interrupt_acknowledge(spd->vector);#ifndef CYGPKG_REDBOOT    cyg_drv_interrupt_unmask(spd->vector);#endif    }// The deliver function (ex-DSR)  handles the ethernet [logical] processingstatic voidsaa9730_deliver(struct eth_drv_sc *sc){    struct saa9730_priv_data *spd = (struct saa9730_priv_data *)sc->driver_private;    unsigned long __base = spd->base;        if (spd->active)	__do_deliver(sc);    cyg_drv_interrupt_acknowledge(spd->vector);#ifndef CYGPKG_REDBOOT    // Clear SAA9730 LAN interrupt and re-enable interrupts.    SAA9730_EVM_IER_SW |= (SAA9730_EVM_LAN_INT|SAA9730_EVM_MASTER);    cyg_drv_interrupt_unmask(spd->vector);#endif    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?