summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/leon3/console/spacewire.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sparc/leon3/console/spacewire.c')
-rw-r--r--c/src/lib/libbsp/sparc/leon3/console/spacewire.c677
1 files changed, 677 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/leon3/console/spacewire.c b/c/src/lib/libbsp/sparc/leon3/console/spacewire.c
new file mode 100644
index 0000000000..a0460a4027
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/leon3/console/spacewire.c
@@ -0,0 +1,677 @@
+/*
+ * This file contains the TTY driver for the spacewire port on the LEON.
+ *
+ * This driver uses the termios pseudo driver.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * Modified for LEON3 BSP.
+ * COPYRIGHT (c) 2005.
+ * Gaisler Research.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * spacewire.c,v 1.1.2.1 2005/11/02 19:25:59 jiri Exp
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <sched.h>
+#include <ctype.h>
+#include <rtems/bspIo.h>
+
+#define DBGSPW_IOCALLS 1
+#define DBGSPW_TX 2
+#define DBGSPW_RX 4
+#define DBGSPW_IOCTRL 8
+#define DBGSPW_DUMP 16
+#define DEBUG_SPACEWIRE_FLAGS -1
+
+/*#define DEBUG_SPACEWIRE_ONOFF*/
+
+#ifdef DEBUG_SPACEWIRE_ONOFF
+int DEBUG_printf(const char *fmt, ...);
+#define SPACEWIRE_DBG(fmt, args...) \
+ do { \
+ { printf(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__,## args); } \
+ } while(0)
+#define SPACEWIRE_DBG2(fmt) \
+ do { \
+ { printf(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__); } \
+ } while(0)
+#define SPACEWIRE_DBGC(c,fmt, args...) \
+ do { \
+ if (DEBUG_SPACEWIRE_FLAGS&c) { \
+ printf(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__,## args); \
+ } \
+ } while(0)
+#else
+#define SPACEWIRE_DBG(fmt, args...)
+#define SPACEWIRE_DBG2(fmt, args...)
+#define SPACEWIRE_DBGC(fmt, args...)
+#endif
+
+int spacewire_hw_init(int minor);
+void spacewire_hw_send(int minor,unsigned char *b,int c);
+int spacewire_hw_receive(int minor,unsigned char *b,int c);
+int spacewire_hw_startup (int minor);
+int spacewire_hw_stop (int minor);
+void spacewire_hw_waitlink (int minor);
+void spacewire_rxnext(int minor);
+
+int _SPW_READ(void *addr) {
+ int tmp;
+ asm(" lda [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(addr)
+ );
+ return tmp;
+}
+
+rtems_device_driver spacewire_console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+);
+rtems_device_driver spacewire_console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+);
+rtems_device_driver spacewire_console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+);
+rtems_device_driver spacewire_console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+);
+rtems_device_driver spacewire_console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+);
+rtems_device_driver spacewire_console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+);
+
+#define SPWCEWIRE_CONSOLE_DRIVER_TABLE_ENTRY \
+ { spacewire_console_initialize, spacewire_console_open, \
+ spacewire_console_close, spacewire_console_read, \
+ spacewire_console_write, spacewire_console_control }
+
+static rtems_driver_address_table
+ spacewire_driver = SPWCEWIRE_CONSOLE_DRIVER_TABLE_ENTRY;
+
+void spacewire_register()
+{
+ rtems_status_code r;
+ rtems_device_major_number m;
+
+ SPACEWIRE_DBG2("register driver\n");
+ if ((r = rtems_io_register_driver(
+ 0,
+ &spacewire_driver,
+ &m)) == RTEMS_SUCCESSFUL) {
+ SPACEWIRE_DBG2("success\n");
+ } else {
+ switch(r) {
+ case RTEMS_TOO_MANY:
+ SPACEWIRE_DBG2("failed RTEMS_TOO_MANY\n"); break;
+ case RTEMS_INVALID_NUMBER:
+ SPACEWIRE_DBG2("failed RTEMS_INVALID_NUMBER\n"); break;
+ case RTEMS_RESOURCE_IN_USE:
+ SPACEWIRE_DBG2("failed RTEMS_RESOURCE_IN_USE\n"); break;
+ default:
+ SPACEWIRE_DBG("failed %i\n",r); break;
+ }
+ }
+}
+
+#ifdef SPW_BUFMALLOC
+void spacewire_buffer_alloc(int minor) {
+ if (SPW_PARAM(minor).ptr_rxbuf0) {
+ free(SPW_PARAM(minor).ptr_rxbuf0);
+ }
+ if (SPW_PARAM(minor).ptr_txbuf0) {
+ free(SPW_PARAM(minor).ptr_txbuf0);
+ }
+ SPW_PARAM(minor).ptr_rxbuf0 =
+ (char *) malloc(SPW_PARAM(minor).rxbufsize * SPW_PARAM(minor).rxbufcnt);
+ SPW_PARAM(minor).ptr_txbuf0 =
+ (char *) malloc(SPW_PARAM(minor).txbufsize * SPW_PARAM(minor).txbufcnt);
+}
+#endif
+
+/*
+ * Console Device Driver Entry Points
+ *
+ */
+
+SPACEWIRE_PARAM LEON3_Spacewire[SPACEWIRE_MAX_CORENR];
+
+rtems_device_driver spacewire_console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+ unsigned int iobar, conf;
+ int i, uarts;
+ char *console_name = "/dev/spacewire_a";
+ SPACEWIRE_DBG2("spacewire driver inizialisation\n");
+
+ rtems_termios_initialize();
+
+ /* Find spacewire cores */
+ i = 0; uarts = 0;
+ while (i < amba_conf.apbslv.devnr && uarts < SPACEWIRE_MAX_CORENR)
+ {
+ conf = amba_get_confword(amba_conf.apbslv, i, 0);
+ if ((amba_vendor(conf) == VENDOR_GAISLER) &&
+ (amba_device(conf) == GAISLER_SPACEWIRE))
+ {
+ iobar = amba_apb_get_membar(amba_conf.apbslv, i);
+ LEON3_Spacewire[uarts].regs =
+ (LEON3_SPACEWIRE_Regs_Map *) amba_iobar_start(amba_conf.apbmst, iobar);
+ LEON3_Spacewire[uarts].irq = amba_irq(conf);
+
+ SPACEWIRE_DBG("spacewire code at [0x%x]\n",
+ (unsigned int)LEON3_Spacewire[uarts].regs);
+
+ /* initialize the code with some resonable values,
+ actual initialization is done later using ioctl(fd)
+ on the opened device */
+ LEON3_Spacewire[uarts].nodeaddr = 0x14;
+ LEON3_Spacewire[uarts].destkey = 0xBF;
+ LEON3_Spacewire[uarts].maxfreq = 1;
+ LEON3_Spacewire[uarts].clkdiv = 0;
+ LEON3_Spacewire[uarts].rxmaxlen = SPACEWIRE_RXPCK_SIZE;
+ LEON3_Spacewire[uarts].txbufsize = SPACEWIRE_TXPCK_SIZE;
+ LEON3_Spacewire[uarts].rxbufsize = SPACEWIRE_RXPCK_SIZE;
+ LEON3_Spacewire[uarts].txbufcnt = SPACEWIRE_TXBUFS_NR;
+ LEON3_Spacewire[uarts].rxbufcnt = SPACEWIRE_RXBUFS_NR;
+
+#ifndef SPW_BUFMALLOC
+ LEON3_Spacewire[uarts].ptr_rxbuf0 = &LEON3_Spacewire[uarts]._rxbuf0;
+ LEON3_Spacewire[uarts].ptr_txbuf0 = &LEON3_Spacewire[uarts]._txbuf0;
+#else
+ LEON3_Spacewire[uarts].ptr_rxbuf0 = 0;
+ LEON3_Spacewire[uarts].ptr_txbuf0 = 0;
+ spacewire_buffer_alloc(uarts);
+#endif
+ uarts++;
+ }
+ i++;
+ }
+
+ /* Register Device Names, /dev/spacewire, /dev/spacewire_b ... */
+ if (uarts) {
+ SPACEWIRE_DBG2("registering minor 0 as /dev/spacewire\n");
+ status = rtems_io_register_name( "/dev/spacewire", major, 0 );
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred(status);
+ for (i = 1; i < uarts; i++) {
+ console_name[15]++;
+ SPACEWIRE_DBG("registering minor %i as %s\n",i,console_name);
+ status = rtems_io_register_name( console_name, major, i);
+ }
+ }
+
+ /* Initialize Hardware */
+ for (i = 0; i < uarts; i++) {
+ spacewire_hw_init(i);
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+int spacewire_setattibutes(int minor, int nodeaddr, int proto, int dest) {
+ if ( minor >= SPACEWIRE_MAX_CORENR ) {
+ printf("minor %i too big\n",minor);
+ return RTEMS_INVALID_NUMBER;
+ }
+ SPW_PARAM(minor).nodeaddr = nodeaddr;
+ SPW_PARAM(minor).proto = proto;
+ SPW_PARAM(minor).destnodeaddr = dest;
+ /*set node address*/
+ SPW_WRITE(&SPW_REG(minor,nodeaddr),SPW_PARAM(minor).nodeaddr);
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver spacewire_console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+){
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS,"open [%i,%i]\n",major, minor);
+ if ( minor >= SPACEWIRE_MAX_CORENR ) {
+ SPACEWIRE_DBG("minor %i too big\n",minor);
+ return RTEMS_INVALID_NUMBER;
+ }
+ return spacewire_hw_startup(minor);
+}
+
+rtems_device_driver spacewire_console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS,"close [%i,%i]\n",major, minor);
+ spacewire_hw_stop(minor);
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver spacewire_console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_rw_args_t *rw_args;
+ unsigned32 count = 0;
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS,"read [%i,%i]: buf:0x%x len:%i \n",
+ major, minor, (unsigned int)rw_args->buffer,rw_args->count);
+
+ count = spacewire_hw_receive(minor,rw_args->buffer,rw_args->count);
+
+#ifdef DEBUG_SPACEWIRE_ONOFF
+ if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
+ int k;
+ for (k = 0;k < count;k++){
+ if (k % 16 == 0) {
+ printf ("\n");
+ }
+ printf ("%.2x(%c) ",rw_args->buffer[k] & 0xff,
+ isprint(rw_args->buffer[k] & 0xff) ? rw_args->buffer[k] & 0xff : ' ');
+ }
+ printf ("\n");
+ }
+#endif
+
+ rw_args->bytes_moved = count;
+ return RTEMS_SUCCESSFUL;
+
+}
+
+rtems_device_driver spacewire_console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_rw_args_t *rw_args;
+ int count = 0;
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS,"write [%i,%i]: buf:0x%x len:%i\n",
+ major, minor, (unsigned int)rw_args->buffer,rw_args->count);
+
+ while (rw_args->count > 0) {
+ int c = rw_args->count;
+ if (c > SPW_PARAM(minor).txbufsize-2) {
+ c = SPW_PARAM(minor).txbufsize-2;
+ }
+ spacewire_hw_send(minor,rw_args->buffer,c);
+ rw_args->count -= c;
+ rw_args->buffer += c;
+ count += c;
+ }
+
+ if (count >= 0) {
+ rw_args->bytes_moved = count;
+ return RTEMS_SUCCESSFUL;
+ }
+ return RTEMS_UNSATISFIED;
+}
+
+rtems_device_driver spacewire_console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+ SPACEWIRE_DBGC(DBGSPW_IOCALLS,"ctrl [%i,%i]\n",major, minor);
+
+ if (!ioarg)
+ return RTEMS_INVALID_ADDRESS;
+
+ switch(ioarg->command) {
+ case SPACEWIRE_IOCTRL_SET_NODEADDR:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_NODEADDR %i\n",
+ ioarg->buffer);
+ SPW_PARAM(minor).nodeaddr = (unsigned int) ioarg->buffer;
+ /*set node address*/
+ SPW_WRITE(&SPW_REG(minor,nodeaddr),SPW_PARAM(minor).nodeaddr);
+ break;
+ case SPACEWIRE_IOCTRL_SET_PROTOCOL:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_PROTOCOL %i\n",
+ ioarg->buffer);
+ SPW_PARAM(minor).proto = (unsigned int) ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_SET_DESTNODEADDR:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DESTNODEADDR %i\n",
+ ioarg->buffer);
+ SPW_PARAM(minor).destnodeaddr = (unsigned int) ioarg->buffer;
+ break;
+ case SPACEWIRE_IOCTRL_GET_COREBASEADDR:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_BASEADDR=%i\n",
+ (unsigned int)SPW_PARAM(minor).regs);
+ *(unsigned int *)ioarg->buffer = (unsigned int )SPW_PARAM(minor).regs;
+ break;
+ case SPACEWIRE_IOCTRL_GET_COREIRQ:
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_COREIRQ=%i\n",
+ (unsigned int)SPW_PARAM(minor).irq);
+ *(unsigned int *)ioarg->buffer = (unsigned int )SPW_PARAM(minor).irq;
+ break;
+#ifdef SPW_BUFMALLOC
+ case SPACEWIRE_IOCTRL_SET_PACKETSIZE:
+ {
+ spw_ioctl_packetsize *ps = (spw_ioctl_packetsize*)ioarg->buffer;
+ SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RXPACKETSIZE \n",
+ ioarg->buffer);
+ spacewire_hw_stop(minor);
+ SPW_PARAM(minor).rxbufsize = ps->rxsize;
+ SPW_PARAM(minor).txbufsize = ps->txsize;
+ SPW_PARAM(minor).rxmaxlen = SPW_PARAM(minor).rxbufsize;
+ spacewire_buffer_alloc(minor);
+ spacewire_hw_startup(minor);
+ }
+ break;
+#endif
+ case SPACEWIRE_IOCTRL_GETPACKET: {
+ spw_ioctl_packet *p = (spw_ioctl_packet*)ioarg->buffer;
+ p->ret_size = spacewire_hw_receive(minor,p->buf,p->buf_size);
+ }
+ break;
+ case SPACEWIRE_IOCTRL_PUTPACKET:{
+ spw_ioctl_packet *p = (spw_ioctl_packet*)ioarg->buffer;
+ spacewire_hw_send(minor,p->buf,p->buf_size);
+ }
+ break;
+ default:
+ return RTEMS_NOT_DEFINED;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/* ========================================================================== */
+
+int spacewire_set_rxmaxlen(int minor) {
+ unsigned int rxmax;
+ /*set rx maxlength*/
+ SPW_WRITE(&SPW_REG(minor,dma0rxmax),SPW_PARAM(minor).rxmaxlen);
+ rxmax = SPW_READ(&SPW_REG(minor,dma0rxmax));
+ if (rxmax != SPW_PARAM(minor).rxmaxlen) {
+ printf("spacewire: error initializing rx max len (0x%x, read: 0x%x)\n",
+ SPW_PARAM(minor).rxmaxlen,rxmax);
+ return 0;
+ }
+ return 1;
+}
+
+int spacewire_hw_init(int minor) {
+ unsigned int dma0ctrl;
+ int ctrl = SPW_CTRL_READ(minor);
+
+ SPW_PARAM(minor).rx = (SPACEWIRE_RXBD *)
+ SPW_ALIGN(&SPW_PARAM(minor)._rxtable,SPACEWIRE_BDTABLE_SIZE);
+ SPW_PARAM(minor).tx = (SPACEWIRE_TXBD *)
+ SPW_ALIGN(&SPW_PARAM(minor)._txtable,SPACEWIRE_BDTABLE_SIZE);
+
+ SPACEWIRE_DBG("hw_init [minor %i]\n", minor);
+
+ SPW_PARAM(minor).is_rmap = ctrl & SPACEWIRE_CTRL_RA;
+ SPW_PARAM(minor).is_rxunaligned = ctrl & SPACEWIRE_CTRL_RX;
+ SPW_PARAM(minor).is_rmapcrc = ctrl & SPACEWIRE_CTRL_RC;
+
+ /*set node address*/
+ SPW_WRITE(&SPW_REG(minor,nodeaddr),SPW_PARAM(minor).nodeaddr);
+
+ /*set clock divisor*/
+ SPW_WRITE(&SPW_REG(minor,clockdiv),SPW_PARAM(minor).clkdiv);
+ if (SPW_PARAM(minor).is_rmap) {
+ SPW_WRITE(&SPW_REG(minor,destkey),SPW_PARAM(minor).destkey);
+ }
+ SPW_WRITE(
+ &SPW_REG(minor,dma0ctrl),
+ /*clear status, set ctrl for dma chan*/
+ SPACEWIRE_DMACTRL_PS|SPACEWIRE_DMACTRL_PR|
+ SPACEWIRE_DMACTRL_TA|SPACEWIRE_DMACTRL_RA
+ );
+ if ((dma0ctrl = SPW_READ(&SPW_REG(minor,dma0ctrl))) != 0) {
+ printf("spacewire: error initializing dma ctrl (0x%x)\n",dma0ctrl);
+ }
+
+ SPW_CTRL_WRITE(minor, SPACEWIRE_CTRL_RESET ); /*set ctrl*/
+ SPW_CTRL_WRITE(minor,
+ SPACEWIRE_CTRL_LINKSTART | (SPW_PARAM(minor).maxfreq << 5)); /*set ctrl*/
+ return 0;
+}
+
+void spacewire_hw_waitlink (int minor) {
+ int j;
+ while (SPW_LINKSTATE(SPW_STATUS_READ(minor)) != 5) {
+ rtems_task_wake_after(100);
+ sched_yield();
+ printf("timeout loop dev %i\n",minor);
+ j++;
+ }
+}
+
+int spacewire_hw_startup (int minor) {
+ int i,j;
+ unsigned int dmactrl;
+ SPW_STATUS_WRITE(minor,0xFF); /*clear status*/
+ SPW_CTRL_WRITE(minor, SPACEWIRE_CTRL_RESET ); /*set ctrl*/
+ SPW_CTRL_WRITE(minor,
+ SPACEWIRE_CTRL_LINKSTART | (SPW_PARAM(minor).maxfreq << 5)); /*set ctrl*/
+ sched_yield();
+ j = 0; i = 0;
+ spacewire_hw_waitlink(minor);
+
+ /* prepare transmit buffers */
+ for (i = 0; i < SPW_PARAM(minor).txbufcnt;i++) {
+ if (i+1 == SPW_PARAM(minor).txbufcnt) {
+ SPW_PARAM(minor).tx[i].ctrl = 0|SPACEWIRE_TXBD_WR;
+ } else {
+ SPW_PARAM(minor).tx[i].ctrl = 0;
+ }
+ SPW_PARAM(minor).tx[i].addr_data =
+ ((unsigned int)&SPW_PARAM(minor).ptr_txbuf0[0]) +
+ (i * SPW_PARAM(minor).txbufsize);
+ }
+ SPW_PARAM(minor).txcur = 0;
+
+ /* prepare receive buffers */
+ for (i = 0; i < SPW_PARAM(minor).rxbufcnt;i++) {
+ if (i+1 == SPW_PARAM(minor).rxbufcnt) {
+ SPW_PARAM(minor).rx[i].ctrl = SPACEWIRE_RXBD_EN|SPACEWIRE_RXBD_WR;
+ } else {
+ SPW_PARAM(minor).rx[i].ctrl = SPACEWIRE_RXBD_EN;
+ }
+ SPW_PARAM(minor).rx[i].addr =
+ ((unsigned int)&SPW_PARAM(minor).ptr_rxbuf0[0]) +
+ (i * SPW_PARAM(minor).rxbufsize);
+ }
+ SPW_PARAM(minor).rxcur = 0;
+ SPW_PARAM(minor).rxbufcur = -1;
+ spacewire_set_rxmaxlen(minor);
+
+ SPW_WRITE(&SPW_REG(minor,dma0txdesc),(unsigned int)SPW_PARAM(minor).tx);
+ SPW_WRITE(&SPW_REG(minor,dma0rxdesc),(unsigned int)SPW_PARAM(minor).rx);
+
+ /* start RX */
+ dmactrl = SPW_READ(&SPW_REG(minor,dma0ctrl));
+ SPW_WRITE(&SPW_REG(minor,dma0ctrl),
+ (dmactrl & SPACEWIRE_PREPAREMASK_RX) |
+ SPACEWIRE_DMACTRL_RD | SPACEWIRE_DMACTRL_RXEN);
+
+ SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: setup complete\n",SPW_PARAM(minor).regs);
+ return RTEMS_SUCCESSFUL;
+}
+
+int spacewire_hw_stop (int minor) {
+ unsigned int dmactrl;
+
+ /* stop RX */
+ dmactrl = SPW_READ(&SPW_REG(minor,dma0ctrl));
+ SPW_WRITE(&SPW_REG(minor,dma0ctrl),
+ (dmactrl & SPACEWIRE_PREPAREMASK_RX) &
+ ~(SPACEWIRE_DMACTRL_RD |SPACEWIRE_DMACTRL_RXEN));
+
+ /* stop link */
+ SPW_CTRL_WRITE(minor,
+ (SPW_CTRL_READ(minor) & 0x3FD) | SPACEWIRE_CTRL_LINKDISABLE);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+void spacewire_hw_send(int minor,unsigned char *b,int c) {
+
+ unsigned int dmactrl, ctrl;
+ unsigned int cur = SPW_PARAM(minor).txcur;
+ char *txb = SPW_PARAM(minor).ptr_txbuf0 + (cur * SPW_PARAM(minor).txbufsize);
+
+ sched_yield();
+ memcpy(&txb[2],b,c);
+
+ txb[0] = SPW_PARAM(minor).destnodeaddr;
+ txb[1] = SPW_PARAM(minor).proto;
+
+#ifdef DEBUG_SPACEWIRE_ONOFF
+ if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
+ int k;
+ for (k = 0;k < c+2;k++){
+ if (k % 16 == 0) {
+ printf ("\n");
+ }
+ printf ("%.2x(%c) ",txb[k] & 0xff,
+ isprint(txb[k] & 0xff) ? txb[k] & 0xff : ' ');
+ }
+ printf ("\n");
+ }
+#endif
+
+ do {
+ SPW_PARAM(minor).tx[0].addr_header = 0;
+ SPW_PARAM(minor).tx[0].len = c+2;
+ SPW_PARAM(minor).tx[0].addr_data = (unsigned int)txb;
+ SPW_PARAM(minor).tx[0].ctrl = SPACEWIRE_TXBD_WR|SPACEWIRE_TXBD_EN;
+
+ dmactrl = SPW_READ(&SPW_REG(minor,dma0ctrl));
+ SPW_WRITE(&SPW_REG(minor,dma0ctrl),
+ (dmactrl & SPACEWIRE_PREPAREMASK_TX) | SPACEWIRE_DMACTRL_TXEN);
+
+ while((ctrl = SPW_READ((volatile void *)&SPW_PARAM(minor).tx[0].ctrl)) &
+ SPACEWIRE_TXBD_EN) {
+ sched_yield();
+ }
+ if (ctrl & SPACEWIRE_TXBD_LE) {
+ printf("tx error: SPACEWIRE_TXBD_LE, link error\n");
+ }
+ } while(ctrl & SPACEWIRE_TXBD_ERROR);
+
+ SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: transmitted <%i> bytes\n",
+ SPW_PARAM(minor).regs,c+2);
+}
+
+int spacewire_hw_receive(int minor,unsigned char *b,int c) {
+ unsigned int count = 0, len, rxlen, ctrl;
+ unsigned int cur = SPW_PARAM(minor).rxcur;
+ char *rxb = SPW_PARAM(minor).ptr_rxbuf0 + (cur * SPW_PARAM(minor).rxbufsize);
+
+ SPACEWIRE_DBGC(DBGSPW_RX,"0x%x: waitin packet at pos %i\n",
+ SPW_PARAM(minor).regs,cur);
+
+ sched_yield();
+
+ while(1) {
+ ctrl = SPW_READ((volatile void *)&SPW_PARAM(minor).rx[cur].ctrl);
+ if (!(ctrl & SPACEWIRE_RXBD_EN)) {
+ break;
+ }
+ if (SPW_LINKSTATE(SPW_STATUS_READ(minor)) != 5) {
+ return 0;
+ }
+ sched_yield();
+ }
+ SPACEWIRE_DBGC(DBGSPW_RX,"checking packet\n",0);
+
+ len = SPACEWIRE_RXBD_LENGTH(ctrl);
+ if (!(ctrl & (SPACEWIRE_RXBD_ERROR & ~SPACEWIRE_RXBD_RMAPERROR))) {
+
+ if (SPW_PARAM(minor).rxbufcur == -1) {
+ SPACEWIRE_DBGC(DBGSPW_RX,"incoming packet len %i\n",len);
+ SPW_PARAM(minor).rxbufcur = 2;
+ }
+ rxlen = len - SPW_PARAM(minor).rxbufcur;
+ if (rxlen > c) {
+ rxlen = c;
+ }
+ memcpy(b,rxb+SPW_PARAM(minor).rxbufcur,rxlen);
+ count += rxlen;
+ b += rxlen;
+ c -= rxlen;
+ SPW_PARAM(minor).rxbufcur += rxlen;
+ } else {
+ if (ctrl & SPACEWIRE_RXBD_EEP) {
+ printf("rx error: SPACEWIRE_RXBD_EEP, error end of packet\n");
+ }
+ if (ctrl & SPACEWIRE_RXBD_EHC) {
+ printf("rx error: SPACEWIRE_RXBD_EHC, header crc error\n");
+ }
+ if (ctrl & SPACEWIRE_RXBD_EDC) {
+ printf("rx error: SPACEWIRE_RXBD_EDC, crc error\n");
+ }
+ if (ctrl & SPACEWIRE_RXBD_ETR) {
+ printf("rx error: SPACEWIRE_RXBD_ETR, truncated\n");
+ }
+ }
+
+ if (SPW_PARAM(minor).rxbufcur == len ||
+ (ctrl & (SPACEWIRE_RXBD_ERROR & ~SPACEWIRE_RXBD_RMAPERROR))) {
+ spacewire_rxnext(minor);
+ }
+ return count;
+}
+
+void spacewire_rxnext(int minor) {
+
+ unsigned int dmactrl;
+ unsigned int cur = SPW_PARAM(minor).rxcur;
+ unsigned int ctrl = SPW_READ((volatile void *)&SPW_PARAM(minor).rx[cur].ctrl);
+ int cur2 = cur;
+ cur++;
+ if (cur >= SPACEWIRE_RXBUFS_NR) {
+ cur = 0;
+ ctrl |= SPACEWIRE_RXBD_WR;
+ }
+ SPW_PARAM(minor).rx[cur2].ctrl = ctrl | SPACEWIRE_RXBD_EN;
+
+ SPW_PARAM(minor).rxcur = cur;
+ SPW_PARAM(minor).rxbufcur = -1;
+
+ /* start RX */
+ dmactrl = SPW_READ(&SPW_REG(minor,dma0ctrl));
+ SPW_WRITE(&SPW_REG(minor,dma0ctrl),
+ (dmactrl & SPACEWIRE_PREPAREMASK_RX) | SPACEWIRE_DMACTRL_RD |
+ SPACEWIRE_DMACTRL_RXEN);
+
+}