summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/1553/b1553brm.c
blob: 045146a58b7ed97c2ae5edc675ebd92d496acfdc (plain) (tree)
1
2
3
4
5
6
7
8
9
  
              





                                                           
                                         













                                       
                                                               







                                                              

                                 








                                                                               

                                    












                                   













                                                    
                                       






                                           
                 




                               
                     





                                                                     
                                    




































                                                                                                                       




                                    
                






                              
                                     


















                                                                                                     
 











                                                                               
                                                         
















                                                                            
 







                                                        

 

                                                                                 
 
                                                                
                                                         
















                                                                                 
 







                                                          

 

                                                                                            
 
                                                                
                                                         





                                               
                                 


















                                            
            


                                                     
 







                                                                                                                                       
                                   




                                          
                                 
                                                              
      









                                                    
     

























                                                       
                                                       








                                                       
                                                       



      


                               
                                                                                                                       




                                 
 





                                                                
 


                                                        
                                   
      
 



                                                                    
 






































                                                                                          
 



                                                                                         
 




                                                              
                                                                       









                                                                                                                        
 






                                             

                                



                                                                                                                 
 




                                                                                                                    
                                                                                                                           

















                                                                                                                            
         







                                                                                                                            
 













                                                  
 

                                      
                                                                       
 

                                                
 









                                                                                                                               
 
                                   
 
                                
 














                                                   
 

                          
 
                                                                                            
 





                                                              
                                                                     












                                                                                      
 
                                   
 
                                
 









                                                                                                                      
                                       
                  
 



                                         
 
                                  
                                                                                               




                                                                
 
                                                        
                                                         



                                                                


                                                        



                                                       
                                             

                                                                              
                                                                                                         




                                                                        
 









                                                                       
 
                                                             

                                                                           
 





                                                     
                               

                                                    
 

                                                   
 
                                                                                                      
 



                                                                       
 


                                                                                       
                                                                                                                                  








                                                                                       
                                                                                                                                  








                                                                                       
                                                                                                                                  





                                                              
 



                                                                           
                                                                                                     
 

                                     
 



                                                                                    
 

                                                                                       
 
                             
 

                                                               
 

                                            
 
                                          
 




                                                                                                                  
 





                                              
 
                                   
 



                                                                                                    
 

                                  
 
                         
 

                            
 









                                                                                                                 
 













































                                                                                                                
 


                                                                   
 
                                            
 























                                                                                                                
 








                                                                                                                 
 


                                                   
 



                                                                                                                 
 










                                                                
                                            


                                           
 

                                 
                                                    







                                                                                                                       
                      






                                                                                
 







                                                

                                 








                                                                                                                   
 







                                                                       
 
                                                             
 














                                                          




                                




                                                                   
 





















                                                                                                            
                         







                                                                                    

                     

















                                                                                     
                                       

              


                                       











































                                                                                                                                                  
                                                                                                   







                                                                                                     
 




                                                        
                             
 
              





                                        
 



                                                                    
 











                                                                                                  

 









                                                               

                                                               

















                                                                                                                                                  
 



                                                          
 

                                                                     
 









                                                                
                                 









                                                              
      





                                                            

                                                                                                              
 

                                                                       
 






                                                                              
 
                                              


                                        




                                                  
 












                                                                  
                                  
                                       
                                  




                                                     
             




                                        

                                                                                





                                                                           
 




























                                                                                                                                                      
 
         
 

     
                                










                                                                 

                                


                             
 

                                                                       
 
                                     
 


















                                                                                           
            






                                                                                  
 




                                                          
 



                                             

                                              









                                                              
 




                                                             
                                                         

                                       
 





                                                         
                                          

                                                
 
                     
 

                                                            
 




                                                 
 




                                                  
 




                                                 
 





                                                  
 



                                                              
 
 
/*
 *  BRM driver
 *
 *  COPYRIGHT (c) 2006.
 *  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.org/license/LICENSE.
 *
 */

/********** Set defaults **********/

/* basic bus/interface of device,
 * Default to direct accessed AMBA bus.
 */
#ifndef B1553BRM_NO_AMBA
 #define B1553BRM_AMBA
 #undef B1553BRM_PCI
#endif

/* default name to /dev/brm */
#if !defined(B1553BRM_DEVNAME) || !defined(B1553BRM_DEVNAME_NO)
 #undef B1553BRM_DEVNAME
 #undef B1553BRM_DEVNAME_NO
 #define B1553BRM_DEVNAME "/dev/brm0"
 #define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[8]='0'+(no))
#endif

#ifndef B1553BRM_PREFIX
 #define B1553BRM_PREFIX(name) b1553brm##name
#else
 #define B1553BRM_REGISTER_STATIC
#endif

/* default to no translation */
#ifndef B1553BRM_ADR_TO
 #define memarea_to_hw(x) ((unsigned int)(x))
#endif

#ifndef B1553BRM_REG_INT
 #define B1553BRM_REG_INT(handler,irqno,arg) set_vector(handler,(irqno)+0x10,1)
  #undef  B1553BRM_DEFINE_INTHANDLER
  #define B1553BRM_DEFINE_INTHANDLER
#endif

/* default to 128K memory layout */
#if !defined(DMA_MEM_16K)
 #define DMA_MEM_128K
#endif

#include <bsp.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <rtems/bspIo.h>

#include <b1553brm.h>
#include <ambapp.h>

/* Uncomment for debug output */
/*#define DEBUG 1
#define FUNCDEBUG 1*/
#undef DEBUG
#undef FUNCDEBUG

/* EVENT_QUEUE_SIZE sets the size of the event queue
 */
#define EVENT_QUEUE_SIZE           1024


#define INDEX(x) ( x&(EVENT_QUEUE_SIZE-1) )

#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif

#ifdef FUNCDEBUG
#define FUNCDBG(x...) printk(x)
#else
#define FUNCDBG(x...)
#endif

#define READ_REG(address) _BRM_REG_READ16((unsigned int)address)
#define READ_DMA(address) _BRM_REG_READ16((unsigned int)address)
static __inline__ unsigned short _BRM_REG_READ16(unsigned int addr) {
	unsigned short tmp;
	__asm__ (" lduha [%1]1, %0 "
	  : "=r"(tmp)
	  : "r"(addr)
	);
	return tmp;
}

static rtems_device_driver brm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver brm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver brm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver brm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
static rtems_device_driver brm_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);

#define BRM_DRIVER_TABLE_ENTRY { brm_initialize, brm_open, brm_close, brm_read, brm_write, brm_control }

static rtems_driver_address_table brm_driver = BRM_DRIVER_TABLE_ENTRY;

struct msg {
	unsigned short miw;
	unsigned short time;
	unsigned short data[32];
};
#if defined(DMA_MEM_128K)
struct circ_buf {
	struct msg msgs[9];
};
#elif defined(DMA_MEM_16K)
/* two message queue */
struct circ_buf_2 {
	struct msg msgs[2];
};
/* one message queue */
struct circ_buf_1 {
	struct msg msgs[1];
};
#endif

struct irq_log_list {
        volatile unsigned short iiw;
        volatile unsigned short iaw;
};

typedef struct {

    unsigned int memarea_base;
    struct brm_reg *regs;

    /* BRM descriptors */
    struct desc_table {

        volatile unsigned short ctrl;
        volatile unsigned short top;
        volatile unsigned short cur;
        volatile unsigned short bot;

    } *desc;

    volatile unsigned short *mem;
		/* bc mem struct */
		struct {
			/* BC Descriptors */
			struct {
				unsigned short ctrl; /* control */
				unsigned short cw1;  /* Command word 1*/
				unsigned short cw2;  /* Command word 1*/
				unsigned short dptr; /* Data pointer in halfword offset from bcmem */
				unsigned short tsw[2]; /* status word 1 & 2 */
				unsigned short ba;     /* branch address */
				unsigned short timer;  /* timer value */
			} descs[128]; /* 2k (1024 half words) */

			/* message data */
			struct {
				unsigned short data[32]; /* 1 message's data */
			} msg_data[128]; /* 8k */

#if defined(DMA_MEM_128K)
			/* offset to last 64bytes of 128k */
			unsigned short unused[(64*1024-(128*8+128*32))-16*2];
#elif defined(DMA_MEM_16K)
			unsigned short unused[(8*1024-(128*8+128*32))-16*2];
#endif
			/* interrupt log at 64 bytes from end */
			struct irq_log_list irq_logs[16];
		} *bcmem;

#if defined(DMA_MEM_128K)
		/* Memory structure of a RT being inited, just used
		 * for RT initialization.
		 *
		 * *mesgs[32] fit each minimally 8 messages per sub address.
		 */
		struct {
			/* RX Sub Address descriptors */
			struct desc_table rxsubs[32];
			/* TX Sub Address descriptors */
			struct desc_table txsubs[32];
			/* RX mode code descriptors */
			struct desc_table rxmodes[32];
			/* TX mode code descriptors */
			struct desc_table txmodes[32];

			/* RX Sub Address messages */
			struct circ_buf rxsuba_msgs[32];
			/* TX Sub Address messages */
			struct circ_buf txsuba_msgs[32];
			/* RX Mode Code messages */
			struct circ_buf rxmode_msgs[32];
			/* RX Mode Code messages */
			struct circ_buf txmode_msgs[32];


			/* offset to last 64bytes of 128k: tot-used-needed */
			unsigned short unused[(64*1024-(4*32*4+4*32*9*34))-16*2];

			/* interrupt log at 64 bytes from end */
			struct irq_log_list irq_logs[16];
		} *rtmem;
#elif defined(DMA_MEM_16K)
		/* Memory structure of a RT being inited, just used
		 * for RT initialization.
		 *
		 * circ_buf_2 *mesgs[32] fit each minimally 2 messages per queue.
		 * circ_buf_1 *mesgs[32] fit each minimally 1 messages per queue.
		 */
		struct {
			/* RX Sub Address descriptors */
			struct desc_table rxsubs[32];
			/* TX Sub Address descriptors */
			struct desc_table txsubs[32];
			/* RX mode code descriptors */
			struct desc_table rxmodes[32];
			/* TX mode code descriptors */
			struct desc_table txmodes[32];

			/* RX Sub Address messages */
			struct circ_buf_2 rxsuba_msgs[32];
			/* TX Sub Address messages */
			struct circ_buf_2 txsuba_msgs[32];
			/* RX Mode Code messages */
			struct circ_buf_2 rxmode_msgs[32];
			/* RX Mode Code messages */
			struct circ_buf_1 txmode_msgs[32];


			/* offset to last 64bytes of 16k: tot-used-needed */
			unsigned short unused[8*1024 -(4*32*4 +3*32*2*34 +1*32*1*34) -16*2];

			/* interrupt log at 64 bytes from end */
			struct irq_log_list irq_logs[16];
		} *rtmem;
#else
	#error You must define one DMA_MEM_???K
#endif

    /* Interrupt log list */
    struct irq_log_list *irq_log;
    unsigned int irq;

    /* Received events waiting to be read */
    struct rt_msg *rt_event;
    struct bm_msg *bm_event;

    unsigned int head, tail;

    unsigned int last_read[128];
    unsigned int written[32];

    struct bc_msg *cur_list;

    int tx_blocking, rx_blocking;

    rtems_id rx_sem, tx_sem, dev_sem;
		int minor;
		int irqno;
		unsigned int mode;
#ifdef DEBUG
		unsigned int log[EVENT_QUEUE_SIZE*4];
		unsigned int log_i;
#endif

		rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command BRM_SET_EVENTID */
		unsigned int status;
		int bc_list_fail;
} brm_priv;

static int brm_cores;
static unsigned int allbrm_memarea;
static brm_priv *brms;
static struct ambapp_bus *amba_bus;
static unsigned int	allbrm_cfg_clksel;
static unsigned int allbrm_cfg_clkdiv;
static unsigned int allbrm_cfg_freq;

static void brm_interrupt(brm_priv *brm);
#ifdef B1553BRM_DEFINE_INTHANDLER
static void b1553brm_interrupt_handler(rtems_vector_number v);
#endif

#define OFS(ofs) (((unsigned int)&ofs & 0x1ffff)>>1)

static int odd_parity(unsigned int data) {
    unsigned int i=0;

    while(data)
    {
        i++;
        data &= (data - 1);
    }

    return !(i&1);
}


static void start_operation(brm_priv *brm) {
	unsigned int ctrl = READ_REG(&brm->regs->ctrl);
	brm->regs->ctrl = ctrl | 0x8000;
}

static void stop_operation(brm_priv *brm) {
	unsigned int ctrl = READ_REG(&brm->regs->ctrl);
  brm->regs->ctrl = ctrl & ~0x8000;
}
static int is_executing(brm_priv *brm) {
	unsigned int ctrl = READ_REG(&brm->regs->ctrl);
	return ((ctrl>>15) & 1);
}

#ifdef LEON3
#ifndef DONT_DEF_RAMON
int brm_register_leon3_ramon_fpga(void){
	/* Clock div & Clock sel is NOT available.
	 * The BRM is always clocked with 24MHz.
	 * 3 in BRM enhanced register will select 24MHz
	 */
	return b1553brm_register(&ambapp_plb, 0, 0, 3);
}

int brm_register_leon3_ramon_asic(void){
	/* Clock div & Clock sel is available.
	 * Clkdiv only matter when clksel is 1.
	 * clksel=2, clkdiv=don't care, brm_frq=24MHz
	 *
	 * 3 in BRM enhanced register will select 24MHz
	 */
	return b1553brm_register(&ambapp_plb, 2, 0, 3);
}
#endif
#endif

#ifdef B1553BRM_REGISTER_STATIC
static
#endif
int B1553BRM_PREFIX(_register)(struct ambapp_bus *bus, unsigned int clksel, unsigned int clkdiv, unsigned int brm_freq)
{
    rtems_status_code r;
    rtems_device_major_number m;

    FUNCDBG("brm_register:\n\r");

		/* save amba bus pointer */
		amba_bus = bus;
		if ( !bus ){
			printk("brm_register: bus is NULL\n\r");
			return 1;
		}

#ifdef B1553BRM_LOCAL_MEM
		allbrm_memarea = B1553BRM_LOCAL_MEM_ADR;
#else
		allbrm_memarea = 0;
#endif

		/* Save clksel, clkdiv and brm_freq for later use */
		allbrm_cfg_clksel = clksel & CLKSEL_MASK;
		allbrm_cfg_clkdiv = clkdiv & CLKDIV_MASK;
		allbrm_cfg_freq = brm_freq & BRM_FREQ_MASK;

    if ((r = rtems_io_register_driver(0, &brm_driver, &m)) == RTEMS_SUCCESSFUL) {
        DBG("BRM: driver successfully registered, major: %d\n",m);

    } else {
        switch(r) {
        case RTEMS_TOO_MANY:
            printk("BRM rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); break;
        case RTEMS_INVALID_NUMBER:
            printk("BRM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); break;
        case RTEMS_RESOURCE_IN_USE:
            printk("BRM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); break;
        default:
           printk("BRM rtems_io_register_driver failed\n");
        }
				return 1;
    }
		return 0;
}

static void clr_int_logs(struct irq_log_list *logs){
	int i;
	for(i=0; i<16; i++){
		logs[i].iiw = 0xffff;
		logs[i].iaw = 0x0;
	}
}

static rtems_device_driver rt_init(brm_priv *brm) {
	unsigned int i;

	brm->head = brm->tail = 0;
	brm->rx_blocking = brm->tx_blocking = 1;

  if ( brm->bm_event )
		free(brm->bm_event);
	brm->bm_event = NULL;

  if ( brm->rt_event )
		free(brm->rt_event);

	brm->bcmem = NULL;
	brm->rtmem = (void *)brm->mem;

	brm->rt_event = (struct rt_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct rt_msg));

	if (brm->rt_event == NULL) {
		DBG("BRM driver failed to allocated memory.");
		return RTEMS_NO_MEMORY;
	}

	brm->irq_log = (struct irq_log_list *)&brm->rtmem->irq_logs[0];

	brm->regs->ctrl	  = 0x1912;  /* enable both buses, circular 1 bufmode, broadcast, interrupt log */
	brm->regs->oper	  = 0x0900;  /* configure as RT, with addr 1 */
	brm->regs->imask	 = BRM_RT_ILLCMD_IRQ|BRM_SUBAD_IRQ|BRM_TAPF_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ;
	brm->regs->dpoint	= 0;
	brm->regs->ipoint	= OFS(brm->rtmem->irq_logs[0]);
	brm->regs->enhanced  = 0x0000 | allbrm_cfg_freq;  /* BRM clocked with freq = 12,16,20 or 24MHz */
	brm->regs->w_ctrl	= (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
	brm->regs->w_irqctrl = 6;
	brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);

	clr_int_logs(brm->irq_log);

	/* Legalize all commands */
	for (i = 0; i < 16; i++) {
		brm->regs->rt_cmd_leg[i] = 0;
	}

	/* Init descriptor table
	 *
	 * Each circular buffer has room for 8 messages with up to 34 (32 data + miw + time) words (16b) in each.
	 * The buffers must separated by 34 words.
	 */


	/* RX Sub-address 0 - 31 */
	for (i = 0; i < 32; i++) {
		brm->rtmem->rxsubs[i].ctrl = 0x00E0;				/* Interrupt: INTX, IWA, and IBRD */
		brm->rtmem->rxsubs[i].top  = OFS(brm->rtmem->rxsuba_msgs[i]);		     /* Top address */
		brm->rtmem->rxsubs[i].cur  = OFS(brm->rtmem->rxsuba_msgs[i]);		     /* Current address */
		brm->rtmem->rxsubs[i].bot  = OFS(brm->rtmem->rxsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */
		brm->last_read[i] = OFS(brm->rtmem->rxsuba_msgs[i]);
	}
	/* TX Sub-address 0 - 31 */
	for (i = 0; i < 32; i++) {
		brm->rtmem->txsubs[i].ctrl  = 0x0060;					/* Interrupt: IWA and IBRD */
		brm->rtmem->txsubs[i].top   = OFS(brm->rtmem->txsuba_msgs[i]);			  /* Top address */
		brm->rtmem->txsubs[i].cur   = OFS(brm->rtmem->txsuba_msgs[i]);			  /* Current address */
		brm->rtmem->txsubs[i].bot   = OFS(brm->rtmem->txsuba_msgs[i+1]) - sizeof(struct msg)/2;	/* Bottom address */
		brm->last_read[i+32]  = OFS(brm->rtmem->txsuba_msgs[i]);
		brm->written[i] = OFS(brm->rtmem->txsuba_msgs[i]);
	}
	/* RX mode code 0 - 31 */
	for (i = 0; i < 32; i++) {
		brm->rtmem->rxmodes[i].ctrl = 0x00E0;					/* Interrupt: INTX, IWA, and IBRD */
		brm->rtmem->rxmodes[i].top  = OFS(brm->rtmem->rxmode_msgs[i]);			  /* Top address */
		brm->rtmem->rxmodes[i].cur  = OFS(brm->rtmem->rxmode_msgs[i]);			  /* Current address */
		brm->rtmem->rxmodes[i].bot  = OFS(brm->rtmem->rxmode_msgs[i+1]) - sizeof(struct msg)/2;	/* Bottom address */
		brm->last_read[i+64] = OFS(brm->rtmem->rxmode_msgs[i]);
	}
	/* TX mode code 0 - 31 */
	for (i = 0; i < 32; i++) {
		brm->rtmem->txmodes[i].ctrl = 0x0060;					/* Interrupt: IWA and IBRD */
		brm->rtmem->txmodes[i].top  = OFS(brm->rtmem->txmode_msgs[i]);			  /* Top address */
		brm->rtmem->txmodes[i].cur  = OFS(brm->rtmem->txmode_msgs[i]);			  /* Current address */
		brm->rtmem->txmodes[i].bot  = OFS(brm->rtmem->txmode_msgs[i+1]) - sizeof(struct msg)/2;	/* Bottom address */
		brm->last_read[i+96] = OFS(brm->rtmem->txmode_msgs[i]);
	}

	brm->mode = BRM_MODE_RT;

	return RTEMS_SUCCESSFUL;
}

static rtems_device_driver bc_init(brm_priv *brm){

  if ( brm->bm_event )
		free(brm->bm_event);
	brm->bm_event = NULL;

  if ( brm->rt_event )
		free(brm->rt_event);
	brm->rt_event = NULL;

	brm->bcmem = (void *)brm->mem;
	brm->rtmem = NULL;
	brm->irq_log = (struct irq_log_list *)&brm->bcmem->irq_logs[0];

	brm->head = brm->tail = 0;
	brm->rx_blocking = brm->tx_blocking = 1;

	brm->regs->ctrl	  = 0x0006;  /* ping pong enable and enable interrupt log */
	brm->regs->oper	  = 0x0800;  /* configure as BC */
	brm->regs->imask	 = BRM_EOL_IRQ|BRM_BC_ILLCMD_IRQ|BRM_ILLOP_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ;
	brm->regs->dpoint	= 0;
	printk("Set BC interrupt log: 0x%lx, 0x%lx, 0x%lx\n",OFS(brm->bcmem->irq_logs[0]),&brm->bcmem->irq_logs[0],brm->bcmem);
	brm->regs->ipoint	= OFS(brm->bcmem->irq_logs[0]);
	brm->regs->enhanced  = 0x0000 | (allbrm_cfg_freq&0x3);  /* freq = 24 */
	brm->regs->w_ctrl	= (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
	brm->regs->w_irqctrl = 6;
	brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);

	clr_int_logs(brm->irq_log);

	brm->mode = BRM_MODE_BC;

	return RTEMS_SUCCESSFUL;
}

static rtems_device_driver bm_init(brm_priv *brm) {


	brm->head = brm->tail = 0;
	brm->rx_blocking = brm->tx_blocking = 1;

  if ( brm->rt_event )
		free(brm->rt_event);
	brm->rt_event = NULL;

  if ( brm->bm_event )
		free(brm->bm_event);

	brm->bcmem = NULL;
	brm->rtmem = NULL;

	brm->bm_event	 = (struct bm_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct bm_msg));

	if (brm->bm_event == NULL) {
		DBG("BRM driver failed to allocated memory.");
		return RTEMS_NO_MEMORY;
	}

	/* end of 16K, fits all current modes (128K, 16K) */
	brm->irq_log = (struct irq_log_list *)&brm->mem[8*1024-16*2];

	brm->regs->ctrl	  = 0x0006;  /* ping pong enable and enable interrupt log */
	brm->regs->oper	  = 0x0A00;  /* configure as BM */
	brm->regs->imask	= BRM_MBC_IRQ|BRM_MERR_IRQ|BRM_DMAF_IRQ|BRM_MERR_IRQ;
	brm->regs->dpoint	= 0;
	brm->regs->ipoint	= OFS(brm->mem[8*1024-16*2]);
	brm->regs->mcpoint   = 0;	   /* Command pointer */
	brm->regs->mdpoint   = 0x100;   /* Data pointer */
	brm->regs->mbc	   = 1;	   /* Block count */
	brm->regs->enhanced  = 0x0000 | (allbrm_cfg_freq&0x3);  /* freq = 24 */
	brm->regs->w_ctrl	= (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1;
	brm->regs->w_irqctrl = 6;
	brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base);

	clr_int_logs(brm->irq_log);

	brm->mode = BRM_MODE_BM;

	return RTEMS_SUCCESSFUL;
}


static rtems_device_driver brm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
	rtems_status_code status;
	int dev_cnt;
	char fs_name[20];
	brm_priv *brm;
	struct ambapp_ahb_info ambadev;
	char *mem;

	FUNCDBG("brm_initialize\n");

	brm_cores = 0;
	strcpy(fs_name,B1553BRM_DEVNAME);

	/* Find all BRM devices */
	dev_cnt = ambapp_get_number_ahbslv_devices(amba_bus, VENDOR_GAISLER, GAISLER_B1553BRM);
	if ( dev_cnt < 1 ){
		/* Failed to find any CAN cores! */
		printk("BRM: Failed to find any BRM cores\n\r");
		return -1;
	}

	/* allocate & zero memory for the brm devices */
	brms = (brm_priv *)malloc(sizeof(*brms)*dev_cnt);
	if ( !brms ){
		printk("BRM: Failed to allocate SW memory\n\r");
		return -1;
	}
	memset(brms,0,sizeof(*brms)*dev_cnt);

	/* Allocate memory for all device's descriptors,
	 * they must be aligned to a XXX byte boundary.
	 */
	#define BRM_DESCS_PER_CTRL 128
	if ( allbrm_memarea ){
		mem = (char *)allbrm_memarea;
	}else{
 		/* sizeof(struct desc_table) * BRM_DESCS_PER_CTRL * dev_cnt */
		mem = (char *)malloc( (128*1024) * (dev_cnt+1)); /* 128k per core + 128k for alignment */
		if ( !mem ){
			free(brms);
			printk("BRM: Failed to allocate HW memory\n\r");
			return -1;
		}

		/* align memory to 128k boundary */
		mem = (char *)(((unsigned int)mem+0x1ffff) & ~0x1ffff);
	}

	/* clear the used memory */
	memset(mem,0,(128*1024) * dev_cnt);

	/* initialize each brm device, one at a time */
	for(minor=0; minor<dev_cnt; minor++){
		brm = &brms[minor];

		/* Get AMBA AHB device info from Plug&Play */
		ambapp_find_ahbslv_next(amba_bus, VENDOR_GAISLER,
		                        GAISLER_B1553BRM, &ambadev, minor);

		/* Copy Basic HW info */
		brm->regs = (void *)ambadev.start[0];
		brm->irqno = ambadev.irq;
		brm->minor = minor;
		brm->irq = 0;
#ifdef DEBUG
		brm->log_i = 0;
		memset(brm->log,0,sizeof(brm->log));
#endif

		/* Set unique name */
		B1553BRM_DEVNAME_NO(fs_name,minor);

    DBG("Registering BRM core at [0x%x] irq %d, minor %d as %s\n",brm->regs,brm->irqno,minor,fs_name);

		/* Bind filesystem name to device number (minor) */
		status = rtems_io_register_name(fs_name, major, minor);
    if (status != RTEMS_SUCCESSFUL)
			rtems_fatal_error_occurred(status);

		/* RX Semaphore created with count = 0 */
		if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'R', '0'+minor),
		         0,
		         RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
		         0,
		         &brm->rx_sem) != RTEMS_SUCCESSFUL ){
      printk("BRM: Failed to create rx semaphore\n");
	  	return RTEMS_INTERNAL_ERROR;
    }

			/* TX Semaphore created with count = 1 */
		if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'T', '0'+minor),
		         1,
		         RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
		         0,
		         &brm->tx_sem) != RTEMS_SUCCESSFUL ){
      printk("BRM: Failed to create tx semaphore\n");
	  	return RTEMS_INTERNAL_ERROR;
    }

		/* Device Semaphore created with count = 1 */
		if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'D', '0'+minor),
		         1,
		         RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
		         0,
		         &brm->dev_sem) != RTEMS_SUCCESSFUL ){
      printk("BRM: Failed to create device semaphore\n");
	  	return RTEMS_INTERNAL_ERROR;
    }


		/* Set base address of all descriptors */
		brm->memarea_base = (unsigned int)&mem[(128*1024) * minor];
		brm->desc = (struct desc_table *) brm->memarea_base;
		brm->mem = (volatile unsigned short *) brm->memarea_base;
 	  brm->irq_log	= (struct irq_log_list *)(brm->memarea_base + (0xFFE0<<1)); /* last 64byte */

		brm->bm_event = NULL;
		brm->rt_event = NULL;

		/* Sel clock so that we can write to BRM's registers */
		brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5);
		/* Reset BRM core */
		brm->regs->w_ctrl = 1<<10 | READ_REG(&brm->regs->w_ctrl);

		/* Register interrupt handler */
		B1553BRM_REG_INT(B1553BRM_PREFIX(_interrupt_handler), brm->irqno, brm);

		rt_init(brm);

		DBG("BRM: LOG: 0x%lx, 0x%lx\n\r",brm->log,brm);
	}

	/* save number of BRM cores found */
	brm_cores = dev_cnt;

	DBG("BRM initialisation done.\n");

	return RTEMS_SUCCESSFUL;
}

static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
		brm_priv *brm;

    FUNCDBG("brm_open\n");

    if (minor >= brm_cores) {
        DBG("Wrong minor %d\n", minor);
        return RTEMS_UNSATISFIED; /* ENODEV */
    }

		brm = &brms[minor];

    if (rtems_semaphore_obtain(brm->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
        DBG("brm_open: resource in use\n");
        return RTEMS_RESOURCE_IN_USE; /* EBUSY */
    }

		/* Set defaults */
		brm->event_id = 0;

    start_operation(brm);

    return RTEMS_SUCCESSFUL;
}

static rtems_device_driver brm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
	brm_priv *brm = &brms[minor];
	FUNCDBG("brm_close");

	stop_operation(brm);
	rtems_semaphore_release(brm->dev_sem);

	return RTEMS_SUCCESSFUL;
}

static int get_rt_messages(brm_priv *brm, void *buf, unsigned int msg_count) {

    struct rt_msg *dest = (struct rt_msg *) buf;
    int count = 0;

    if (brm->head == brm->tail) {
        return 0;
    }

    do {

        DBG("rt read - head: %d, tail: %d\n", brm->head, brm->tail);
        dest[count++] = brm->rt_event[INDEX(brm->tail++)];

    } while (brm->head != brm->tail && count < msg_count);

    return count;

}

static int get_bm_messages(brm_priv *brm, void *buf, unsigned int msg_count) {

    struct bm_msg *dest = (struct bm_msg *) buf;
    int count = 0;

    if (brm->head == brm->tail) {
        return 0;
    }

    do {

        DBG("bm read - head: %d, tail: %d\n", brm->head, brm->tail);
        dest[count++] = brm->bm_event[INDEX(brm->tail++)];

    } while (brm->head != brm->tail && count < msg_count);

    return count;

}

static rtems_device_driver brm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
    rtems_libio_rw_args_t *rw_args;
    int count = 0;
		brm_priv *brm = &brms[minor];
    int (*get_messages)(brm_priv *brm, void *buf, unsigned int count);

		if ( ! (brm->mode & (BRM_MODE_RT | BRM_MODE_BM)) ){
			return RTEMS_INVALID_NAME;
		}

    rw_args = (rtems_libio_rw_args_t *) arg;

    if ( ((READ_REG(&brm->regs->oper)>>8) & 3) == 1 ) { /* RT */
        get_messages = get_rt_messages;
    }
    else { /* BM */
        get_messages = get_bm_messages;
    }


    FUNCDBG("brm_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);

    while ( (count=get_messages(brm,rw_args->buffer, rw_args->count)) == 0 ) {

        if (brm->rx_blocking) {
            rtems_semaphore_obtain(brm->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
        }
        else {
            /* Translates to EBUSY */
            return RTEMS_RESOURCE_IN_USE;
        }

    }

    rw_args->bytes_moved = count;
    return RTEMS_SUCCESSFUL;

}


static rtems_device_driver brm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
    rtems_libio_rw_args_t *rw_args;
    struct rt_msg *source;
    unsigned int count=0, current, next, descriptor, wc, suba;
		brm_priv *brm = &brms[minor];

		if ( ! (brm->mode & BRM_MODE_RT) ){
			return RTEMS_INVALID_NAME;
		}

    rw_args = (rtems_libio_rw_args_t *) arg;
    source = (struct rt_msg *) rw_args->buffer;

    FUNCDBG("brm_write [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);

    do {

        descriptor = source[count].desc & 0x7F;
        suba       = descriptor-32;
        wc         = source[count].miw >> 11;
        wc = wc ? wc : 32;

        /* Only subaddress transmission is allowed with write */
        if (descriptor < 32 || descriptor >= 64)
            return RTEMS_INVALID_NAME;

        current = brm->desc[descriptor].cur;
        next = brm->written[suba] + 2 + wc;

        if (brm->written[suba] < current) {

            if (next > current) {

                /* No room in transmission buffer */

                if (brm->tx_blocking && count == 0) {
                    rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
                }
								else if ( brm->tx_blocking && (count != 0) ){
									/* return the number of messages sent so far */
									break;
								}
                else {
                    /* Translates to posix EBUSY */
                    return RTEMS_RESOURCE_IN_USE;
                }
            }
        }

        memcpy((void *)&brm->mem[brm->written[suba]], &source[count], (2+wc)*2);

        count++;

        if (next >= brm->desc[descriptor].bot) {
            next = brm->desc[descriptor].top;
        }
        brm->written[suba] = next;

    }  while (count < rw_args->count);

    rw_args->bytes_moved = count;

    if (count >= 0) {
        return RTEMS_SUCCESSFUL;
    }
    return RTEMS_UNSATISFIED;
}

static rtems_device_driver brm_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{

    unsigned int i=0;
    unsigned short ctrl, oper, cw1, cw2;
    rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
    unsigned int *data = ioarg->buffer;
    struct bc_msg *cmd_list = (struct bc_msg *) ioarg->buffer;
		brm_priv *brm = &brms[minor];
		rtems_device_driver ret;
		int len;

    FUNCDBG("brm_control[%d]: [%i,%i]\n",minor,major, minor);

    if (!ioarg) {
        DBG("brm_control: invalid argument\n");
        return RTEMS_INVALID_NAME;
    }

    ioarg->ioctl_return = 0;
    switch(ioarg->command) {

    case BRM_SET_MODE:
			if ( data[0] > 2 )
				return RTEMS_INVALID_NAME;
      stop_operation(brm);
        if (data[0] == 0) {
            ret = bc_init(brm);
        }
        else if (data[0] == 1) {
            ret = rt_init(brm);
        }
        else if (data[0] == 2) {
            ret = bm_init(brm);
        }else
					ret = RTEMS_INVALID_NAME;

				if ( ret != RTEMS_SUCCESSFUL)
							return ret;

        if ( brm->mode & (BRM_MODE_RT | BRM_MODE_BM ) )
					start_operation(brm);
        break;

    case BRM_SET_BUS:
        stop_operation(brm);
				ctrl = READ_REG(&brm->regs->ctrl);
        ctrl &= 0xE7FF;                               /* Clear bit 12-11 ...      */
        ctrl |= (data[0]&0x3)<<11;                    /* ... OR in new bus status */
				brm->regs->ctrl = ctrl;
        start_operation(brm);
        break;

    case BRM_SET_MSGTO:
        stop_operation(brm);
        ctrl = READ_REG(&brm->regs->ctrl);
				ctrl &= 0xFDFF;                               /* Clear bit 9 ...          */
        ctrl |= (data[0]&1)<<9;                       /* ... OR in new MSGTO      */
				brm->regs->ctrl = ctrl;
        start_operation(brm);
        break;

    case BRM_SET_RT_ADDR:
        stop_operation(brm);
				oper = READ_REG(&brm->regs->oper);
        oper &= 0x03FF;                               /* Clear bit 15-10 ...      */
        oper |= (data[0]&0x1f)<<11;                   /* ... OR in new address    */
        oper |= odd_parity(data[0]&0x1f)<<10;         /* ... OR in parity         */
				brm->regs->oper = oper;
        start_operation(brm);
        break;

    case BRM_SET_STD:
        stop_operation(brm);
				ctrl = READ_REG(&brm->regs->ctrl);
        ctrl &= 0xFF7F;                               /* Clear bit 7 ...           */
        ctrl |= (data[0]&1)<<7;                       /* ... OR in new ABSTD (1=A) */
				brm->regs->ctrl = ctrl;
        start_operation(brm);
        break;

    case BRM_SET_BCE:
        stop_operation(brm);
				ctrl = READ_REG(&brm->regs->ctrl);
        ctrl &= 0xFFEF;                               /* Clear bit 4 ...           */
        ctrl |= (data[0]&1)<<4;                       /* ... OR in new BCE         */
				brm->regs->ctrl = ctrl;
        start_operation(brm);
     break;

    case BRM_TX_BLOCK:
        brm->tx_blocking     = data[0];
        break;

    case BRM_RX_BLOCK:
        brm->rx_blocking     = data[0];
        break;

    case BRM_DO_LIST:

        if ( brm->mode != BRM_MODE_BC ){
          return RTEMS_INVALID_NAME;
				}

        /* Check if we are bus controller */
        if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
            return RTEMS_INVALID_NAME;
        }

        /* Already processing list? */
        if (is_executing(brm)) {
            return RTEMS_RESOURCE_IN_USE;
        }

				/* clear any earlier releases */
        rtems_semaphore_obtain(brm->tx_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT);

				brm->bc_list_fail = 0;
        brm->cur_list = cmd_list;
				brm->regs->dpoint = 0;

        i = 0;
        while ( (cmd_list[i].ctrl & BC_EOL) == 0) {

            ctrl = (4<<12) | (((cmd_list[i].ctrl&BC_BUSA)==BC_BUSA)<<9) | (((cmd_list[i].ctrl&BC_RTRT)==BC_RTRT)<<8);

            if (cmd_list[i].ctrl&BC_RTRT) {
                cw1 = (cmd_list[i].rtaddr[0]<<11) | (0<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc & 0x1f); /* receive cw */
                cw2 = (cmd_list[i].rtaddr[1]<<11) | (1<<10) | (cmd_list[i].subaddr[1]<<5) | (cmd_list[i].wc & 0x1f); /* transmit cw */
            }
            else {
                cw1 = (cmd_list[i].rtaddr[0]<<11) | (((cmd_list[i].ctrl&BC_TR)==BC_TR)<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc&0x1f);
								cw2 = 0;
            }


            /* Set up command block */
            brm->bcmem->descs[i].ctrl = ctrl;
            brm->bcmem->descs[i].cw1 = cw1;
            brm->bcmem->descs[i].cw2 = cw2;
						/* data pointer:
						 * (&brm->bcmem->msg_data[i].data[0] & 0x1ffff) / 2
						 */
            brm->bcmem->descs[i].dptr = 1024+i*32;  /* data pointer */
						brm->bcmem->descs[i].tsw[0] = 0;
						brm->bcmem->descs[i].tsw[1] = 0;
						brm->bcmem->descs[i].ba = 0;
						brm->bcmem->descs[i].timer = 0;

            memcpy((void *)&brm->bcmem->msg_data[i].data[0], &cmd_list[i].data[0], cmd_list[i].wc*2);

            i++;
        }

        brm->bcmem->descs[i].ctrl = 0; /* end of list */

        start_operation(brm);

        break;

    case BRM_LIST_DONE:

        if ( brm->mode != BRM_MODE_BC ){
          return RTEMS_INVALID_NAME;
				}

				/* Check if we are bus controller */
        if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) {
            return RTEMS_INVALID_NAME;
        }

        if (is_executing(brm)) {

            data[0] = 0;
            if (brm->tx_blocking) {
                rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
                data[0] = 1;
								if ( brm->bc_list_fail ){
									return RTEMS_INVALID_NAME;
								}
            }else{
							return RTEMS_RESOURCE_IN_USE;
						}


        }
        else {
            data[0] = 1; /* done */
        }

        /* copy finished list results back into bc_msg array */
        i = 0;
        while ( (brm->cur_list[i].ctrl & BC_EOL) == 0) {

            if (READ_DMA(&brm->bcmem->descs[i].ctrl) & 1) {
                brm->cur_list[i].ctrl |= 0x8000; /* Set BAME */
            }
            if (brm->cur_list[i].ctrl & BC_TR) {
                /* RT Transmit command, copy received data */
								len = brm->cur_list[i].wc;
								while( len-- > 0){
									brm->cur_list[i].data[len] = READ_DMA(&brm->bcmem->msg_data[i].data[len]);
								}
            }
            brm->cur_list[i].tsw[0] = READ_DMA(&brm->bcmem->descs[i].tsw[0]);
            brm->cur_list[i].tsw[1] = READ_DMA(&brm->bcmem->descs[i].tsw[1]);

            i++;
        }
        break;


    case BRM_CLR_STATUS:
			brm->status = 0;
			break;

    case BRM_GET_STATUS: /* copy status */

			if ( !ioarg->buffer )
				return RTEMS_INVALID_NAME;

			*(unsigned int *)ioarg->buffer = brm->status;
			break;

		case BRM_SET_EVENTID:
			brm->event_id = (rtems_id)ioarg->buffer;
			break;

    default:
        return RTEMS_NOT_DEFINED;
    }
    return RTEMS_SUCCESSFUL;
}

