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 + -
显示快捷键?