summaryrefslogtreecommitdiff
path: root/bsps/shared/net/cs8900.c.bsp
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/shared/net/cs8900.c.bsp')
-rw-r--r--bsps/shared/net/cs8900.c.bsp510
1 files changed, 510 insertions, 0 deletions
diff --git a/bsps/shared/net/cs8900.c.bsp b/bsps/shared/net/cs8900.c.bsp
new file mode 100644
index 0000000..7b7374a
--- /dev/null
+++ b/bsps/shared/net/cs8900.c.bsp
@@ -0,0 +1,510 @@
+/*
+ * RTEMS CS8900 Driver Setup for the DIMM-PC/i386 made by Kontron.
+ *
+ * Port to the DIMM PC copyright (c) 2004 Angelo Fraietta
+ * This project has been assisted by the Commonwealth Government
+ * through the Australia Council, its arts funding and advisory body.
+ *
+ * Port performed by Chris Johns, Cybertec Pty Ltd, Jan 2004.
+ * Based on the Cybertec CS8900 driver setup for the SFP-101.
+ *
+ */
+
+#define CS8900_VERBOSE 0
+#define HAVE_MRB_CS8900_DATA_BUS_SWAPPED 1
+
+#include <bsp.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+
+#include <rtems.h>
+#include <rtems/monitor.h>
+#include <rtems/rtems_bsdnet.h>
+#include <irq.h>
+
+#include "cs8900.h"
+
+#include <net/route.h>
+
+/*
+ * Loopback interface.
+ */
+
+extern int rtems_bsdnet_loopattach (struct rtems_bsdnet_ifconfig *, int);
+
+static struct rtems_bsdnet_ifconfig loopback_config =
+{
+ "lo0", /* name */
+ rtems_bsdnet_loopattach, /* attach function */
+ NULL, /* link to next interface */
+ "127.0.0.1", /* IP address */
+ "255.0.0.0", /* IP net mask */
+};
+
+/*
+ * Network configuration
+ */
+
+struct rtems_bsdnet_config rtems_bsdnet_config =
+{
+ &loopback_config,
+ NULL,
+ 20, /* Network task priority */
+ 32 * 1024, /* Mbuf capacity */
+ 96 * 1024, /* Mbuf cluster capacity */
+};
+
+
+static void cs8900_isr ();
+static void cs8900_int_off (const rtems_irq_connect_data* unused);
+static void cs8900_int_on (const rtems_irq_connect_data* unused);
+static int cs8900_int_is_on (const rtems_irq_connect_data *irq);
+
+/**
+ * The device's data.
+ */
+static cs8900_device cs8900;
+static rtems_irq_connect_data cs8900_irq =
+{
+ 0,
+ cs8900_isr,
+ cs8900_int_on,
+ cs8900_int_off,
+ cs8900_int_is_on
+};
+
+#if CS8900_VERBOSE
+static int cs8900_io_verbose = 1;
+#endif
+
+/**
+ * Device structure for attaching to the BSD stack.
+ */
+static struct rtems_bsdnet_ifconfig cs8900_ifconfig =
+{
+ "cs0", /* name */
+ cs8900_driver_attach, /* attach funtion */
+ NULL, /* next interface */
+ NULL, /* ip address */
+ NULL, /* ip netmask */
+ NULL, /* hardware address */
+ 0, /* ignore broadcast */
+ 0, /* mtu */
+ 0, /* rbuf count */
+ 0, /* xbuf count */
+ 0, /* port */
+ 0, /* irno */
+ 0, /* bpar */
+ 0 /* drv ctrl */
+};
+
+
+/*
+ * Commands to register.
+ */
+
+rtems_monitor_command_entry_t rtems_bsdnet_commands[] =
+{
+ {
+ "ifstats",
+ "Show the interface stats.\n",
+ 0,
+ (void*) rtems_bsdnet_show_if_stats,
+ 0,
+ 0,
+ },
+ {
+ "ipstats",
+ "Show the IP stats.\n",
+ 0,
+ (void*) rtems_bsdnet_show_ip_stats,
+ 0,
+ 0,
+ },
+ {
+ "routes",
+ "Show the inet routes.\n",
+ 0,
+ (void*) rtems_bsdnet_show_inet_routes,
+ 0,
+ 0,
+ },
+ {
+ "mbufs",
+ "Show the mbuf stats.\n",
+ 0,
+ (void*) rtems_bsdnet_show_mbuf_stats,
+ 0,
+ 0,
+ },
+ {
+ "icmp",
+ "Show the ICMP stats.\n",
+ 0,
+ (void*) rtems_bsdnet_show_icmp_stats,
+ 0,
+ 0,
+ },
+ {
+ "udp",
+ "Show the UDP stats.\n",
+ 0,
+ (void*) rtems_bsdnet_show_udp_stats,
+ 0,
+ 0,
+ },
+ {
+ "tcp",
+ "Show the TCP stats.\n",
+ 0,
+ (void*) rtems_bsdnet_show_tcp_stats,
+ 0,
+ 0,
+ }
+};
+
+static void
+cs8900_isr ()
+{
+ /*
+ * Note: we could have a high priority task here to call the
+ * drivers handler. The would lower the interrupt latancy
+ * we aother wise have.
+ */
+ cs8900_interrupt (cs8900_irq.name, &cs8900);
+}
+
+static void
+cs8900_int_on (const rtems_irq_connect_data *unused)
+{
+}
+
+static void
+cs8900_int_off (const rtems_irq_connect_data *unused)
+{
+}
+
+static int
+cs8900_int_is_on (const rtems_irq_connect_data *irq)
+{
+ return BSP_irq_enabled_at_i8259s (irq->name);
+}
+
+void cs8900_io_set_reg (cs8900_device *cs, unsigned short reg, unsigned short data)
+{
+#if CS8900_VERBOSE
+ if (cs8900_io_verbose)
+ printk ("CS8900: io set reg=0x%04x, data=0x%04x\n", reg, data);
+#endif
+ outport_word (cs->io_base + reg, data);
+}
+
+unsigned short cs8900_io_get_reg (cs8900_device *cs, unsigned short reg)
+{
+ unsigned short data;
+ inport_word (cs->io_base + reg, data);
+#if CS8900_VERBOSE
+ if (cs8900_io_verbose)
+ printk ("CS8900: io get reg=0x%04x, data=0x%04x\n", reg, data);
+#endif
+ return data;
+}
+
+void cs8900_mem_set_reg (cs8900_device *cs, unsigned long reg, unsigned short data)
+{
+ printk ("CS8900: mem_set_reg register access called. Only IO supported.\n");
+ while (1);
+}
+
+unsigned short cs8900_mem_get_reg (cs8900_device *cs, unsigned long reg)
+{
+ printk ("CS8900: mem_get_reg register access called. Only IO supported.\n");
+ while (1);
+ return 0;
+}
+
+void cs8900_put_data_block (cs8900_device *cs, int len, unsigned char *data)
+{
+ unsigned short *src = (unsigned short *) ((unsigned long) data);
+
+ for (; len > 1; len -= 2)
+ outport_word (cs->io_base, *src++);
+
+ if (len)
+ outport_word (cs->io_base, *src++);
+}
+
+unsigned short cs8900_get_data_block (cs8900_device *cs, unsigned char *data)
+{
+ unsigned short *dst;
+ int cnt;
+ int len;
+
+ /*
+ * Drop the Rx status first.
+ */
+ inport_word (cs->io_base, len);
+
+ /*
+ * Now the length.
+ */
+ inport_word (cs->io_base, len);
+
+ dst = (unsigned short *) ((unsigned long) data);
+ cnt = len >> 1;
+
+ while (cnt--)
+ inport_word (cs->io_base, *dst++);
+
+ if (len & 1)
+ inport_word (cs->io_base, *dst++);
+
+ return len;
+}
+
+void
+cs8900_tx_load (cs8900_device *cs, struct mbuf *m)
+{
+ unsigned int len;
+ unsigned char *src = 0;
+ unsigned short *wsrc = 0;
+ unsigned char remainder = 0;
+ unsigned char word[2];
+
+ while (m)
+ {
+ /*
+ * We can get empty mbufs from the stack.
+ */
+
+ len = m->m_len;
+ src = mtod (m, unsigned char*);
+
+ if (len)
+ {
+ if (remainder)
+ {
+#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
+ word[1] = *src++;
+#else
+ word[0] = *src++;
+#endif
+ outport_word (cs->io_base, *((unsigned short*) (unsigned long) &word));
+ len--;
+ remainder = 0;
+ }
+
+ if (len & 1)
+ {
+ remainder = 1;
+ len--;
+ }
+
+ wsrc = (unsigned short*) src;
+
+ for (; len; len -= 2, src += 2)
+ outport_word (cs->io_base, *wsrc++);
+
+ if (remainder)
+#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
+ word[0] = *src++;
+#else
+ word[1] = *src++;
+#endif
+ }
+
+ m = m->m_next;
+ }
+
+ if (remainder)
+ {
+#if HAVE_MRB_CS8900_DATA_BUS_SWAPPED
+ word[1] = *src++;
+#else
+ word[0] = *src++;
+#endif
+ outport_word (cs->io_base, *((unsigned short*) (unsigned long) &word));
+ }
+}
+
+void cs8900_attach_interrupt (cs8900_device *cs)
+{
+ BSP_install_rtems_irq_handler (&cs8900_irq);
+}
+
+void cs8900_detach_interrupt (cs8900_device *cs)
+{
+ BSP_remove_rtems_irq_handler (&cs8900_irq);
+}
+
+void
+BSP_cs8900_attach (unsigned long io_base, unsigned long mem_base, int intrp,
+ const char* ip, const char* nm, const char* gw)
+{
+ cs8900_device *cs = &cs8900;
+ int flags;
+ struct sockaddr_in address;
+ struct sockaddr_in netmask;
+ struct sockaddr_in broadcast;
+ struct sockaddr_in gateway;
+ int cmd;
+
+ printf ("cso: io=0x%0lx mem=0 irq=%d\n", io_base, intrp);
+
+ memset (cs, 0, sizeof (cs8900));
+
+ cs->dev = 0;
+ cs->rx_queue_size = 30;
+ cs->io_base = io_base;
+
+ if (mem_base)
+ printf ("cs8900: memory mode is currently not supported.\n");
+
+ cs->mem_base = 0;
+
+ switch (intrp)
+ {
+ case 5:
+ cs->irq_level = 3;
+ break;
+ case 10:
+ cs->irq_level = 0;
+ break;
+ case 11:
+ cs->irq_level = 1;
+ break;
+ case 12:
+ cs->irq_level = 2;
+ break;
+ default:
+ printf ("cs8900: unsupported IRQ level\n");
+ return;
+ }
+
+ cs8900_irq.name = intrp;
+
+ /*
+ * Get the MAC adress from the CS8900.
+ */
+
+ cs8900_get_mac_addr (cs, cs->mac_address);
+
+ /*
+ * Setup the BSD interface configure structure.
+ */
+
+ cs8900_ifconfig.drv_ctrl = cs;
+ cs8900_ifconfig.hardware_address = cs->mac_address;
+
+ printf ("CS8900 initialisation\n");
+
+ rtems_bsdnet_attach (&cs8900_ifconfig);
+
+ /*
+ * Configure the interface using the boot configuration.
+ */
+
+ flags = IFF_UP;
+ if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
+ SIOCSIFFLAGS,
+ &flags) < 0)
+ {
+ printf ("error: can't bring up %s: %s\n",
+ cs8900_ifconfig.name, strerror (errno));
+ return;
+ }
+
+ if (ip && strlen (ip) && nm && strlen (nm))
+ {
+ printf ("%s: addr: %s netmask: %s gateway: %s\n",
+ cs8900_ifconfig.name, ip, nm, gw ? gw : "none");
+
+ memset (&netmask, '\0', sizeof netmask);
+ netmask.sin_len = sizeof netmask;
+ netmask.sin_family = AF_INET;
+
+ if (!inet_aton (nm, &netmask.sin_addr))
+ {
+ printf ("error: cannot parse the network mask: %s\n", nm);
+ return;
+ }
+
+ memset (&address, '\0', sizeof address);
+ address.sin_len = sizeof address;
+ address.sin_family = AF_INET;
+
+ if (!inet_aton (ip, &address.sin_addr))
+ {
+ printf ("error: cannot parse the ip address: %s\n", ip);
+ return;
+ }
+
+ if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
+ SIOCSIFNETMASK,
+ &netmask) < 0)
+ {
+ printf ("error: can't set %s netmask: %s\n",
+ cs8900_ifconfig.name, strerror (errno));
+ return;
+ }
+
+ if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
+ SIOCSIFADDR,
+ &address) < 0)
+ {
+ printf ("error: can't set %s address: %s\n",
+ cs8900_ifconfig.name, strerror (errno));
+ return;
+ }
+
+ memset (&broadcast, '\0', sizeof broadcast);
+ broadcast.sin_len = sizeof broadcast;
+ broadcast.sin_family = AF_INET;
+ broadcast.sin_addr.s_addr =
+ (address.sin_addr.s_addr & netmask.sin_addr.s_addr) | ~netmask.sin_addr.s_addr;
+
+ if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
+ SIOCSIFBRDADDR,
+ &broadcast) < 0)
+ {
+ printf ("error: can't set %s broadcast address: %s\n",
+ cs8900_ifconfig.name, strerror (errno));
+ return;
+ }
+
+ if (gw && strlen (gw))
+ {
+ address.sin_addr.s_addr = INADDR_ANY;
+ netmask.sin_addr.s_addr = INADDR_ANY;
+ memset (&gateway, '\0', sizeof gateway);
+ gateway.sin_len = sizeof gateway;
+ gateway.sin_family = AF_INET;
+
+ if (!inet_aton (gw, &gateway.sin_addr))
+ printf ("warning: cannot parse the gateway address: %s\n", ip);
+ else
+ {
+ if (rtems_bsdnet_rtrequest (RTM_ADD,
+ (struct sockaddr *) &address,
+ (struct sockaddr *) &gateway,
+ (struct sockaddr *) &netmask,
+ (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL) < 0)
+ printf ("error: can't set default route: %s\n", strerror (errno));
+ }
+ }
+ }
+ else
+ {
+ rtems_bsdnet_do_bootp_and_rootfs ();
+ }
+
+ for (cmd = 0;
+ cmd < sizeof (rtems_bsdnet_commands) / sizeof (rtems_monitor_command_entry_t);
+ cmd++)
+ rtems_monitor_insert_cmd (&rtems_bsdnet_commands[cmd]);
+}