[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH] CDI NE2K driver
This patch adds a CDI driver for the NE2K (PCI) NIC.
Signed-off-by: Matthew Iselin <matthew@xxxxxxxxxxxxxx>
---
src/modules/cdi/ne2k/Makefile.all | 6 +
src/modules/cdi/ne2k/include/ethernet.h | 43 ++++
src/modules/cdi/ne2k/include/ne2k.h | 105 +++++++++
src/modules/cdi/ne2k/main.c | 118 ++++++++++
src/modules/cdi/ne2k/ne2k.c | 355 +++++++++++++++++++++++++++++++
5 files changed, 627 insertions(+), 0 deletions(-)
create mode 100644 src/modules/cdi/ne2k/Makefile.all
create mode 100644 src/modules/cdi/ne2k/include/ethernet.h
create mode 100644 src/modules/cdi/ne2k/include/ne2k.h
create mode 100644 src/modules/cdi/ne2k/main.c
create mode 100644 src/modules/cdi/ne2k/ne2k.c
diff --git a/src/modules/cdi/ne2k/Makefile.all b/src/modules/cdi/ne2k/Makefile.all
new file mode 100644
index 0000000..250d3c3
--- /dev/null
+++ b/src/modules/cdi/ne2k/Makefile.all
@@ -0,0 +1,6 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
+
+echo "LD $1/modules/ne2k"
+$LOST_TOOLS_LD -Ttext=0x40000000 -one2k.mod *.o --start-group $2 --end-group
+$LOST_TOOLS_STRIP -s ne2k.mod -o $1/modules/ne2k
diff --git a/src/modules/cdi/ne2k/include/ethernet.h b/src/modules/cdi/ne2k/include/ethernet.h
new file mode 100644
index 0000000..a8159d1
--- /dev/null
+++ b/src/modules/cdi/ne2k/include/ethernet.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ETHERNET_H_
+#define _ETHERNET_H_
+
+#include <stdint.h>
+
+#define ETH_TYPE_IP 0x0008
+#define ETH_TYPE_ARP 0x0608
+
+struct eth_packet_header {
+ uint64_t dest : 48;
+ uint64_t src : 48;
+ uint16_t type;
+} __attribute__ ((packed));
+
+#endif
diff --git a/src/modules/cdi/ne2k/include/ne2k.h b/src/modules/cdi/ne2k/include/ne2k.h
new file mode 100644
index 0000000..a3c78e3
--- /dev/null
+++ b/src/modules/cdi/ne2k/include/ne2k.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2007 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Matthew Iselin.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NE2K_H_
+#define _NE2K_H_
+
+#include <stdint.h>
+
+#include "cdi.h"
+#include "cdi/net.h"
+#include "cdi/pci.h"
+
+#define NE_CMD 0
+#define NE_PSTART 1
+#define NE_PSTOP 2
+#define NE_BNDRY 3
+
+#define NE_TSR 4 // R
+#define NE_TPSR 4 // W
+
+#define NE_TBCR0 5
+#define NE_TBCR1 6
+
+#define NE_ISR 7
+
+#define NE_RSAR0 8
+#define NE_RSAR1 9
+#define NE_RBCR0 10
+#define NE_RBCR1 11
+
+#define NE_RCR 12
+#define NE_TCR 13
+#define NE_DCR 14
+#define NE_IMR 15
+
+// Register page 1
+#define NE_PAR 1 // PAR0..5
+#define NE_CURR 7
+#define NE_MAR 8
+
+// Packet ring buffer offsets
+#define PAGE_TX 0x40
+#define PAGE_RX 0x50
+#define PAGE_STOP 0x80
+
+#define NE_RESET 0x1F
+#define NE_DATA 0x10
+
+#define PHYS(netcard, field) \
+ ((uintptr_t) netcard->phys + offsetof(struct rtl8139_device, field))
+
+#define RX_BUFFER_SIZE 0x2000
+#define TX_BUFFER_SIZE 0x1000
+
+typedef struct {
+ void* virt;
+ uintptr_t phys;
+} cdi_dma_mem_ptr_t;
+
+struct ne2k_device {
+ struct cdi_net_device net;
+ struct cdi_pci_device* pci;
+
+ void* phys;
+ uint16_t port_base;
+
+ uint8_t next_packet;
+
+ int tx_in_progress;
+
+ cdi_list_t pending_sends;
+};
+
+void ne2k_init_device(struct cdi_device* device);
+void ne2k_remove_device(struct cdi_device* device);
+
+void ne2k_send_packet
+ (struct cdi_net_device* device, void* data, size_t size);
+
+#endif
diff --git a/src/modules/cdi/ne2k/main.c b/src/modules/cdi/ne2k/main.c
new file mode 100644
index 0000000..66ec9a8
--- /dev/null
+++ b/src/modules/cdi/ne2k/main.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2007 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Matthew Iselin.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include "cdi/net.h"
+#include "cdi/pci.h"
+#include "cdi/misc.h"
+
+#include "ne2k.h"
+
+struct module_options {
+ uint32_t ip;
+};
+
+static struct {
+ struct cdi_net_driver net;
+} driver;
+
+static const char* driver_name = "ne2k";
+
+static int ne2k_driver_init(int argc, char* argv[]);
+static void ne2k_driver_destroy(struct cdi_driver* driver);
+
+#ifdef CDI_STANDALONE
+int main(int argc, char* argv[])
+#else
+int init_ne2k(int argc, char* argv[])
+#endif
+{
+ cdi_init();
+
+ ne2k_driver_init(argc, argv);
+ cdi_driver_register((struct cdi_driver*) &driver);
+
+ cdi_run_drivers();
+
+ return 0;
+}
+
+static int ne2k_driver_init(int argc, char* argv[])
+{
+ // TODO Auf pci-Service warten
+ // TODO Auf tcpip-Service warten
+
+ // Konstruktor der Vaterklasse
+ cdi_net_driver_init((struct cdi_net_driver*) &driver);
+
+ // Namen setzen
+ driver.net.drv.name = driver_name;
+
+ // Funktionspointer initialisieren
+ driver.net.drv.destroy = ne2k_driver_destroy;
+ driver.net.drv.init_device = ne2k_init_device;
+ driver.net.drv.remove_device = ne2k_remove_device;
+
+ // Passende PCI-Geraete suchen
+ cdi_list_t pci_devices = cdi_list_create();
+ cdi_pci_get_all_devices(pci_devices);
+
+ struct cdi_pci_device* dev;
+ int i;
+ for (i = 0; (dev = cdi_list_get(pci_devices, i)); i++) {
+ if ((dev->vendor_id == 0x10ec) && (dev->device_id == 0x8029)) {
+ void* phys_device;
+ struct ne2k_device* device;
+
+ cdi_alloc_phys_mem(sizeof(*device),
+ (void**) &device, &phys_device);
+ memset(device, 0, sizeof(*device));
+
+ device->phys = phys_device;
+ device->pci = dev;
+ cdi_list_push(driver.net.drv.devices, device);
+ } else {
+ cdi_pci_device_destroy(dev);
+ }
+ }
+
+ cdi_list_destroy(pci_devices);
+
+ return 0;
+}
+
+/**
+ * Deinitialisiert die Datenstrukturen fuer den ne2k-Treiber
+ */
+static void ne2k_driver_destroy(struct cdi_driver* driver)
+{
+ cdi_net_driver_destroy((struct cdi_net_driver*) driver);
+
+ // TODO Alle Karten deinitialisieren
+}
diff --git a/src/modules/cdi/ne2k/ne2k.c b/src/modules/cdi/ne2k/ne2k.c
new file mode 100644
index 0000000..2e54f28
--- /dev/null
+++ b/src/modules/cdi/ne2k/ne2k.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2007 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Matthew Iselin.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "cdi/net.h"
+#include "cdi/pci.h"
+#include "cdi/io.h"
+#include "cdi/misc.h"
+
+#include "ne2k.h"
+#include "ethernet.h"
+
+//Hier koennen die Debug-Nachrichten aktiviert werden
+// #define DEBUG_MSG(s) printf("[ne2k] debug: %s() '%s'\n", __FUNCTION__, s)
+#define DEBUG_MSG(s) //
+
+static void ne2k_handle_interrupt(struct cdi_device* device);
+static void receive_ok_handler(struct ne2k_device* netcard);
+static void transmit_ok_handler(struct ne2k_device* netcard);
+
+static inline void write_register_byte(struct ne2k_device* netcard, uint8_t reg, uint8_t value)
+{
+ cdi_outb(netcard->port_base + reg, value);
+}
+
+static inline void write_register_word(struct ne2k_device* netcard, uint8_t reg, uint16_t value)
+{
+ cdi_outw(netcard->port_base + reg, value);
+}
+
+static inline void write_register_dword(struct ne2k_device* netcard, uint8_t reg, uint32_t value)
+{
+ cdi_outl(netcard->port_base + reg, value);
+}
+
+static inline uint8_t read_register_byte(struct ne2k_device* netcard, uint8_t reg)
+{
+ return cdi_inb(netcard->port_base + reg);
+}
+
+static inline uint16_t read_register_word(struct ne2k_device* netcard, uint8_t reg)
+{
+ return cdi_inw(netcard->port_base + reg);
+}
+
+static inline uint32_t read_register_dword(struct ne2k_device* netcard, uint8_t reg)
+{
+ return cdi_inl(netcard->port_base + reg);
+}
+
+void ne2k_init_device(struct cdi_device* device)
+{
+ struct ne2k_device* netcard = (struct ne2k_device*) device;
+ netcard->net.send_packet = ne2k_send_packet;
+
+ // PCI-bezogenes Zeug initialisieren
+ DEBUG_MSG("Interrupthandler und Ports registrieren");
+ cdi_register_irq(netcard->pci->irq, ne2k_handle_interrupt, device);
+ cdi_pci_alloc_ioports(netcard->pci);
+
+ cdi_list_t reslist = netcard->pci->resources;
+ struct cdi_pci_resource* res;
+ int i;
+ for (i = 0; (res = cdi_list_get(reslist, i)); i++) {
+ if (res->type == CDI_PCI_IOPORTS) {
+ netcard->port_base = res->start;
+ }
+ }
+
+ // Reset the card
+ DEBUG_MSG("Resetting the card");
+ write_register_byte(netcard, NE_CMD, 0x21);
+
+ // Enable 16-bit transfer, turn on monitor mode to avoid receiving packets
+ // and turn on loopback just in case. Receive logic is not ready yet.
+ write_register_byte(netcard, NE_DCR, 0x09);
+ write_register_byte(netcard, NE_RCR, 0x20);
+ write_register_byte(netcard, NE_TCR, 0x02);
+
+ // Disable card interrupts
+ write_register_byte(netcard, NE_ISR, 0xFF);
+ write_register_byte(netcard, NE_IMR, 0);
+
+ // Read the MAC address from PROM
+ write_register_byte(netcard, NE_RSAR0, 0);
+ write_register_byte(netcard, NE_RSAR1, 0);
+
+ write_register_byte(netcard, NE_RBCR0, 32);
+ write_register_byte(netcard, NE_RBCR1, 0);
+
+ write_register_byte(netcard, NE_CMD, 0x0A);
+
+ uint16_t prom[16];
+ uint8_t mac[6];
+ for(i = 0; i < 16; i++) {
+ prom[i] = read_register_word(netcard, NE_DATA);
+ }
+
+ // Set the MAC address for the system use
+ for(i = 0; i < 6; i++) {
+ mac[i] = (uint8_t) (prom[i] & 0xFF);
+ }
+ netcard->net.mac = (*(uint32_t*) (&mac[0])) | ((uint64_t) ((*(uint32_t*) (&mac[4])) & 0xFFFF) << 32);
+
+ // Setup the packet ring buffer
+ write_register_byte(netcard, NE_CMD, 0x61);
+ netcard->next_packet = PAGE_RX + 1;
+ write_register_byte(netcard, NE_CURR, netcard->next_packet);
+
+ write_register_byte(netcard, NE_CMD, 0x21);
+
+ write_register_byte(netcard, NE_PSTART, PAGE_RX);
+ write_register_byte(netcard, NE_BNDRY, PAGE_RX);
+ write_register_byte(netcard, NE_PSTOP, PAGE_STOP);
+
+ // Accept broadcast and runt packets
+ write_register_byte(netcard, NE_RCR, 0x06);
+ write_register_byte(netcard, NE_TCR, 0);
+
+ // Clear pending interrupts, enable them all, and begin card operation
+ write_register_byte(netcard, NE_ISR, 0xFF);
+ write_register_byte(netcard, NE_IMR, 0x3F);
+ write_register_byte(netcard, NE_CMD, 0x22);
+
+ netcard->pending_sends = cdi_list_create();
+
+ cdi_net_device_init((struct cdi_net_device*) device);
+ DEBUG_MSG("Fertig initialisiert");
+}
+
+void ne2k_remove_device(struct cdi_device* device)
+{
+}
+
+void ne2k_send_packet
+ (struct cdi_net_device* device, void* data, size_t size)
+{
+ struct ne2k_device* netcard = (struct ne2k_device*) device;
+
+ if (size > 0x700) {
+ // Spezialfall - keine Lust
+ printf("ne2k: size ist boese\n");
+ return;
+ }
+
+ if (!__sync_lock_test_and_set(&netcard->tx_in_progress, 1)) {
+ netcard->tx_in_progress = 1;
+ } else {
+ DEBUG_MSG("Tx-Buffer ist schon besetzt");
+
+ void* pending = malloc(size + sizeof(uint32_t));
+ cdi_list_insert(netcard->pending_sends,
+ cdi_list_size(netcard->pending_sends), pending);
+ *((uint32_t*) pending) = size;
+ pending += sizeof(uint32_t);
+ memcpy(pending, data, size);
+
+ return;
+ }
+
+ // Send the length/address for this write
+ write_register_byte(netcard, NE_RSAR0, 0);
+ write_register_byte(netcard, NE_RSAR1, PAGE_TX);
+
+ write_register_byte(netcard, NE_RBCR0, (size > 64) ? (size & 0xff) : 64);
+ write_register_byte(netcard, NE_RBCR1, size >> 8);
+
+ write_register_byte(netcard, NE_CMD, 0x12);
+
+ // Write to the NIC
+ uint16_t *p = (uint16_t*) data;
+ size_t i;
+ for(i = 0; (i + 1) < size; i += 2) {
+ write_register_word(netcard, NE_DATA, p[i/2]);
+ }
+
+ // Handle odd bytes
+ if(size & 1) {
+ write_register_byte(netcard, NE_DATA, p[i/2]);
+ i++;
+ }
+
+ // Pad to 64 bytes, if needed
+ for(; i < 64; i += 2) {
+ write_register_word(netcard, NE_DATA, 0);
+ }
+
+ // Await the transfer completion and then transmit
+ // FIXME: Should wait upon a mutex or something which is unlocked when
+ // the IRQ fires.
+ while(!(read_register_byte(netcard, NE_ISR) & 0x40));
+ write_register_byte(netcard, NE_ISR, 0x40);
+
+ write_register_byte(netcard, NE_TBCR0, (size > 64) ? (size & 0xff) : 64);
+ write_register_byte(netcard, NE_TBCR1, size >> 8);
+
+ write_register_byte(netcard, NE_TPSR, PAGE_TX);
+
+ write_register_byte(netcard, NE_CMD, 0x26);
+}
+
+static void receive_ok_handler(struct ne2k_device* netcard)
+{
+ DEBUG_MSG("ROK");
+
+ write_register_byte(netcard, NE_ISR, 0x1);
+
+ write_register_byte(netcard, NE_CMD, 0x61);
+ uint8_t current = read_register_byte(netcard, NE_CURR);
+ write_register_byte(netcard, NE_CMD, 0x21);
+
+ while (netcard->next_packet != current)
+ {
+ write_register_byte(netcard, NE_RSAR0, 0);
+ write_register_byte(netcard, NE_RSAR1, netcard->next_packet);
+
+ // 4 bytes - 2 for status, 2 for length
+ write_register_byte(netcard, NE_RBCR0, 4);
+ write_register_byte(netcard, NE_RBCR1, 0);
+
+ write_register_byte(netcard, NE_CMD, 0x0A);
+
+ uint16_t status = read_register_word(netcard, NE_DATA);
+ uint16_t length = read_register_word(netcard, NE_DATA);
+
+ if(!length) {
+ break;
+ }
+
+ // Remove status and length bytes
+ length -= 3;
+
+ if (length >= sizeof(struct eth_packet_header))
+ {
+ // Verify status
+ while(!(read_register_byte(netcard, NE_ISR) & 0x40));
+ write_register_byte(netcard, NE_ISR, 0x40);
+
+ // Read the packet
+ write_register_byte(netcard, NE_RSAR0, 4);
+ write_register_byte(netcard, NE_RSAR1, netcard->next_packet);
+ write_register_byte(netcard, NE_RBCR0, length & 0xFF);
+ write_register_byte(netcard, NE_RBCR1, (length >> 8) & 0xFF);
+
+ write_register_byte(netcard, NE_CMD, 0x0A);
+
+ uint16_t data[(length / 2) + 1];
+ int i, words = (length / 2);
+ for(i = 0; i < words; ++i) {
+ data[i] = read_register_word(netcard, NE_DATA);
+ }
+ if(length & 1) {
+ data[i] = read_register_word(netcard, NE_DATA) & 0xFF;
+ }
+
+ // Verify status
+ while(!(read_register_byte(netcard, NE_ISR) & 0x40));
+ write_register_byte(netcard, NE_ISR, 0x40);
+
+ netcard->next_packet = status >> 8;
+ write_register_byte(netcard, NE_BNDRY, (netcard->next_packet == PAGE_RX) ? (PAGE_STOP - 1) : (netcard->next_packet - 1));
+
+ cdi_net_receive(
+ (struct cdi_net_device*) netcard,
+ (uint8_t*) data,
+ length);
+ }
+ }
+}
+
+static void transmit_ok_handler(struct ne2k_device* netcard)
+{
+ DEBUG_MSG("TOK");
+ netcard->tx_in_progress = 0;
+}
+
+static void ne2k_handle_interrupt(struct cdi_device* device)
+{
+ DEBUG_MSG("<ne2k Interrupt>");
+
+ struct ne2k_device* netcard = (struct ne2k_device*) device;
+ uint32_t isr = read_register_word(netcard, NE_ISR);
+
+ // Packet received?
+ if(isr & 0x05) {
+ DEBUG_MSG("ne2k: received packet");
+ if(!(isr & 0x04)) {
+ write_register_byte(netcard, NE_IMR, 0x3A);
+ isr &= ~1;
+ receive_ok_handler(netcard);
+ write_register_byte(netcard, NE_IMR, 0x3F);
+ }
+ else {
+ DEBUG_MSG("ne2k: receive failed");
+ }
+ }
+
+ // Packet transmitted?
+ if(isr & 0x0A) {
+ if(!(isr & 0x8)) {
+ transmit_ok_handler(netcard);
+ }
+ }
+
+ // Overflows
+ if(isr & 0x10) {
+ DEBUG_MSG("ne2K: receive buffer overflow");
+ }
+ if(isr & 0x20) {
+ DEBUG_MSG("ne2K: counter overflow");
+ }
+
+ write_register_byte(netcard, NE_ISR, isr);
+
+ // Falls noch Pakete zu senden waren, die nicht gesendet werden
+ // konnten, weil die Karte beschaeftigt war, das jetzt nachholen
+ void* pending = cdi_list_pop(netcard->pending_sends);
+ if (pending) {
+ uint32_t size = *((uint32_t*) pending);
+ pending += sizeof(uint32_t);
+ DEBUG_MSG("Sende Paket aus der pending-Queue");
+ ne2k_send_packet((struct cdi_net_device*) device, pending, size);
+ free(pending - sizeof(uint32_t));
+ }
+
+ DEBUG_MSG("interrupt returns");
+}
--
1.5.6.3