📄 cs8900if.c
字号:
* Reset the CS8900A chip-wide using a soft reset * * @note You MUST wait 30 ms before accessing the CS8900 * after calling this function. */ IO1SET = SEL1; IO1CLR = SEL1; IO1SET = SEL1; IO1CLR = SEL1; cs8900a_write(ADD_PORT, PP_SelfCTL); cs8900a_write(DATA_PORT, POWER_ON_RESET); IO1SET = SEL1; IO1CLR = SEL1; IO1SET = SEL1; IO1CLR = SEL1; // Wait until chip-reset is done cs8900a_write(ADD_PORT, PP_SelfST); // INITD bit still clear? while ((cs8900a_read(DATA_PORT) & INIT_DONE) == 0) ; IO1SET = SEL1; IO1CLR = SEL1; IO1SET = SEL1; IO1CLR = SEL1; /* //空读写使cs8900a进入16位模式 dummy = *(u8_t *)(MEM_BASE + IO_BASE + 0x0D) ; // Dummy read, put chip in 16bit-mode dummy = *(u16_t *)(MEM_BASE + IO_BASE + 0x0D) ; */ IO1SET = SEL1; IO1CLR = SEL1; IO1SET = SEL1; IO1CLR = SEL1; cs8900a_write(ADD_PORT,0x0102); // Configure the CS8900A for (i = 0; i < sizeof(InitSeq) / sizeof (TInitSeq); ++i) { cs8900a_write(ADD_PORT, InitSeq[i].addr); cs8900a_write(DATA_PORT, InitSeq[i].data); } /* Hack - pass the netif structure to the recieve thread through a global variable. */ //用一个全局变量传递给接收线程一个网络接口 cs8900if_netif = netif;}/*-----------------------------------------------------------------------------------*//* * cs8900a_output(): * @return error code * - ERR_OK: packet transferred to hardware * - ERR_CONN: no link or link failure * - ERR_IF: could not transfer to link (hardware buffer full?) * * * Should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * * 我想在数据接收和发送的过程中应该用信号量来保证数据的完整性。 *//*-----------------------------------------------------------------------------------*/static err_tcs8900a_output(struct netif *netif, struct pbuf *p){ struct pbuf *q; struct cs8900if *cs8900if; int tries = 0; err_t result; cs8900if = netif->state; // exit if link has failed cs8900a_write(ADD_PORT,PP_LineST); if ((cs8900a_read(DATA_PORT) & 0x0080U/*LinkOK*/) == 0) return ERR_CONN; // no Ethernet link result = ERR_OK; // issue 'transmit' command to CS8900 cs8900a_write(TX_CMD_PORT, TX_START_ALL_BYTES); /* send length (in bytes) of packet to send, but at least minimum frame length */ cs8900a_write(TX_LEN_PORT, (p->tot_len < ETH_MIN_FRAME_LEN? ETH_MIN_FRAME_LEN: p->tot_len)); cs8900a_write(ADD_PORT,PP_BusST); // not ready for transmission and still within 100 retries? //如果当前不能发送,尝试100次 while (((cs8900a_read(DATA_PORT) & 0x0100U/*Rdy4TxNOW*/) == 0) && (tries++ < 10)) { // throw away the last committed received frame cs8900a_write(ADD_PORT,PP_RxCFG); cs8900a_write(DATA_PORT,0x0003U | 0x0040U/*Skip_1*/ | 0x0100U/*RxOKiE*/); cs8900a_write(ADD_PORT,PP_BusST); } //drop the padding word #if ETH_PAD_SIZE pbuf_header(p,-ETH_PAD_SIZE); #endif // ready to transmit?如果准备好则发送数据 if ((cs8900a_read(DATA_PORT) & 0x0100U/*Rdy4TxNOW*/) != 0) { unsigned long sent_bytes = 0; /* q traverses through linked list of pbuf's * This list MUST consist of a single packet ONLY */ for (q = p; q != NULL; q = q->next) { u16_t i; u16_t *ptr = (u16_t *)q->payload; /* Send the data from the pbuf to the interface, one pbuf at a * time. The size of the data in each pbuf is kept in the ->len * variable. 可能有多个缓冲区中的数据要发送,我们争取全部把它们发送出去 */ for (i = 0; i < q->len; i += 2) { /** TODO: this routine assumes 16-bit boundary pbufs... */ cs8900a_write(TX_FRAME_PORT,*ptr++); sent_bytes += 2; } } /* provide any additional padding to comply with minimum Ethernet * frame length (RFC10242)如果数据过短就补充0,达到以太网最小的数据包 */ while (sent_bytes < ETH_MIN_FRAME_LEN) { cs8900a_write(TX_FRAME_PORT,0x0000); sent_bytes += 2; } } else { // { not ready to transmit!? } /* return not connected */ result = ERR_IF; } //reclaim the padding word #if ETH_PAD_SIZE pbuf_header(p,-ETH_PAD_SIZE); #endif #if LINK_STATS lwip_stats.link.xmit++; #endif /* LINK_STATS */ return result;}/*-----------------------------------------------------------------------------------*//* * cs8900a_input(): * * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * * Move a received packet from the cs8900 into a new pbuf. * * Must be called after reading an ISQ event containing the * "Receiver Event" register, before reading new ISQ events. * * This function copies a frame from the CS8900A. * It is designed failsafe: * - It does not assume a frame is actually present. * - It checks for non-zero length * - It does not overflow the frame buffer *//*-----------------------------------------------------------------------------------*/static struct pbuf *cs8900a_input(struct netif *netif){ struct cs8900if *cs8900if; struct pbuf *p = NULL, *q = NULL; u16_t len = 0; u16_t event_type; u16_t i; u16_t *ptr = NULL; cs8900if = netif->state; // read RxStatus event_type = cs8900a_read(RX_FRAME_PORT); // correctly received frame, either broadcast or individual address? // TODO: maybe defer these conditions to cs8900_input() if ((event_type & 0x0100U/*RxOK*/) && (event_type & 0x0c00U/*Broadcast | Individual*/)) { event_type = 0; // read RxLength len = cs8900a_read(RX_FRAME_PORT); LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_input: packet len %u\n", len)); // positive length? if (len > 0) { // allocate a pbuf chain with total length 'len' p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif for (q = p; q != 0; q = q->next) { LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_input: pbuf @%p tot_len %u len %u\n", q, q->tot_len, q->len)); ptr = q->payload; // TODO: CHECK: what if q->len is odd? we don't use the last byte? for (i = 0; i < (q->len + 1) / 2; i++) { *ptr = cs8900a_read(RX_FRAME_PORT); ptr++; } } #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif } // could not allocate a pbuf else { // skip received frame // TODO: maybe do not skip the frame at this point in time? cs8900a_skip_frame(); len = 0; #if LINK_STATS lwip_stats.link.memerr++; lwip_stats.link.drop++; #endif /* LINK_STATS */ } } // length was zero else { } } return p;}/** * cs8900if_input(): * * Read a received packet from the CS8900. * * This function should be called when a packet is received by the CS8900 * and is fully available to read. It moves the received packet to a pbuf * which is forwarded to the IP network layer or ARP module. It transmits * a resulting ARP reply or queued packet. * * @param netif The lwIP network interface to read from. * * @internal Uses cs8900_input() to move the packet from the CS8900 to a * newly allocated pbuf. * * * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. * *//*-----------------------------------------------------------------------------------*/void cs8900if_input(struct netif *netif){ struct cs8900if *cs8900if; struct eth_hdr *ethhdr; struct pbuf *p; cs8900if = netif->state;/* move received packet into a new pbuf */ p = cs8900a_input(netif); /* no packet could be read */ if (p == NULL) { /* silently ignore this */ return; } /* points to packet payload, which starts with an Ethernet header */ ethhdr = p->payload;#if LINK_STATS lwip_stats.link.recv++;#endif /* LINK_STATS */ switch (htons(ethhdr->type)) { /* IP packet? */ case ETHTYPE_IP: /* update ARP table */ etharp_ip_input(netif, p); /* skip Ethernet header */ pbuf_header(p, -sizeof(struct eth_hdr)); /* pass to network layer */ netif->input(p, netif); break; case ETHTYPE_ARP: /* pass p to ARP module */ etharp_arp_input(netif, cs8900if->ethaddr, p); break; default: pbuf_free(p); p = NULL; break; }}/** * cs8900if_output(): * * Writing an IP packet (to be transmitted) to the CS8900. * * Before writing a frame to the CS8900, the ARP module is asked to resolve the * Ethernet MAC address. The ARP module might undertake actions to resolve the * address first, and queue this packet for later transmission. * * @param netif The lwIP network interface data structure belonging to this device. * @param p pbuf to be transmitted (or the first pbuf of a chained list of pbufs). * @param ipaddr destination IP address. * * @return ERR_OK if the packet was sent or queued. There is no way to * find out if a packet really makes it onto the network link. * * @internal It uses the function cs8900_input() that should handle the actual * reception of bytes from the network interface. * * This function is called by the TCP/IP stack when an IP packet * should be sent. It calls the function called low_level_output() to * do the actual transmission of the packet. * */err_tcs8900if_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr){ /* resolve hardware address, then send (or queue) packet */ return etharp_output(netif, ipaddr, p); }/** * arp_timer. */static void arp_timer(void *arg){ etharp_tmr(); sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL);} void cs8900a_send_test(void);/** * cs8900if_init(): * Initialize the CS8900 Ethernet MAC/PHY and its device driver. * * @param netif The lwIP network interface data structure belonging to this device. * MAY be NULL as we do not support multiple devices yet. * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * */ err_tcs8900if_init(struct netif *netif){ struct cs8900if *cs8900if; //协议栈有自己的内存管理机制 cs8900if = mem_malloc(sizeof(struct cs8900if)); if (cs8900if == NULL) { LWIP_DEBUGF(NETIF_DEBUG, ("cs8900if_init: out of memory\n")); return ERR_MEM; } // initialize cs8900 specific interface state data pointer netif->state = cs8900if; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = cs8900if_output; netif->linkoutput = cs8900a_output; cs8900if->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); // intialize the cs8900a chip cs8900a_init(netif); etharp_init(); sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); //cs8900a_send_test(); return ERR_OK;}/*-----------------------------------------------------------------------------------*//** * TODO:写出不依赖于上层程序的驱动测试程序。先实现 * */ /* static const u8_t arpdata[60] = { 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x08,0x06,0x00,0x01, 0x08,0x00,0x06,0x04,0x00,0x01,0x00,0x01,0x02,0x03,0x04,0x05,0xd2,0x1d,0x68,0x08, 0x00,0x00,0x00,0x00,0x00,0x00,0xd2,0x1d,0x68,0x1e,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; void cs8900a_send_test(void) { u16_t u; // Transmit command cs8900a_write(TX_CMD_PORT, TX_START_ALL_BYTES); cs8900a_write(TX_LEN_PORT, 60); // Maximum number of retries u = 8; for (;;) { // Check for avaliable buffer space cs8900a_write(ADD_PORT, PP_BusST); if (cs8900a_read(DATA_PORT) & READY_FOR_TX_NOW) break; if (u -- == 0) return; // No space avaliable, skip a received frame and try again cs8900a_skip_frame(); } // Send uip_len bytes of header for (u = 0; u < 60; u += 2) { cs8900a_write(TX_FRAME_PORT,*(u16_t *)&arpdata[u]); } }*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -