📄 cs8900if.c
字号:
// cs8900a whether it needs service.////// As such, may be used robustly called as a deferred// (or "late") interrupt handler, or may be called in// a loop to implement polling, or both.//// Use cs8900if_service() from your application instead// of this function.static void cs8900_service(struct netif *netif){ // amount of ISQ's to handle (> 0) in one cs8900_service() call unsigned char events2service = 1; // NOTES: // static, so only initialized to zero at program start. // irq_status will always hold the last ISQ event register that // still needs service. As such, we may leave this function if // we encounter an event we cannot service yet, and return later // to try to service it. static u16_t irq_status = 0x0000U; // The "cs8900_needs_service" flag indicates whether any events // still need to be serviced. // clear flag here. // a receive interrupt can, *concurrently with this function*, // set this flag on new ISQ event occurences. // we will re-evaluate the correct setting of this flag at // function exit (below). ((struct cs8900if *)netif->state)->needs_service = 0; // no unhandled irq_status left? if (irq_status == 0x0000U) { // read ISQ register irq_status = ISQ; } // ISQ interrupt event, and allowed to service in this loop? while ((irq_status != 0x0000U) && (events2service-- > 0)) { // investigate event if ((irq_status & 0x003fU) == 0x0004U/*Receiver Event*/) { // correctly received frame, either broadcast or individual address // TODO: think where these checks should appear: here or in cs8900_input() if ((irq_status & 0x0100U/*RxOK*/) && (irq_status & 0x0c00U/*Broadcast | Individual*/)) { // read the frame from the cs8900a cs8900if_input(netif); } else { // skip this frame PACKETPP = CS_PP_RXCFG; PPDATA |= 0x0040U/*Skip_1*/;#if (CS8900_STATS > 0) ((struct cs8900if *)netif->state)->dropped++;#endif } }#if (CS8900_STATS > 0) else if ((irq_status & 0x003fU) == 0x0010U/*RxMISS Event*/) { ((struct cs8900if *)netif->state)->missed += (irq_status >> 6); } else if ((irq_status & 0x003fU) == 0x0012U/*TxCOL Event*/) { ((struct cs8900if *)netif->state)->collisions += (irq_status >> 6); }#endif // read ISQ register irq_status = ISQ; } // we did not deplete the ISQ? if (irq_status != 0x0000U) { // the cs8900a still needs service ((struct cs8900if *)netif->state)->needs_service = 1; }#if (CS8900_STATS > 1) // read RxMiss Counter (zeroes itself upon read) PACKETPP = CS_PP_RXMISS; ((struct cs8900if *)netif->state)->missed += (PPDATA >> 6); // read RxCol Counter (zeroes itself upon read) PACKETPP = CS_PP_TXCOL; ((struct cs8900if *)netif->state)->collisions += (PPDATA >> 6);#endif}void cs8900if_service(struct netif *netif){ // is there a reason to call the service routine? if ((((struct cs8900if *)netif->state)->needs_service) || (((struct cs8900if *)netif->state)->use_polling)) { cs8900_service(netif); }}/*-----------------------------------------------------------------------------------*//* * cs8900if_output(): * * This function is called by the TCP/IP stack when an IP packet * should be sent. After ARP address lookup, it calls cs8900_output() to * do the actual transmission of the packet. * *//*-----------------------------------------------------------------------------------*/static err_tcs8900if_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr){ struct cs8900if *cs8900if = netif->state; struct pbuf *q = NULL; struct eth_hdr *ethhdr; struct eth_addr *dest, mcastaddr; struct ip_addr *queryaddr; struct pbuf *r; err_t err; u8_t i; /* Make room for Ethernet header. */ if(pbuf_header(p, 14) != 0) { /* The pbuf_header() call shouldn't fail, but we allocate an extra pbuf just in case. */ q = pbuf_alloc(PBUF_LINK, 14, PBUF_RAM); if(q == NULL) { return ERR_MEM; } pbuf_chain(q, p); p = q; } /* Construct Ethernet header. Start with looking up deciding which MAC address to use as a destination address. Broadcasts and multicasts are special, all other addresses are looked up in the ARP table. */ queryaddr = ipaddr; if(ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, &(netif->netmask))) { dest = (struct eth_addr *)ðbroadcast; } else if(ip_addr_ismulticast(ipaddr)) { /* Handle multicast MAC address hashing. */ mcastaddr.addr[0] = 0x01; mcastaddr.addr[1] = 0x00; mcastaddr.addr[2] = 0x5e; mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; mcastaddr.addr[4] = ip4_addr3(ipaddr); mcastaddr.addr[5] = ip4_addr4(ipaddr); dest = &mcastaddr; } else { if(ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { /* Use destination IP address if the destination is on the same subnet as we are. */ queryaddr = ipaddr; } else { /* Otherwise we use the default router as the address to send the Ethernet frame to. */ queryaddr = &(netif->gw); } dest = arp_lookup(queryaddr); } /* If the arp_lookup() didn't find an address, we send out an ARP query for the IP address. */ if(dest == NULL) { /* Put_String("Call:"); mprintf((float)stats.mem.used,6,0); Put_String(" \n");*/ r = arp_query(netif, ((struct cs8900if *)netif->state)->ethaddr, queryaddr);/* Put_String("Arp_querry:"); mprintf((float)stats.mem.used,6,0); Put_String(" \n");*/ if(r != NULL) { err = cs8900_output(netif, r);#if defined(CS8900_TX_QUEUE) && (CS8900_TX_QUEUE > 0) // a rather stupid attempt to queue packets during ARP resolution // arp request sent? if (err == ERR_OK) { // enqueue packet if (((struct cs8900if *)netif->state)->tx_queue == NULL) ((struct cs8900if *)netif->state)->tx_queue = p; return ERR_OK; }#else pbuf_free(r); return err;#endif } return ERR_MEM; } ethhdr = p->payload; for(i = 0; i < 6; i++) { ethhdr->dest.addr[i] = dest->addr[i]; ethhdr->src.addr[i] = ((struct cs8900if *)netif->state)->ethaddr->addr[i]; } ethhdr->type = htons(ETHTYPE_IP); err = cs8900_output(netif, p); // we allocated the ethernet header ourselves // dechain it from the original pbuf // then free it if (q != NULL) { pbuf_dechain(q); pbuf_free(q); }/* Put_String("After:"); mprintf((float)stats.mem.used,6,0); Put_String(" \n");*/ return err;}/*-----------------------------------------------------------------------------------*//* * cs8900if_input(): * * This function should be called when a packet is ready to be read * from the interface. It uses the function cs8900_input() that * should handle the actual reception of bytes from the network * interface. * *//*-----------------------------------------------------------------------------------*/static voidcs8900if_input(struct netif *netif){ struct cs8900if *cs8900if = netif->state; struct eth_hdr *ethhdr; struct pbuf *p; p = cs8900_input(netif); if(p == NULL) { return; } ethhdr = p->payload; switch(htons(ethhdr->type)) { case ETHTYPE_IP:/* Put_String("cs8900if_input: ip-pack "); pbuf_free(p); */ arp_ip_input(netif, p); pbuf_header(p, -14); netif->input(p, netif); break; case ETHTYPE_ARP: p = arp_arp_input(netif, ((struct cs8900if *)netif->state)->ethaddr, p); if(p != NULL) { cs8900_output(netif, p); pbuf_free(p); }#if defined(CS8900_TX_QUEUE) && (CS8900_TX_QUEUE > 0) // this could have been an ARP reply // possible resolving a queued packet destination address else { if (((struct cs8900if *)netif->state)->tx_queue) { struct eth_addr *dest; struct ip_hdr *iphdr; // point to IP header pbuf_header(((struct cs8900if *)netif->state)->tx_queue, -14); iphdr = ((struct cs8900if *)netif->state)->tx_queue->payload; // point to link header pbuf_header(((struct cs8900if *)netif->state)->tx_queue, 14); // address can now be resolved? if ((dest = arp_lookup(&(iphdr->dest)))) { char i; ethhdr = ((struct cs8900if *)netif->state)->tx_queue->payload; for(i = 0; i < 6; i++) { ethhdr->dest.addr[i] = dest->addr[i]; ethhdr->src.addr[i] = ((struct cs8900if *)netif->state)->ethaddr->addr[i]; } ethhdr->type = htons(ETHTYPE_IP); cs8900_output(netif, ((struct cs8900if *)netif->state)->tx_queue); } ((struct cs8900if *)netif->state)->tx_queue = NULL; } }#endif break; default: pbuf_free(p); break; }}/*-----------------------------------------------------------------------------------*//* * cs8900if_init(): * * 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. * *//*-----------------------------------------------------------------------------------*/voidcs8900if_init(struct netif *netif){ struct cs8900if *cs8900if; // TODO: check result! cs8900if = mem_malloc(sizeof(struct cs8900if)); if (cs8900if == NULL) return; netif->state = cs8900if; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = cs8900if_output; netif->linkoutput = cs8900_output; cs8900if->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); // initially assume no ISQ event cs8900if->needs_service = 0; // set to 1 if polling method is used cs8900if->use_polling = 1;#if (CS8900_STATS > 0) // number of interrupts (vector calls) cs8900if->interrupts = 0; cs8900if->missed = 0; cs8900if->dropped = 0; cs8900if->sentpackets = 0; cs8900if->sentbytes = 0;#endif cs8900_init(netif); // TODO: remove this hack cs8900if_netif = netif; arp_init();}/*-----------------------------------------------------------------------------------*/// this basically dumps a array of bytes, length "len" into a UDP message. It bypasses// any functionality within lwIP, acting as a low level debug output function (in case// your hardware has no, or limited, display output available) to debug lwIP itself.//// The checksum routines are not implemented yet here, so do not expect your target's// IP stack to accept this packet. It works great, however, in combination with a// packet snooper, such as Ethereal (www.ethereal.org).//void cs8900_send_debug(unsigned char *p, unsigned int len){ int tries = 0, i; // exit if link has failed PACKETPP = CS_PP_LINESTATUS; if ((PPDATA & 0x0080U/*LinkOK*/) == 0) return; // TODO: find a correct error code /* transmit command */ TXCMD = 0x00C9U; TXLENGTH = (14 + 20 + 8 + len < 60)?60:(14 + 20 + 8 + len); PACKETPP = CS_PP_BUSSTATUS; // not ready for transmission and still within 100 retries? while(((PPDATA & 0x0100U/*Rdy4TxNOW*/) == 0) && (tries++ < 100)) { // throw away the last committed received frame PACKETPP = CS_PP_RXCFG; PPDATA = (0x0003U | 0x0040U/*Skip_1*/ | 0x0100U/*RxOKiE*/); PACKETPP = CS_PP_BUSSTATUS; /* cs8900if->dropped++; CHECK: we do not know if we actually will drop a frame here, do we? */ } // ready to transmit? if((PPDATA & 0x0100U/*Rdy4TxNOW*/) != 0) { // destination Ethernet address RXTXREG = 0xffff;//htons((0x00 << 8) | 0x0a); RXTXREG = 0xffff;//htons((0x24 << 8) | 0xc5); RXTXREG = 0xffff;//htons((0x72 << 8) | 0x6d); // source Ethernet address RXTXREG = htons(((u16_t)ETHADDR0 << 8U) | (u16_t)ETHADDR1); RXTXREG = htons(((u16_t)ETHADDR2 << 8U) | (u16_t)ETHADDR3); RXTXREG = htons(((u16_t)ETHADDR4 << 8U) | (u16_t)ETHADDR5); // frame type RXTXREG = htons(0x0800); // TOS, version RXTXREG = htons(((0x40 | 0x05) << 8) | 0x00); // length RXTXREG = htons(20 + 12 + len); // identifier RXTXREG = htons(0); // fragment offset RXTXREG = htons(0); // TTL, UDP protocol RXTXREG = htons((255U << 8) | 17U); // checksum RXTXREG = htons(0); // source IP RXTXREG = htons((htonl(cs8900if_netif->ip_addr.addr) & 0xffff0000U) >> 16); // source IP RXTXREG = htons(htonl(cs8900if_netif->ip_addr.addr) & 0x0000ffffU); // destination IP RXTXREG = htons(0xc0a8); // destination IP RXTXREG = htons(0x0001); // source port 3000 RXTXREG = htons(3000); // destination port 3000 RXTXREG = htons(3000); // UDP length RXTXREG = htons(len); // UDP checksum RXTXREG = htons(0); for (i = 0; i < len; i += 2) { RXTXREG = htons((p[i] << 8) | p[i + 1]); } while (i < 60) { RXTXREG = 0; i += 2; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -