diff options
Diffstat (limited to 'c/src/lib/libbsp/sparc/leon3/console/spacewire.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/leon3/console/spacewire.c | 677 |
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); + +} |