📄 dm90x0.c
字号:
* Description: * An interrupt was received indicating the availability of a new RX packet * * Parameters: * dm9x - Reference to the driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void dm9x_receive(struct dm9x_driver_s *dm9x){ union rx_desc_u rx; boolean bchecksumready; uint8 mdrah; uint8 mdral; uint8 rxbyte; nvdbg("Packet received\n"); do { /* Store the value of memory data read address register */ mdrah = getreg(DM9X_MDRAH); mdral = getreg(DM9X_MDRAL); getreg(DM9X_MRCMDX); /* Dummy read */ rxbyte = (uint8)DM9X_DATA; /* Get the most up-to-date data */ /* Packet ready for receive check */ bchecksumready = dm9x_rxchecksumready(rxbyte); if (!bchecksumready) { break; } /* A packet is ready now. Get status/length */ DM9X_INDEX = DM9X_MRCMD; /* set read ptr ++ */ /* Read packet status & length */ dm9x->dm_read((uint8*)&rx, 4); /* Check if any errors were reported by the hardware */ if (rx.desc.rx_status & 0xbf) { /* Bad RX packet... update statistics */#if defined(CONFIG_DM9X_STATS) if (rx.desc.rx_status & 0x01) { dm9x->dm_nrxfifoerrors++; ndbg("RX FIFO error: %d\n", dm9x->dm_nrxfifoerrors); } if (rx.desc.rx_status & 0x02) { dm9x->dm_nrxcrcerrors++; ndbg("RX CRC error: %d\n", dm9x->dm_nrxcrcerrors); } if (rx.desc.rx_status & 0x80) { dm9x->dm_nrxlengtherrors++; ndbg("RX length error: %d\n", dm9x->dm_nrxlengtherrors); } if (rx.desc.rx_status & 0x08) { dm9x->dm_nphyserrors++; ndbg("Physical Layer error: %d\n", dm9x->dm_nphyserrors); }#else ndbg("Received packet with errors: %02x\n", rx.desc.rx_status);#endif /* Drop this packet and continue to check the next packet */ dm9x->dm_discard(rx.desc.rx_len); } /* Also check if the packet is a valid size for the uIP configuration */ else if (rx.desc.rx_len < UIP_LLH_LEN || rx.desc.rx_len > (CONFIG_NET_BUFSIZE + 2)) {#if defined(CONFIG_DM9X_STATS) dm9x->dm_nrxlengtherrors++; ndbg("RX length error: %d\n", dm9x->dm_nrxlengtherrors);#endif /* Drop this packet and continue to check the next packet */ dm9x->dm_discard(rx.desc.rx_len); } else { /* Good packet... Copy the packet data out of SRAM and pass it one to uIP */ dm9x->dm_dev.d_len = rx.desc.rx_len; dm9x->dm_read(dm9x->dm_dev.d_buf, rx.desc.rx_len); /* We only accept IP packets of the configured type and ARP packets */#ifdef CONFIG_NET_IPv6 if (BUF->type == HTONS(UIP_ETHTYPE_IP6))#else if (BUF->type == HTONS(UIP_ETHTYPE_IP))#endif { uip_arp_ipin(); uip_input(&dm9x->dm_dev); /* If the above function invocation resulted in data that should be * sent out on the network, the field d_len will set to a value > 0. */ if (dm9x->dm_dev.d_len > 0) { uip_arp_out(&dm9x->dm_dev); dm9x_transmit(dm9x); } } else if (BUF->type == htons(UIP_ETHTYPE_ARP)) { uip_arp_arpin(&dm9x->dm_dev); /* If the above function invocation resulted in data that should be * sent out on the network, the field d_len will set to a value > 0. */ if (dm9x->dm_dev.d_len > 0) { dm9x_transmit(dm9x); } } }#if defined(CONFIG_DM9X_STATS) dm9x->dm_nrxpackets++; dm9x->dm_nrxbytes += rx.desc.rx_len;#endif dm9x->ncrxpackets++; } while ((rxbyte & 0x01) == DM9X_PKTRDY && dm9x->ncrxpackets < DM9X_CRXTHRES); nvdbg("All RX packets processed\n");}/**************************************************************************** * Function: dm9x_txdone * * Description: * An interrupt was received indicating that the last TX packet(s) is done * * Parameters: * dm9x - Reference to the driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void dm9x_txdone(struct dm9x_driver_s *dm9x){ int nsr; nvdbg("TX done\n"); /* Another packet has completed transmission. Decrement the count of * of pending TX transmissions. */ nsr = getreg(DM9X_NETS); if (nsr & DM9X_NETS_TX1END) { if (dm9x->dm_ntxpending) { dm9x->dm_ntxpending--; } else { ndbg("Bad TX count (TX1END)\n"); } } if (nsr & DM9X_NETS_TX2END) { if (dm9x->dm_ntxpending) { dm9x->dm_ntxpending--; } else { ndbg("Bad TX count (TX2END)\n"); } } /* Cancel the TX timeout */ if (dm9x->dm_ntxpending == 0) { wd_cancel(dm9x->dm_txtimeout); } /* Then poll uIP for new XMIT data */ (void)uip_poll(&dm9x->dm_dev, dm9x_uiptxpoll);}/**************************************************************************** * Function: dm9x_interrupt * * Description: * DM90x0 interrupt handler * * Parameters: * irq - Number of the IRQ that generated the interrupt * context - Interrupt register state save info (architecture-specific) * * Returned Value: * OK on success * * Assumptions: * ****************************************************************************/static int dm9x_interrupt(int irq, FAR void *context){#if CONFIG_DM9X_NINTERFACES == 1 register struct dm9x_driver_s *dm9x = &g_dm9x[0];#else# error "Additional logic needed to support multiple interfaces"#endif uint8 isr; uint8 save; int i; /* Save previous register address */ save = (uint8)DM9X_INDEX; /* Disable all DM90x0 interrupts */ putreg(DM9X_IMR, DM9X_IMRDISABLE); /* Get and clear the DM90x0 interrupt status bits */ isr = getreg(DM9X_ISR); putreg(DM9X_ISR, isr); nvdbg("Interrupt status: %02x\n", isr); /* Check for link status change */ if (isr & DM9X_INT_LNKCHG) { /* Wait up to 0.5s for link OK */ for (i = 0; i < 500; i++) { dm9x_phyread(dm9x,0x1); if (dm9x_phyread(dm9x,0x1) & 0x4) /*Link OK*/ { /* Wait to get detected speed */ for (i = 0; i < 200; i++) { up_mdelay(1); } /* Set the new network speed */ if (dm9x_phyread(dm9x, 0) & 0x2000) { dm9x->dm_b100M = TRUE; } else { dm9x->dm_b100M = FALSE; } break; } up_mdelay(1); } ndbg("delay: %dmS speed: %s\n", i, dm9x->dm_b100M ? "100M" : "10M"); } /* Check if we received an incoming packet */ if (isr & DM9X_INT_PR) { dm9x_receive(dm9x); } /* Check if we are able to transmit a packet */ if (isr & DM9X_INT_PT) { dm9x_txdone(dm9x); } /* If the number of consecutive receive packets exceeds a threshold, * then disable the RX interrupt. */ if (dm9x->ncrxpackets >= DM9X_CRXTHRES) { /* Eanble all DM90x0 interrupts EXCEPT for RX */ putreg(DM9X_IMR, DM9X_IMRRXDISABLE); } else { /* Enable all DM90x0 interrupts */ putreg(DM9X_IMR, DM9X_IMRENABLE); } /* Restore previous register address */ DM9X_INDEX = save; return OK;}/**************************************************************************** * Function: dm9x_txtimeout * * Description: * Our TX watchdog timed out. Called from the timer interrupt handler. * The last TX never completed. Reset the DM90x0 and start again. * * Parameters: * argc - The number of available arguments * arg - The first argument * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void dm9x_txtimeout(int argc, uint32 arg, ...){ struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)arg; ndbg("TX timeout\n"); /* Increment statistics and dump debug info */#if defined(CONFIG_DM9X_STATS) dm9x->dm_ntxtimeouts++; dm9x->dm_ntxerrors++;#endif ndbg(" TX packet count: %d\n", dm9x->dm_ntxpending); #if defined(CONFIG_DM9X_STATS) ndbg(" TX timeouts: %d\n", dm9x->dm_ntxtimeouts); #endif ndbg(" TX read pointer address: 0x%02x:%02x\n", getreg(DM9X_TRPAH), getreg(DM9X_TRPAL)); ndbg(" Memory data write address: 0x%02x:%02x (DM9010)\n", getreg(DM9X_MDWAH), getreg(DM9X_MDWAL)); /* Then reset the DM90x0 */ dm9x_reset(dm9x); /* Then poll uIP for new XMIT data */ (void)uip_poll(&dm9x->dm_dev, dm9x_uiptxpoll);}/**************************************************************************** * Function: dm9x_polltimer * * Description: * Periodic timer handler. Called from the timer interrupt handler. * * Parameters: * argc - The number of available arguments * arg - The first argument * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void dm9x_polltimer(int argc, uint32 arg, ...){ struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)arg; /* If the number of contiguous RX packets exceeds a threshold, reset the counter and * re-enable RX interrupts */ if (dm9x->ncrxpackets >= DM9X_CRXTHRES) { dm9x->ncrxpackets = 0; putreg(DM9X_IMR, DM9X_IMRENABLE); } /* Check if there is room in the DM90x0 to hold another packet. In 100M mode, * that can be 2 packets, otherwise it is a single packet. */ if (dm9x->dm_ntxpending < 1 || (dm9x->dm_b100M && dm9x->dm_ntxpending < 2)) { /* If so, update TCP timing states and poll uIP for new XMIT data */ (void)uip_timer(&dm9x->dm_dev, dm9x_uiptxpoll, DM6X_POLLHSEC); } /* Setup the watchdog poll timer again */ (void)wd_start(dm9x->dm_txpoll, DM6X_WDDELAY, dm9x_polltimer, 1, arg);}/**************************************************************************** * Function: dm9x_phymode * * Description: * Configure the PHY operating mode * * Parameters: * dm9x - Reference to the driver state structure * * Returned Value: * None *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -