diff options
Diffstat (limited to 'bsps/shared/net/cs8900.c.bsp')
-rw-r--r-- | bsps/shared/net/cs8900.c.bsp | 510 |
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]); +} |