BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / drivers / net

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
new file mode 100644
index 0000000..e801845
--- /dev/null
+++ b/drivers/net/rtl8139.c
@@ -0,0 +1,148 @@
+/*
+ * The is the RTL8139 driver.  It is a simple driver for a simple network card.
+ * It will just abstract the hardware away, and allows the network system to
+ * utilise it
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include "../pci.h"
+#include "../../mem/heap.h"
+#include "../../proc/proc.h"
+#include "../../net/net.h"
+#include "../../io.h"
+#include "../../screen.h"
+
+#define RTL_PORT_MAC     0x00
+#define RTL_PORT_RX_PTR  0x38
+#define RTL_PORT_RBSTART 0x30
+#define RTL_PORT_IMR     0x3C
+#define RTL_PORT_ISR     0x3E
+#define RTL_PORT_CMD     0x37
+#define RTL_PORT_RXMISS  0x4C
+#define RTL_PORT_TCR     0x40
+#define RTL_PORT_RCR     0x44
+#define RTL_PORT_CONFIG  0x52
+#define RTL_RX_BUF_SIZE  (8192+16+1500)
+#define RTL_TX_BUF_SIZE  (1536)
+
+#define RTL_CFG_AAP (1 << 0) /* Accept all packets */
+#define RTL_CFG_APM (1 << 1) /* Accept packets to NIC's MAC address */
+#define RTL_CFG_AM  (1 << 2) /* Accept multicast packets */
+#define RTL_CFG_AB  (1 << 3) /* Accept broadcast packets */
+
+#define RTL_ISR_ROK (1 << 0) /* Receive Okay */
+#define RTL_ISR_TOK (1 << 2) /* Transmit Okay */
+
+static NetIF *netif;
+
+void *txBuf, *rxBuf;
+uint8_t txIndex = 0;
+uint32_t rxIndex = 0;
+uint16_t port;
+
+uint16_t txStartRegs[] = {0x20, 0x24, 0x28, 0x2C};
+uint16_t txControlRegs[] = {0x10, 0x14, 0x18, 0x1C};
+
+void rtl8139_transmit(void *data, size_t len);
+void rtl8139_receive(void);
+
+/* Handle the RTL8139 interrupt */
+void
+rtl8139_irq(InterruptFrame *frame)
+{
+	uint16_t status;
+	/* Loop until everything has been handled */
+	while (1) {
+		status = inw(port + RTL_PORT_ISR);
+		outw(port + RTL_PORT_ISR, status);
+		if (!status)
+			break;
+		if (status & RTL_ISR_ROK)
+			rtl8139_receive();
+	}
+}
+
+/* Transmit a frame */
+void
+rtl8139_transmit(void *data, size_t len)
+{
+	memcpy(txBuf, data, len);
+	outl(port + txStartRegs[txIndex], (uintptr_t) txBuf);
+	outl(port + txControlRegs[txIndex], len);
+	txIndex++;
+	if (txIndex > 3)
+		txIndex = 0;
+}
+
+/* Receive a frame */
+void
+rtl8139_receive(void)
+{
+	uint8_t *frame, *buf = rxBuf;
+	uint32_t index = rxIndex;
+	uint32_t offset, len;
+
+	/* While the buffer is not empty */
+	while ((inb(port + RTL_PORT_CMD) & 0x01) == 0) {
+		offset = index % RTL_RX_BUF_SIZE;
+		len = (buf[3 + index] << 8) + buf[2 + index];
+
+		frame = kmalloc(len);
+		memcpy(frame, &buf[offset + 4], len);
+		ethernet_receive_frame(netif, frame, len);
+		kfree(frame);
+
+		index = (index + len + 7) & ~3;
+		outw(port + RTL_PORT_RX_PTR, index - 16);
+	}
+
+	rxIndex = index;
+}
+
+/* Get the RTL8139 MAC Address */
+void
+rtl8139_get_mac(char *buf)
+{
+	uint8_t i;
+	for (i = 0; i < 6; i++)
+		buf[i] = inb(port + RTL_PORT_MAC + i);
+}
+
+/* Initialise the RTL8139 Network card */
+void
+rtl8139_init(uint8_t bus, uint8_t dev, uint8_t func)
+{
+	/* Enable bus mastering */
+	uint16_t command = pci_read_word(bus, dev, func, 4);
+	if (!(command & (1 << 2)))
+		pci_write_word(bus, dev, func, 4, command | (1 << 2));
+
+	/* Turn device on */
+	port = pci_read_word(bus, dev, func, 0x10) & ~3;
+	outb(port + RTL_PORT_CONFIG, 0x00);
+	/* Software reset */
+	outb(port + RTL_PORT_CMD, 0x10);
+	while ((inb(port + RTL_PORT_CMD) & 0x10) != 0);
+	/* Initialise buffers */
+	txBuf = kmalloc(RTL_RX_BUF_SIZE);
+	rxBuf = kmalloc(RTL_TX_BUF_SIZE);
+	/* TODO: use dedicated DMA area */
+	outl(port + RTL_PORT_RBSTART, (uintptr_t) rxBuf);
+	/* IMR & ISR */
+	outw(port + RTL_PORT_IMR, 0x05);
+
+	/* Configure receive buffer */
+	outl(port + RTL_PORT_RCR, (1 << 7) |
+	     RTL_CFG_AB | RTL_CFG_AM | RTL_CFG_APM | RTL_CFG_AAP);
+	/* Enable RX and TX */
+	outb(port + RTL_PORT_CMD, 0x0C);
+
+	/* Register interrupt handler */
+	uint8_t irq = pci_read_byte(bus, dev, func, 0x3C);
+	register_interrupt(irq, rtl8139_irq);
+
+	/* Setup Network Interface */
+	netif = net_create_interface(1, rtl8139_transmit, rtl8139_get_mac);
+}