1 #include <geekos/ne2k.h>
2 #include <geekos/debug.h>
4 #include <geekos/irq.h>
5 #include <geekos/malloc.h>
6 #include <geekos/string.h>
10 #include <uip/uip_arp.h>
14 #define TX_START_BUFF 0x40
15 #define RX_START_BUFF 0x4c
16 #define RX_END_BUFF 0x80
18 static uint_t next = (RX_START_BUFF << 8);
19 static uint_t received = 0;
20 static uint_t send_done = 1;
22 struct NE2K_REGS* regs;
25 int (*packet_received)(struct NE2K_Packet_Info *info, uchar_t *packet);
29 static void Dump_Registers()
32 PrintBoth("Dumping NIC registers for page %x...\n", (In_Byte(NE2K_CR) & 0xc0) >> 6);
34 for(i = 0; i <= 0x0f; i += 0x01) {
35 data = In_Byte(NE2K_BASE_ADDR+i);
36 PrintBoth("\t%x: %x\n", NE2K_BASE_ADDR + i, data);
41 static void NE2K_Interrupt_Handler(struct Interrupt_State * state)
45 PrintBoth("NIC Interrupt Occured!\n");
46 uchar_t isr_content = In_Byte(NE2K_ISR);
48 PrintBoth("Contents of ISR: %x\n", isr_content);
50 if(isr_content & 0x01) /* A packet has been received. */
53 Out_Byte(NE2K_CR, 0x4a); /* Page 1 */
54 current = In_Byte(NE2K_CURR);
55 Out_Byte(NE2K_CR, 0x0a); /* Page 0 */
58 /* When CURR equals BNRY, all packets in the receive ring buffer have been read, and
59 the packet received bit in the interrupt status register can be cleared. */
60 if(current == In_Byte(NE2K_BNRY))
61 Out_Byte(NE2K_ISR, 0x01);
65 if(isr_content & 0x02) /* A packet has been successfully transmitted. */
68 Out_Byte(NE2K_ISR, 0x02);
71 //Out_Byte(NE2K_ISR, 0xff); /* Clear all interrupts. */
74 int Init_Ne2k(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet))
76 callbacks.packet_received = rcvd_fn;
78 PrintBoth("Initializing network card...\n");
79 Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f)); /* Reset */
81 regs = Malloc(sizeof(struct NE2K_REGS));
82 struct _CR * cr = (struct _CR *)&(regs->cr);
83 struct _RCR * rcr = (struct _RCR*)&(regs->rcr);
84 struct _IMR * imr = (struct _IMR *)&(regs->imr);
87 regs->dcr = 0x49; /* Word-wide DMA transfer. */
88 regs->isr = 0xff; /* Clear all interrupts. */
89 regs->rcr = 0x20; /* Accept packets shorter than 64 bytes. */
90 regs->tcr = 0x02; /* Internal loopback mode. */
92 Out_Byte(NE2K_CR, regs->cr);
93 Out_Byte(NE2K_DCR, regs->dcr);
94 Out_Byte(NE2K_ISR, regs->isr);
95 Out_Byte(NE2K_RCR, regs->rcr);
96 Out_Byte(NE2K_TCR, regs->tcr);
97 Out_Byte(NE2K_IMR, regs->imr);
99 /* Remote byte count registers. */
100 Out_Byte(NE2K_RBCR0, 0x00);
101 Out_Byte(NE2K_RBCR1, 0x00);
102 /* Remote start address registers. */
103 Out_Byte(NE2K_RSAR0, 0x00);
104 Out_Byte(NE2K_RSAR1, 0x00);
106 Out_Byte(NE2K_TPSR, TX_START_BUFF); /* Transmit page start register */
107 Out_Byte(NE2K_PSTART, RX_START_BUFF); /* Page start register */
108 Out_Byte(NE2K_PSTOP, RX_END_BUFF); /* Page stop register */
109 Out_Byte(NE2K_BNRY, RX_START_BUFF); /* Boundary register */
111 cr->ps = 0x01; /* Switch to reg page 1. */
112 Out_Byte(NE2K_CR, regs->cr);
113 /* Current page register: points to first free page that can be used for packet reception. */
114 Out_Byte(NE2K_CURR, RX_START_BUFF);
115 cr->ps = 0x00; /* Switch to page 0 */
117 Out_Byte(NE2K_CR, regs->cr);
118 Out_Byte(NE2K_ISR, regs->isr);
120 /* Interrupt mask register: setting a bit to 1 enables the
121 corresponding interrupt in ISR. */
128 Out_Byte(NE2K_IMR, regs->imr);
130 cr->ps = 0x01; /* Switch to reg page 1 */
131 Out_Byte(NE2K_CR, regs->cr);
133 /* Set the physical address of the card */
134 Out_Byte(NE2K_CR+0x01, PHY_ADDR1);
135 Out_Byte(NE2K_CR+0x02, PHY_ADDR2);
136 Out_Byte(NE2K_CR+0x03, PHY_ADDR3);
137 Out_Byte(NE2K_CR+0x04, PHY_ADDR4);
138 Out_Byte(NE2K_CR+0x05, PHY_ADDR5);
139 Out_Byte(NE2K_CR+0x06, PHY_ADDR6);
141 /* Set the multicast address register to all 1s; accepts all multicast packets */
143 for(i = 0x08; i <= 0x0f; i++) {
144 Out_Byte(NE2K_CR+i, 0xff);
147 regs->cr = 0x21; //set CR to start value
148 Out_Byte(NE2K_CR, regs->cr);
151 Out_Byte(NE2K_TCR, regs->tcr);
157 rcr->pro = 0x1; /* Promiscuous mode: accept all packets. */
159 Out_Byte(NE2K_RCR, regs->rcr);
161 cr->sta = 0x1; // toggle start bit
163 Out_Byte(NE2K_CR, regs->cr);
169 Out_Byte(NE2K_CR, regs->cr);
173 Out_Byte(NE2K_CR, regs->cr);
177 Out_Byte(NE2K_CR, regs->cr);
180 Install_IRQ(NE2K_IRQ, NE2K_Interrupt_Handler);
181 Enable_IRQ(NE2K_IRQ);
183 for(i = 0; i < 0; i++)
186 PrintBoth("Transmitting a packet\n");
190 uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 };
191 uchar_t dest_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
194 uchar_t *data = Malloc(size);
195 data = "This is a 64-byte string that will be used to test transmission.";
197 for(i = 0; i < 0; i++) {
198 NE2K_Send(regs, src_addr, dest_addr, 0x01, data, size);
201 //Free(data); // Why does this crash?
207 * This function is called when there is data in uip_buf that's ready to be sent.
208 * uip_arp_out() is used to translate the destination IP address to a MAC address.
209 * If the corresponding MAC address isn't in the cache, the packet is replaced with
210 * an ARP packet, which is sent out instead. The original packet will need to be
211 * retransmitted at some point in the future.
215 int NE2K_Transmit(uint_t size)
221 /* Based on example code from the uIP documentation... */
222 if(size <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
223 memcpy(data, &uip_buf[0], size);
225 memcpy(data, &uip_buf[0], UIP_LLH_LEN + UIP_TCPIP_HLEN);
226 memcpy(data + UIP_LLH_LEN + UIP_TCPIP_HLEN, uip_appdata, size - UIP_TCPIP_HLEN - UIP_LLH_LEN);
229 /* Manually copy in the source MAC address for now. */
230 uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 };
231 memcpy(data + 6, src_addr, 6);
232 if(*(data+12) != 0x08 || *(data+13) != 0x06)
234 /* This is not an ARP packet. Fill in te size of the packet manually. */
235 *(data+12) = size & 0xff;
236 *(data+13) = (size >> 8) & 0xff;
239 NE2K_Send_Packet(data, size);
246 int NE2K_Send_Packet(uchar_t *packet, uint_t size)
248 struct _CR * cr = (struct _CR*)&(regs->cr);
249 regs->cr = 0x21; /* Turn off remote DMA, stop command */
250 cr->stp = 0x0; /* toggle start on */
252 Out_Byte(NE2K_CR, regs->cr);
254 // Read-before-write bug fix?
255 Out_Byte(NE2K_RBCR0, 0x42);
256 Out_Byte(NE2K_RBCR1, 0x00);
257 Out_Byte(NE2K_RSAR0, 0x42);
258 Out_Byte(NE2K_RSAR1, 0x00);
260 cr->rd = 0x01; /* set remote DMA to 'remote read' */
261 Out_Byte(NE2K_CR, regs->cr);
263 regs->isr = 0x40; /* clear 'remote DMA complete' interrupt */
264 Out_Byte(NE2K_ISR, regs->isr);
266 /* Set remote byte count registers */
267 Out_Byte(NE2K_RBCR0, size & 0xff);
268 Out_Byte(NE2K_RBCR1, (size >> 8) & 0xff);
270 /* Set transmit byte count registers. */
271 Out_Byte(NE2K_TBCR0, size & 0xff);
272 Out_Byte(NE2K_TBCR1, (size >> 8) & 0xff);
274 /* Set remote start address registers to the first page of the transmit ring buffer. */
275 Out_Byte(NE2K_RSAR0, 0x00);
276 Out_Byte(NE2K_RSAR1, TX_START_BUFF);
278 cr->rd = 0x02; /* Set remote DMA to 'remote write' */
279 Out_Byte(NE2K_CR, regs->cr);
281 /* Push the packet data to into the dataport */
283 for(i = 0; i < size; i += 2) {
284 Out_Word(NE2K_CR + 0x10, (*(packet + i + 1) << 8) | *(packet + i));
287 cr->txp = 0x1; /* Start transmission */
288 Out_Byte(NE2K_CR, regs->cr);
294 /* Assumes src and dest are arrays of 6 characters. */
295 int NE2K_Send(uchar_t src[], uchar_t dest[], uint_t type, uchar_t *data, uint_t size)
297 struct _CR * cr = (struct _CR*)&(regs->cr);
298 uint_t packet_size = size + 16;
299 regs->cr = 0x21; /* Turn off remote DMA, stop command */
300 cr->stp = 0x0; /* toggle start on */
302 Out_Byte(NE2K_CR, regs->cr);
304 // Read-before-write bug fix?
305 Out_Byte(NE2K_RBCR0, 0x42);
306 Out_Byte(NE2K_RBCR1, 0x00);
307 Out_Byte(NE2K_RSAR0, 0x42);
308 Out_Byte(NE2K_RSAR1, 0x00);
310 cr->rd = 0x01; /* set remote DMA to 'remote read' */
311 Out_Byte(NE2K_CR, regs->cr);
313 regs->isr = 0x40; /* clear 'remote DMA complete' interrupt */
314 Out_Byte(NE2K_ISR, regs->isr);
316 /* Set remote byte count registers */
317 Out_Byte(NE2K_RBCR0, packet_size & 0xff);
318 Out_Byte(NE2K_RBCR1, (packet_size >> 8) & 0xff);
320 /* Set transmit byte count registers. */
321 Out_Byte(NE2K_TBCR0, packet_size & 0xff);
322 Out_Byte(NE2K_TBCR1, (packet_size >> 8) & 0xff);
324 /* Set remote start address registers to the first page of the transmit ring buffer. */
325 Out_Byte(NE2K_RSAR0, 0x00);
326 Out_Byte(NE2K_RSAR1, TX_START_BUFF);
328 cr->rd = 0x02; /* Set remote DMA to 'remote write' */
329 Out_Byte(NE2K_CR, regs->cr);
331 /* Begin pushing the packet into the dataport (located at 0x10 from the base address). */
332 /* Destination Address */
333 Out_Word(NE2K_CR + 0x10, (dest[1] << 8) | dest[0]);
334 Out_Word(NE2K_CR + 0x10, (dest[3] << 8) | dest[2]);
335 Out_Word(NE2K_CR + 0x10, (dest[5] << 8) | dest[4]);
338 Out_Word(NE2K_CR + 0x10, (src[1] << 8) | src[0]);
339 Out_Word(NE2K_CR + 0x10, (src[3] << 8) | src[2]);
340 Out_Word(NE2K_CR + 0x10, (src[5] << 8) | src[4]);
343 Out_Word(NE2K_CR + 0x10, packet_size);
347 for(i = 0; i < size; i += 2) {
348 Out_Word(NE2K_CR + 0x10, (*(data + i + 1) << 8) | *(data + i));
351 cr->txp = 0x1; /* Start transmission */
352 Out_Byte(NE2K_CR, regs->cr);
360 PrintBoth("Packet Received\n");
362 Out_Byte(NE2K_CR, 0x22);
363 /* Set RSAR to the start address of the received packet. */
364 Out_Byte(NE2K_RSAR0, next & 0xff);
365 Out_Byte(NE2K_RSAR1, next >> 8);
366 Out_Byte(NE2K_CR, 0x0a);
369 * A four byte header is added to the beginning of each received packet by the NIC.
370 * The first byte is the location of the next packet in the ring buffer.
371 * The second byte is the receive status code.
372 * The third and fourth bytes are the size of the packet.
377 data = In_Word(NE2K_CR + 0x10);
380 PrintBoth("\nPacket data:\n\t");
381 PrintBoth("%x ", data);
384 /* Get the location of the next packet */
385 next = data & 0xff00;
387 /* Retrieve the packet size from the header, and store it in RBCR. */
388 uint_t packet_size = In_Word(NE2K_CR + 0x10) - 4;
389 uchar_t *packet = Malloc(packet_size);
390 Out_Byte(NE2K_RBCR0, packet_size & 0xff);
391 Out_Byte(NE2K_RBCR1, (packet_size>>8) & 0xff);
394 PrintBoth("packetsize = %x\n\t", packet_size);
397 /* Copy the received packet over from the ring buffer. */
398 for(i = 0; i < packet_size; i+=2) {
399 data = In_Word(NE2K_CR + 0x10);
400 *(packet + i) = data & 0x00ff;
401 *(packet + i + 1) = (data & 0xff00) >> 8;
403 PrintBoth("BNRY = %x\n", In_Byte(NE2K_BNRY));
404 Out_Byte(NE2K_CR, 0x4a);
405 PrintBoth("CURR = %x\n", In_Byte(NE2K_CURR));
406 Out_Byte(NE2K_CR, 0x0a);
410 //Out_Byte(NE2K_RBCR0, (In_Byte(NE2K_RBCR0))-2);
411 //Out_Byte(NE2K_RSAR0, (In_Byte(NE2K_RSAR0))+2);
413 PrintBoth("\n%d packets have been received", ++received);
416 Out_Byte(NE2K_ISR, 0x40); /* Clear the remote DMA complete interrupt. */
418 /* The BNRY register stores the location of the first packet that hasn't been read yet */
419 Out_Byte(NE2K_BNRY, next >> 8);
421 struct NE2K_Packet_Info *info = Malloc(sizeof(struct NE2K_Packet_Info));
422 info->size = packet_size;
424 memcpy(info->dest, packet, 6);
425 memcpy(info->src, packet + 6, 6);
426 callbacks.packet_received(info, packet);