#ifdef B1553BRM_DEFINE_INTHANDLER
static void b1553brm_interrupt_handler(rtems_vector_number v){
	int i;
	/* find minor */
	for(i=0; i<brm_cores; i++){
		if ( (brms[i].irqno+0x10) == v ){
			brm_interrupt(&brms[i]);
			return;
		}
	}
}
#endif

static void brm_interrupt(brm_priv *brm) {
  unsigned short descriptor, current, pending, miw, wc, tmp;
	unsigned short msgadr, iaw, iiw;
	int len;
	int signal_event=0;
	unsigned int event_status=0;
	#define SET_ERROR_DESCRIPTOR(descriptor) (event_status = (event_status & 0x0000ffff) | descriptor<<16)

	while( (iiw=READ_REG(&brm->irq_log[brm->irq].iiw)) != 0xffff ){
		iaw=READ_REG(&brm->irq_log[brm->irq].iaw);

		/* indicate that the interrupt log entry has been processed */
		brm->irq_log[brm->irq].iiw = 0xffff;

		/* Interpret interrupt log entry  */
    descriptor = iaw >> 2;
    pending    = iiw;
    brm->irq = (brm->irq + 1) % 16;

		/* Clear the log so that we */


    /* Subaddress accessed irq (RT only)
     *
     * Can be either a receive or transmit command
     * as well as a mode code.
     */
    if (pending & BRM_SUBAD_IRQ) {

        /* Pointer to next free message in circular buffer */
        current = READ_DMA(&brm->desc[descriptor].cur);

        while  ( (msgadr=brm->last_read[descriptor]) != current) {

            /* Get word count */
            miw = READ_DMA(&brm->mem[msgadr]);
            wc  = miw >> 11;

            /* Data received */
            if (descriptor < 32) {
                wc = wc ? wc : 32;
            }
            /* Data transmitted */
            else if (descriptor < 64) {
                wc = wc ? wc : 32;
                rtems_semaphore_release(brm->tx_sem);
            }
            /* RX Mode code */
            else if (descriptor < 96) {
                wc = (wc>>4);
            }
            /* TX Mode code */
            else if (descriptor < 128) {
                wc = (wc>>4);
            }

#ifdef DEBUG
            brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (descriptor << 16) | wc;
            brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current;
            brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
#endif

            /* If there is room in the event queue, copy the event there */
            if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {

                /* Copy to event queue */
								brm->rt_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[msgadr]);
								brm->rt_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[msgadr+1]);
								len = wc;
								while( len-- > 0){
									brm->rt_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[msgadr+2+len]);
								}
                brm->rt_event[INDEX(brm->head)].desc = descriptor;
                brm->head++;

            }
            else {
                /* Indicate overrun */
                brm->rt_event[INDEX(brm->head)].desc |= 0x8000;
            }

            msgadr += (2+wc);

            if (msgadr >= brm->desc[descriptor].bot) {
                msgadr = brm->desc[descriptor].top;
            }
						brm->last_read[descriptor] = msgadr;

#ifdef DEBUG
            brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr;
#endif

            /* Wake any blocked rx thread */
            rtems_semaphore_release(brm->rx_sem);

        }

    }

    if (pending & BRM_EOL_IRQ) {
        rtems_semaphore_release(brm->tx_sem);
    }

    if (pending & BRM_BC_ILLCMD_IRQ) {
				brm->bc_list_fail = 1;
        rtems_semaphore_release(brm->tx_sem);
				SET_ERROR_DESCRIPTOR(descriptor);
				FUNCDBG("BRM: ILLCMD IRQ\n\r");
    }

    /* Monitor irq */
    if (pending & BRM_MBC_IRQ) {

        stop_operation(brm);
        brm->regs->mbc = 1;
        start_operation(brm);

        /* If there is room in the event queue, copy the event there */
        if (brm->head - brm->tail != EVENT_QUEUE_SIZE) {

            /* Copy to event queue */

            brm->bm_event[INDEX(brm->head)].miw  =  READ_DMA(&brm->mem[0]);
            brm->bm_event[INDEX(brm->head)].cw1  =  READ_DMA(&brm->mem[1]);
            brm->bm_event[INDEX(brm->head)].cw2  =  READ_DMA(&brm->mem[2]);
            brm->bm_event[INDEX(brm->head)].sw1  =  READ_DMA(&brm->mem[4]);
            brm->bm_event[INDEX(brm->head)].sw2  =  READ_DMA(&brm->mem[5]);
            brm->bm_event[INDEX(brm->head)].time =  READ_DMA(&brm->mem[6]);

            len = 32;
            while ( len-- ){
              brm->bm_event[INDEX(brm->head)].data[len] =  READ_DMA(&brm->mem[0x100+len]);
              len--;
              brm->bm_event[INDEX(brm->head)].data[len] =  READ_DMA(&brm->mem[0x100+len]);
              len--;
              brm->bm_event[INDEX(brm->head)].data[len] =  READ_DMA(&brm->mem[0x100+len]);
              len--;
              brm->bm_event[INDEX(brm->head)].data[len] =  READ_DMA(&brm->mem[0x100+len]);
            }
/*            memcpy((void *)brm->bm_event[INDEX(brm->head)].data, &brm->mem[0x100], 32);*/

#ifdef DEBUG
            brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_REG(&brm->regs->mbc);
            brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[0]);
            brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[1]);
            brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[4]);
#endif

            brm->head++;

        }
        else {
            /* Indicate overrun */
            brm->rt_event[INDEX(brm->head)].miw |= 0x8000;
        }

        /* Wake any blocking thread */
        rtems_semaphore_release(brm->rx_sem);

    }

		/* The reset of the interrupts
		 * cause a event to be signalled
		 * so that user can handle error.
		 */
		if ( pending & BRM_RT_ILLCMD_IRQ){
			FUNCDBG("BRM: BRM_RT_ILLCMD_IRQ\n\r");
			brm->status |= BRM_RT_ILLCMD_IRQ;
			event_status |= BRM_RT_ILLCMD_IRQ;
			SET_ERROR_DESCRIPTOR(descriptor);
			signal_event=1;
		}

		if ( pending & BRM_ILLOP_IRQ){
			FUNCDBG("BRM: BRM_ILLOP_IRQ\n\r");
			brm->bc_list_fail = 1;
			rtems_semaphore_release(brm->tx_sem);
			event_status |= BRM_ILLOP_IRQ;
			SET_ERROR_DESCRIPTOR(descriptor);
			signal_event=1;
		}

		if ( pending & BRM_MERR_IRQ){
			FUNCDBG("BRM: BRM_MERR_IRQ\n\r");
			event_status |= BRM_MERR_IRQ;
			SET_ERROR_DESCRIPTOR(descriptor);
			signal_event=1;
		}
	    /* Clear Block Accessed Bit */
    tmp = READ_REG(&brm->desc[descriptor].ctrl);
    brm->desc[descriptor].ctrl = tmp & ~0x10;

	} /* While */

	/* clear interrupt flags & handle Hardware errors */
	pending = READ_REG(&brm->regs->ipend);

	if ( pending & BRM_DMAF_IRQ){
		FUNCDBG("BRM: BRM_DMAF_IRQ\n\r");
		event_status |= BRM_DMAF_IRQ;
		signal_event=1;
	}

	if ( pending & BRM_WRAPF_IRQ){
		FUNCDBG("BRM: BRM_WRAPF_IRQ\n\r");
		event_status |= BRM_WRAPF_IRQ;
		signal_event=1;
	}

	if ( pending & BRM_TAPF_IRQ){
		FUNCDBG("BRM: BRM_TAPF_IRQ\n\r");
		event_status |= BRM_TAPF_IRQ;
		signal_event=1;
	}

	/* Copy current mask to status mask */
	if ( event_status ){
		if ( event_status & 0xffff0000 )
			brm->status &= 0x0000ffff;
		brm->status |= event_status;
	}

	/* signal event once */
	if ( signal_event && (brm->event_id!=0) ){
		rtems_event_send(brm->event_id, event_status);
	}

}