#include <geekos/irq.h>
#include <geekos/malloc.h>
#include <geekos/string.h>
+#include <uip/uip.h>
+#include <uip/uip_arp.h>
#define DEBUG 1
#define TX_START_BUFF 0x40
#define RX_START_BUFF 0x4c
#define RX_END_BUFF 0x80
-uint_t next = (RX_START_BUFF << 8);
+static uint_t next = (RX_START_BUFF << 8);
static uint_t received = 0;
static uint_t send_done = 1;
+struct NE2K_REGS* regs;
+
struct callback {
int (*packet_received)(struct NE2K_Packet_Info *info, uchar_t *packet);
} callbacks;
+#if DEBUG
static void Dump_Registers()
{
uint_t data;
PrintBoth("\t%x: %x\n", NE2K_BASE_ADDR + i, data);
}
}
-
-static int NE2K_Transmit(struct NE2K_REGS *regs)
-{
- while(!send_done);
- send_done = 0;
-
- struct _CR * cr = (struct _CR*)&(regs->cr);
- uint_t packet_size = 80;
- regs->cr = 0x21;
- cr->stp = 0x0; //toggle start on
- cr->sta = 0x1;
- Out_Byte(NE2K_CR, regs->cr);
-
- // Read-before-write bug fix?
- Out_Byte(NE2K_RBCR0, 0x42);
- Out_Byte(NE2K_RBCR1, 0x00);
- Out_Byte(NE2K_RSAR0, 0x42);
- Out_Byte(NE2K_RSAR1, 0x00);
-
- cr->rd = 0x01; // set remote DMA to 'remote read'
- Out_Byte(NE2K_CR, regs->cr);
-
- regs->isr = 0x40; // clear and set Remote DMA high
- Out_Byte(NE2K_ISR, regs->isr);
-
- Out_Byte(NE2K_RBCR0, packet_size);
- Out_Byte(NE2K_RBCR1, 0x00);
-
- Out_Byte(NE2K_TBCR0, packet_size);
- Out_Byte(NE2K_TBCR1, 0x00);
-
- Out_Byte(NE2K_RSAR0, 0x00);
- Out_Byte(NE2K_RSAR1, 0x40);
-
- regs->cr = 0x16;
- Out_Byte(NE2K_CR, regs->cr);
-
- /* Begin pushing the packet into the dataport (located at 0x10 from the base address) */
- /* Destination address = 52:54:00:12:34:56 */
- Out_Word(NE2K_CR+0x10, 0x5452);
- Out_Word(NE2K_CR+0x10, 0x1200);
- Out_Word(NE2K_CR+0x10, 0x5634);
-
- /* Source address = 52:54:00:12:34:58 */
- Out_Word(NE2K_CR+0x10, 0x5452);
- Out_Word(NE2K_CR+0x10, 0x1200);
- Out_Word(NE2K_CR+0x10, 0x5834);
-
- /* Type length and data; currently random data */
- uint_t i;
- uint_t n = 0;
- for(i = 1; i <= packet_size/2-12; i++, n+=2) {
- //Out_Word(NE2K_CR+0x10, 0x0f0b);
- Out_Word(NE2K_CR+0x10, (n<<8) | (n+1));
- }
-
- //regs->isr = 0x40;
- //Out_Byte(NE2K_ISR, regs->isr); /* Do we need this here? */
-
- return 0;
-}
+#endif
static void NE2K_Interrupt_Handler(struct Interrupt_State * state)
{
+
Begin_IRQ(state);
PrintBoth("NIC Interrupt Occured!\n");
uchar_t isr_content = In_Byte(NE2K_ISR);
if(isr_content & 0x01) /* A packet has been received. */
{
uchar_t current;
- do{
- Out_Byte(NE2K_CR, 0x4a);
- current = In_Byte(NE2K_CURR);
- Out_Byte(NE2K_CR, 0x0a);
- NE2K_Receive();
- Out_Byte(NE2K_ISR, 0x01);
- /* If BNRY and CURR aren't equal, more than one packet has been received. */
- }while (current > In_Byte(NE2K_BNRY));
+ Out_Byte(NE2K_CR, 0x4a); /* Page 1 */
+ current = In_Byte(NE2K_CURR);
+ Out_Byte(NE2K_CR, 0x0a); /* Page 0 */
+ NE2K_Receive();
+
+ /* When CURR equals BNRY, all packets in the receive ring buffer have been read, and
+ the packet received bit in the interrupt status register can be cleared. */
+ if(current == In_Byte(NE2K_BNRY))
+ Out_Byte(NE2K_ISR, 0x01);
}
End_IRQ(state);
send_done = 1;
Out_Byte(NE2K_ISR, 0x02);
}
- Out_Byte(NE2K_ISR, 0xff); /* Clear all interrupts. */
+
+ //Out_Byte(NE2K_ISR, 0xff); /* Clear all interrupts. */
}
int Init_Ne2k(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet))
callbacks.packet_received = rcvd_fn;
PrintBoth("Initializing network card...\n");
- Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f)); /* Reset? */
+ Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f)); /* Reset */
- struct NE2K_REGS* regs = Malloc(sizeof(struct NE2K_REGS));
+ regs = Malloc(sizeof(struct NE2K_REGS));
struct _CR * cr = (struct _CR *)&(regs->cr);
struct _RCR * rcr = (struct _RCR*)&(regs->rcr);
struct _IMR * imr = (struct _IMR *)&(regs->imr);
cr->sta = 0x1; // toggle start bit
cr->stp = 0x0;
Out_Byte(NE2K_CR, regs->cr);
-
+
+#if DEBUG
Dump_Registers();
- cr->ps = NE2K_PAGE1;
+ cr->ps = 0x01;
Out_Byte(NE2K_CR, regs->cr);
Dump_Registers();
- cr->ps = NE2K_PAGE2;
+ cr->ps = 0x02;
Out_Byte(NE2K_CR, regs->cr);
Dump_Registers();
- cr->ps = NE2K_PAGE0;
+ cr->ps = 0x00;
Out_Byte(NE2K_CR, regs->cr);
+#endif
Install_IRQ(NE2K_IRQ, NE2K_Interrupt_Handler);
Enable_IRQ(NE2K_IRQ);
-
+#if 0
for(i = 0; i < 0; i++)
{
NE2K_Transmit(regs);
PrintBoth("Transmitting a packet\n");
}
-
+#endif
+/*
uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 };
uchar_t dest_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
for(i = 0; i < 0; i++) {
NE2K_Send(regs, src_addr, dest_addr, 0x01, data, size);
}
-
+*/
//Free(data); // Why does this crash?
return 0;
}
+/*
+ * This function is called when there is data in uip_buf that's ready to be sent.
+ * uip_arp_out() is used to translate the destination IP address to a MAC address.
+ * If the corresponding MAC address isn't in the cache, the packet is replaced with
+ * an ARP packet, which is sent out instead. The original packet will need to be
+ * retransmitted at some point in the future.
+ */
+int NE2K_Transmit(uint_t size)
+{
+ uip_arp_out();
+ uchar_t *data;
+ data = Malloc(size);
+
+ /* Based on example code from the uIP documentation... */
+ if(size <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
+ memcpy(data, &uip_buf[0], size);
+ } else {
+ memcpy(data, &uip_buf[0], UIP_LLH_LEN + UIP_TCPIP_HLEN);
+ memcpy(data + UIP_LLH_LEN + UIP_TCPIP_HLEN, uip_appdata, size - UIP_TCPIP_HLEN - UIP_LLH_LEN);
+ }
+
+ /* Manually copy in the source MAC address for now. */
+ uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 };
+ memcpy(data + 6, src_addr, 6);
+ if(*(data+12) != 0x08 || *(data+13) != 0x06)
+ {
+ /* This is not an ARP packet. Fill in te size of the packet manually. */
+ *(data+12) = size & 0xff;
+ *(data+13) = (size >> 8) & 0xff;
+ }
+
+ NE2K_Send_Packet(data, size);
+ Free(data);
+ return 0;
+}
+
+int NE2K_Send_Packet(uchar_t *packet, uint_t size)
+{
+ struct _CR * cr = (struct _CR*)&(regs->cr);
+ regs->cr = 0x21; /* Turn off remote DMA, stop command */
+ cr->stp = 0x0; /* toggle start on */
+ cr->sta = 0x1;
+ Out_Byte(NE2K_CR, regs->cr);
+
+ // Read-before-write bug fix?
+ Out_Byte(NE2K_RBCR0, 0x42);
+ Out_Byte(NE2K_RBCR1, 0x00);
+ Out_Byte(NE2K_RSAR0, 0x42);
+ Out_Byte(NE2K_RSAR1, 0x00);
+
+ cr->rd = 0x01; /* set remote DMA to 'remote read' */
+ Out_Byte(NE2K_CR, regs->cr);
+
+ regs->isr = 0x40; /* clear 'remote DMA complete' interrupt */
+ Out_Byte(NE2K_ISR, regs->isr);
+
+ /* Set remote byte count registers */
+ Out_Byte(NE2K_RBCR0, size & 0xff);
+ Out_Byte(NE2K_RBCR1, (size >> 8) & 0xff);
+
+ /* Set transmit byte count registers. */
+ Out_Byte(NE2K_TBCR0, size & 0xff);
+ Out_Byte(NE2K_TBCR1, (size >> 8) & 0xff);
+
+ /* Set remote start address registers to the first page of the transmit ring buffer. */
+ Out_Byte(NE2K_RSAR0, 0x00);
+ Out_Byte(NE2K_RSAR1, TX_START_BUFF);
+
+ cr->rd = 0x02; /* Set remote DMA to 'remote write' */
+ Out_Byte(NE2K_CR, regs->cr);
+
+ /* Push the packet data to into the dataport */
+ uint_t i;
+ for(i = 0; i < size; i += 2) {
+ Out_Word(NE2K_CR + 0x10, (*(packet + i + 1) << 8) | *(packet + i));
+ }
+
+ cr->txp = 0x1; /* Start transmission */
+ Out_Byte(NE2K_CR, regs->cr);
+
+ return 0;
+}
+
+#if 1
/* Assumes src and dest are arrays of 6 characters. */
-int NE2K_Send(struct NE2K_REGS *regs, uchar_t src[], uchar_t dest[], uint_t type, uchar_t *data, uint_t size)
+int NE2K_Send(uchar_t src[], uchar_t dest[], uint_t type, uchar_t *data, uint_t size)
{
struct _CR * cr = (struct _CR*)&(regs->cr);
uint_t packet_size = size + 16;
- regs->cr = 0x21;
- cr->stp = 0x0; //toggle start on
+ regs->cr = 0x21; /* Turn off remote DMA, stop command */
+ cr->stp = 0x0; /* toggle start on */
cr->sta = 0x1;
Out_Byte(NE2K_CR, regs->cr);
Out_Byte(NE2K_RSAR0, 0x42);
Out_Byte(NE2K_RSAR1, 0x00);
- cr->rd = 0x01; // set remote DMA to 'remote read'
+ cr->rd = 0x01; /* set remote DMA to 'remote read' */
Out_Byte(NE2K_CR, regs->cr);
- regs->isr = 0x40; // clear and set Remote DMA high
+ regs->isr = 0x40; /* clear 'remote DMA complete' interrupt */
Out_Byte(NE2K_ISR, regs->isr);
/* Set remote byte count registers */
Out_Byte(NE2K_TBCR0, packet_size & 0xff);
Out_Byte(NE2K_TBCR1, (packet_size >> 8) & 0xff);
+ /* Set remote start address registers to the first page of the transmit ring buffer. */
Out_Byte(NE2K_RSAR0, 0x00);
Out_Byte(NE2K_RSAR1, TX_START_BUFF);
- regs->cr = 0x16;
+ cr->rd = 0x02; /* Set remote DMA to 'remote write' */
Out_Byte(NE2K_CR, regs->cr);
+ /* Begin pushing the packet into the dataport (located at 0x10 from the base address). */
/* Destination Address */
Out_Word(NE2K_CR + 0x10, (dest[1] << 8) | dest[0]);
Out_Word(NE2K_CR + 0x10, (dest[3] << 8) | dest[2]);
/* Type */
Out_Word(NE2K_CR + 0x10, packet_size);
+ /* Packet data */
uint_t i;
for(i = 0; i < size; i += 2) {
Out_Word(NE2K_CR + 0x10, (*(data + i + 1) << 8) | *(data + i));
}
+ cr->txp = 0x1; /* Start transmission */
+ Out_Byte(NE2K_CR, regs->cr);
+
return 0;
}
+#endif
int NE2K_Receive()
{
uint_t i;
uint_t data;
- PrintBoth("\nPacket data:\n\t");
-
data = In_Word(NE2K_CR + 0x10);
+
+#if DEBUG
+ PrintBoth("\nPacket data:\n\t");
PrintBoth("%x ", data);
+#endif
/* Get the location of the next packet */
next = data & 0xff00;
/* Copy the received packet over from the ring buffer. */
for(i = 0; i < packet_size; i+=2) {
data = In_Word(NE2K_CR + 0x10);
- //PrintBoth("%x ", data);
*(packet + i) = data & 0x00ff;
*(packet + i + 1) = (data & 0xff00) >> 8;
#if 0
PrintBoth("CURR = %x\n", In_Byte(NE2K_CURR));
Out_Byte(NE2K_CR, 0x0a);
#endif
-
- //if(!(i%10))
- //PrintBoth("\n\t");
}
//Out_Byte(NE2K_RBCR0, (In_Byte(NE2K_RBCR0))-2);