POK
|
RTL8029 driver. More...
Go to the source code of this file.
Functions | |
void | rtl8029_read (pok_port_id_t port_id, void *data, uint32_t len) |
Reads data from the corresponding network stack. | |
void | rtl8029_write (pok_port_id_t port_id, const void *data, uint32_t len) |
Send data to the interface. | |
void | rtl8029_polling () |
Polls rtl8029 device. | |
void | rtl8029_init () |
Initializes rtl8029 device. |
void rtl8029_init | ( | ) |
Initializes rtl8029 device.
Seeks and registers PCI interface, set configuration and fills the dev structure.
Definition at line 382 of file rtl8029.c.
{ dev.pci.vendorid = 0x10ec; dev.pci.deviceid = 0x8029; dev.pci.io_range = 0x10; if (pci_register(&(dev.pci)) != 0) { printf("rtl8029: PCI init failed!\n"); return; } dev.addr = dev.pci.bar[0] & (~0x1F); unsigned char i = 0; unsigned char buf[6 * 2]; // used for MAC address NE2000_SELECT_PAGE(&dev, 0); /* This bit is the STOP command. When it is set, no packets will be received or transmitted. POWER UP=1. */ outb(NE2000_CR_STP, dev.addr + NE2000_CR); // Sets several options... Read the datasheet! outb(0x00, dev.addr + NE2000_TCR); outb(NE2000_RCR_AB, dev.addr + NE2000_RCR); outb(NE2000_DCR_LS | NE2000_DCR_FT1, dev.addr + NE2000_DCR); /* The Page Start register sets the start page address of the receive buffer ring. */ outb(NE2000_RXBUF, dev.addr + NE2000_PSTART); /* The Page Stop register sets the stop page address of the receive buffer ring. */ outb(NE2000_MEMSZ, dev.addr + NE2000_PSTOP); /* This register is used to prevent overwrite of the receive buffer ring. It is typically used as a pointer indicating the last receive buffer page the host has read. */ outb(NE2000_RXBUF, dev.addr + NE2000_BNRY); /* These two registers set the data byte counts of remote DMA. */ outb(0, dev.addr + NE2000_RBCR0); outb(0, dev.addr + NE2000_RBCR1); NE2000_SELECT_PAGE(&dev, 1); /* This register points to the page address of the first receive buffer page to be used for a packet reception. */ outb(NE2000_RXBUF + 1, dev.addr + NE2000_CURR); // Init mac address /* Here's something I do not understand... Section 6.2.2 of the datasheet says bytes 00H-05H of the PROM corresponds to the Ethernet ID. But it looks like each byte of the MAC address is written twice... Therefore I read 2 * sizeof(mac) and select one of the two bytes corresponding to the MAC... Weird... Really... */ ne2000_read(&dev, buf, 6 * 2, 0); for (i = 0; i < 6; i++) dev.mac[i] = buf[i * 2]; /* These registers contain my Ethernet node address and are used to compare the destination address of incoming packets for acceptation or rejection.*/ outb(dev.mac[0], dev.addr + NE2000_PAR0); outb(dev.mac[1], dev.addr + NE2000_PAR1); outb(dev.mac[2], dev.addr + NE2000_PAR2); outb(dev.mac[3], dev.addr + NE2000_PAR3); outb(dev.mac[4], dev.addr + NE2000_PAR4); outb(dev.mac[5], dev.addr + NE2000_PAR5); NE2000_SELECT_PAGE(&dev, 0); // Start command outb(NE2000_CR_STA, dev.addr + NE2000_CR); // Reactivating interrupts /* ISR register must be cleared after power up. */ outb(0xFF, dev.addr + NE2000_ISR); /* All bits correspond to the bits in the ISR register. POWER UP=all 0s. Setting individual bits will enable the corresponding interrupts. */ /* Since POK use polling, ALL interrupts are disabled */ outb(0x00, dev.addr + NE2000_IMR); for (i = 0; i < 20; i++) /* TODO: random constant */ { dev.recv_buf[i].len = 0; dev.recv_buf[i].off = 0; } return; }
void rtl8029_polling | ( | ) |
Polls rtl8029 device.
Watches for events, typically for receiving queued packets.
Definition at line 279 of file rtl8029.c.
{ unsigned char state; // ISR state NE2000_SELECT_PAGE(&dev, 0); while (1) { // do we have an interrupt flag set? if ((state = pok_inb(dev.addr + NE2000_ISR)) == 0) continue; if (state & NE2000_ISR_PRX) { if ((pok_inb(dev.addr + NE2000_RSR) & NE2000_RSR_PRX) == 0) { // error } printf("[*]\n"); /* no errors */ s_ne2000_header ne2000_hdr; // ne2000 packet header unsigned short offset; // dma offset unsigned char start, end; // pointers for the ring buffer pok_packet_t recv_packet; while (1) { /* This register is used to prevent overwrite of the receive buffer ring. It is typically used as a pointer indicating the last receive buffer page the host has read.*/ start = pok_inb(dev.addr + NE2000_BNRY) + 1; /* This register points to the page address of the first receive buffer page to be used for a packet reception. */ NE2000_SELECT_PAGE(&dev, 1); end = pok_inb(dev.addr + NE2000_CURR); NE2000_SELECT_PAGE(&dev, 0); if ((end % NE2000_MEMSZ) == (start % NE2000_MEMSZ) + 1) { break; } /* et on decapsule! */ offset = start << 8; // ne2000 header offset += ne2000_read(&dev, &ne2000_hdr, sizeof(s_ne2000_header), offset); ne2000_read(&dev, &recv_packet, ne2000_hdr.size - sizeof(s_ne2000_header), offset); rtl8029_enqueue(&recv_packet); // update the BNRY register... almost forgot that outb(ne2000_hdr.next > NE2000_MEMSZ ? NE2000_RXBUF - 1 : ne2000_hdr.next - 1, dev.addr + NE2000_BNRY); } outb(NE2000_ISR_PRX, dev.addr + NE2000_ISR); // Clear PRX flag } if (state & NE2000_ISR_PTX) { outb(NE2000_ISR_PTX, dev.addr + NE2000_ISR); // Clear PTX flag } if (state & NE2000_ISR_RXE) { outb(NE2000_ISR_RXE, dev.addr + NE2000_ISR); // Clear RXE flag } if (state & NE2000_ISR_TXE) { outb(NE2000_ISR_TXE, dev.addr + NE2000_ISR); // Clear TXE flag } if (state & NE2000_ISR_OVW) { outb(NE2000_ISR_OVW, dev.addr + NE2000_ISR); // Clear OVW flag } if (state & NE2000_ISR_CNT) { outb(NE2000_ISR_CNT, dev.addr + NE2000_ISR); // Clear CNT flag } if (state & NE2000_ISR_RST) { outb(NE2000_ISR_RST, dev.addr + NE2000_ISR); // Clear RST bit } } }
void rtl8029_read | ( | pok_port_id_t | port_id, |
void * | data, | ||
uint32_t | len | ||
) |
Reads data from the corresponding network stack.
Reads enqueued data in the stack partition.
Definition at line 146 of file rtl8029.c.
{ pok_port_id_t global; pok_ret_t ret; ret = pok_port_virtual_get_global (port_id, &global); if (ret == POK_ERRNO_OK) { char *dest = data; pok_queue_t* queue = dev.recv_buf + global; uint32_t size = len < queue->len ? len : queue->len; uint32_t copied = 0; printf ("[RTL8029] READ DATA FROM LOCAL PORT %d " "GLOBAL_PORT=%d), size=%d\n", port_id, global, len); /* is there something to read ? */ if (queue->len == 0) { printf("rtl8029_read: error: empty read ring buffer %d!\n", port_id); return; } /* copy from the queue to the buffer */ for (copied = 0; copied < size; copied++) { dest[copied % RECV_BUF_SZ] = queue->data[queue->off]; queue->off = (queue->off + 1) % RECV_BUF_SZ; } /* updating data length in this queue */ queue->len -= size; } }
void rtl8029_write | ( | pok_port_id_t | port_id, |
const void * | data, | ||
uint32_t | len | ||
) |
Send data to the interface.
Writes data to be sent to network.
Definition at line 187 of file rtl8029.c.
{ uint32_t nbdest; uint32_t tmp; uint32_t dest; pok_ret_t ret; char node2[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; pok_packet_t packet; const char* d; size_t cpylen = 0; size_t sndlen = 0; unsigned char state; // ISR state ret = pok_port_virtual_nb_destinations (port_id, &nbdest); if (ret != POK_ERRNO_OK) { return; } for (tmp = 0 ; tmp < nbdest ; tmp++) { ret = pok_port_virtual_destination (port_id, tmp, &dest); if (ret == POK_ERRNO_OK) { printf ("[RTL8029] SEND DATA THROUGH NETWORK FROM LOCAL PORT %d " "TO GLOBAL PORT %d, size=%d\n", port_id, dest, len); memcpy(packet.eth.src, dev.mac, ETH_MAC_LEN); memcpy(packet.eth.dst, node2, ETH_MAC_LEN); packet.eth.ethertype = 0x4242; packet.udp.src = port_id; packet.udp.dst = dest; for (d = data; len != 0; len -= cpylen, data += cpylen) { // too short; let's cut if (len <= NET_DATA_MINLEN) { cpylen = len; sndlen = ETH_DATA_MINLEN + sizeof(eth_hdr_t); } else { // too big; let's pad if (len >= NET_DATA_MAXLEN) { cpylen = NET_DATA_MAXLEN; sndlen = ETH_DATA_MAXLEN + sizeof(eth_hdr_t); } // normal else { cpylen = len; sndlen = sizeof(eth_hdr_t) + sizeof(udp_hdr_t) + cpylen; } } packet.udp.len = cpylen; memcpy(&(packet.data), data, cpylen); ne2000_write(&dev, &packet, sndlen, NE2000_TXBUF * 256); do { state = pok_inb(dev.addr + NE2000_ISR); } while ((state & NE2000_ISR_RDC) != NE2000_ISR_RDC); /* This register sets the start page address of the packet to the transmitted. */ outb(NE2000_TXBUF, dev.addr + NE2000_TPSR); //? /* These two registers set the byte counts of the packet to be transmitted. */ outb(sndlen, dev.addr + NE2000_TBCR0); outb(sndlen >> 8, dev.addr + NE2000_TBCR1); /* This bit must be set to transmit a packet. */ outb(pok_inb(dev.addr + NE2000_CR) | NE2000_CR_TXP, dev.addr + NE2000_CR); outb(NE2000_ISR_RDC, dev.addr + NE2000_ISR); // Clear RDC bit } } } }