/*! * \brief Reset the Ethernet controller. * * \return 0 on success, -1 otherwise. */ int NicReset(void) { /* Disable all interrupts. */ nic_outlb(NIC_MSK, 0); /* MAC and PHY software reset. */ nic_bs(0); nic_outw(NIC_RCR, RCR_SOFT_RST); /* Enable Ethernet protocol handler. */ nic_bs(1); nic_outw(NIC_CR, CR_EPH_EN); Delay(1); /* Disable transmit and receive. */ nic_bs(0); nic_outw(NIC_RCR, 0); nic_outw(NIC_TCR, 0); /* Enable auto release. */ nic_bs(1); nic_outw(NIC_CTR, CTR_AUTO_RELEASE); /* Reset MMU. */ nic_bs(2); nic_outlb(NIC_MMUCR, MMU_RST); if (NicMmuWait(1000)) return -1; return 0; }
/*! * \brief Reset the Ethernet controller. * * \return 0 on success, -1 otherwise. */ static int NicReset(phantom_device_t * dev) { #ifdef LANC111_RESET_BIT sbi(LANC111_RESET_DDR, LANC111_RESET_BIT); sbi(LANC111_RESET_PORT, LANC111_RESET_BIT); NutDelay(WAIT100); cbi(LANC111_RESET_PORT, LANC111_RESET_BIT); NutDelay(WAIT250); NutDelay(WAIT250); #endif /* Disable all interrupts. */ nic_outlb(NIC_MSK, 0); /* MAC and PHY software reset. */ nic_bs(0); nic_outw(NIC_RCR, RCR_SOFT_RST); /* Enable Ethernet protocol handler. */ nic_bs(1); nic_outw(NIC_CR, CR_EPH_EN); NutDelay(10); /* Disable transmit and receive. */ nic_bs(0); nic_outw(NIC_RCR, 0); nic_outw(NIC_TCR, 0); /* Enable auto release. */ nic_bs(1); nic_outw(NIC_CTR, CTR_AUTO_RELEASE); /* Reset MMU. */ nic_bs(2); nic_outlb(NIC_MMUCR, MMU_RST); if (NicMmuWait(dev,1000)) return -1; return 0; }
/*! * \brief Load a packet into the nic's transmit ring buffer. * * Interupts must have been disabled when calling this function. * * \param nb Network buffer structure containing the packet to be sent. * The structure must have been allocated by a previous * call NutNetBufAlloc(). This routine will automatically * release the buffer in case of an error. * * \return 0 on success, -1 in case of any errors. Errors * will automatically release the network buffer * structure. */ static int NicPutPacket(NETBUF * nb) { u_int16_t sz; uint8_t odd = 0; uint8_t imsk; //printf("[P]"); /* * Calculate the number of bytes to be send. Do not send packets * larger than the Ethernet maximum transfer unit. The MTU * consist of 1500 data bytes plus the 14 byte Ethernet header * plus 4 bytes CRC. We check the data bytes only. */ if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETH_DATA_LEN) return -1; /* Disable all interrupts. */ imsk = nic_inlb(NIC_MSK); nic_outlb(NIC_MSK, 0); /* Allocate packet buffer space. */ nic_bs(2); nic_outlb(NIC_MMUCR, MMU_ALO); if (NicMmuWait(100)) return -1; /* Enable interrupts including allocation success. */ nic_outlb(NIC_MSK, imsk | INT_ALLOC); /* The MMU needs some time. Use it to calculate the byte count. */ sz += nb->nb_dl.sz; sz += 6; if (sz & 1) { sz++; odd++; } /* Wait for allocation success. */ while ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) { if (NutEventWait(&maq, 125)) { nic_outlb(NIC_MMUCR, MMU_RST); NicMmuWait(1000); nic_outlb(NIC_MMUCR, MMU_ALO); if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) { if (NutEventWait(&maq, 125)) { return -1; } } } } /* Disable interrupts. */ imsk = nic_inlb(NIC_MSK); nic_outlb(NIC_MSK, 0); nic_outlb(NIC_PNR, nic_inhb(NIC_PNR)); nic_outw(NIC_PTR, 0x4000); /* Transfer control word. */ nic_outlb(NIC_DATA, 0); nic_outlb(NIC_DATA, 0); /* Transfer the byte count. */ nic_outw(NIC_DATA, sz); /* Transfer the Ethernet frame. */ NicWrite(nb->nb_dl.vp, nb->nb_dl.sz); NicWrite(nb->nb_nw.vp, nb->nb_nw.sz); NicWrite(nb->nb_tp.vp, nb->nb_tp.sz); NicWrite(nb->nb_ap.vp, nb->nb_ap.sz); if (odd) nic_outlb(NIC_DATA, 0); /* Transfer the control word. */ nic_outw(NIC_DATA, 0); /* Enqueue packet. */ if (NicMmuWait(100)) return -1; nic_outlb(NIC_MMUCR, MMU_ENQ); /* Enable interrupts. */ imsk |= INT_TX | INT_TX_EMPTY; nic_outlb(NIC_MSK, imsk); return 0; }
/*! * \brief Send an Ethernet frame. * * \param dmac Destination MAC address. * \param type Frame type. * \param len Frame size. * * \return 0 on success, -1 otherwise. */ int EtherOutput(const u_char * dmac, u_short type, u_short len) { ETHERHDR *eh; u_char *cp; /* * Set the Ethernet header. */ if (type == ETHERTYPE_ARP) { cp = (u_char *) & arpframe; } else { cp = (u_char *) & sframe; } eh = (ETHERHDR *)cp; memcpy_(eh->ether_shost, confnet.cdn_mac, 6); memcpy_(eh->ether_dhost, dmac, 6); eh->ether_type = type; /* * The total packet length includes * - status word (2 bytes) * - byte count (2 bytes) * - destination address (6 bytes) * - source address (6 bytes) * - Ethernet type (2 bytes) * - data bytes (variable) * - control word (2 bytes) * Thus we add 20 to the number of data bytes. We didn't * manage to get an odd number of bytes transmitted, so * add another byte. */ if((len += 20) & 1) { len++; } DEBUG(" Tx("); DEBUGUSHORT(len); DEBUG(")"); /* Allocate transmit packet buffer space. */ nic_bs(2); nic_outlb(NIC_MMUCR, MMU_ALO); if (NicMmuWait(100)) { return -1; } /* * An allocation error might appear when incoming packets occupy * all the buffer. Reset the MMU to release all memory. This is * very drastic, but OK for our sequential boot loader. */ if ((nic_inlb(NIC_IST) & INT_ALLOC) == 0) { DEBUG("[MMURST]"); nic_outlb(NIC_MMUCR, MMU_RST); NicMmuWait(1000); nic_outlb(NIC_MMUCR, MMU_ALO); if (NicMmuWait(100) || (nic_inlb(NIC_IST) & INT_ALLOC) == 0) { return -1; } } /* * Read the number of the allcocated packet from the allocation * result register and write it to the packet number register. */ nic_outlb(NIC_PNR, nic_inhb(NIC_PNR)); /* * Initially set the pointer register address to 2 and enable * auto increment. The first two bytes will be used by the CSMA * to store the status word upon transmit completion. */ nic_outw(NIC_PTR, PTR_AUTO_INCR | 2); /* * Transfer the byte count and the data bytes. */ nic_outw(NIC_DATA, len); while (len--) { nic_outlb(NIC_DATA, *cp); cp++; } /* * Transfer the control word. As stated above, we never succeeded * in sending an odd number of bytes. */ nic_outw(NIC_DATA, 0); /* Enqueue packet. */ NicMmuWait(100); nic_outlb(NIC_MMUCR, MMU_ENQ); return 0; }