Exemple #1
0
/*************************************************************************
Author: Josiah Snarr
Date: April 11, 2015

stepperHome finds the stepper limits on the platform, and centers the
  stepper at the midpoint between them
*************************************************************************/
void stepperHome(void)
{
  unsigned int midpoint;

  //Delay stops it from going "ttttttzzzhhggggghhghhzzzzzttttt"
  msDelay(25);

  //Go fully left
  while(IS_CLR(STEP_SWI_PORT, SWI_LEFT))
  {
    stepperStep();
    msDelay(2);
  }
  
  //All the way left, 0-position, switch direction
  currStep = 0;
  SWI_DIR(direction);

  //Go all the way right
  while(IS_CLR(STEP_SWI_PORT, SWI_RIGHT))
  {
    stepperStep();
    msDelay(2);
  }
  
  //All the way right, number of steps is current step, find midpoint and switch direction
  numSteps = currStep;
  midpoint = currStep/2;
  SWI_DIR(direction);

  //Move to midpoint
  while(currStep != midpoint)
  {
    stepperStep();
    msDelay(2);
  }
}
Exemple #2
0
		void MBC2::control(uint8_t value, uint16_t addr)
		{
			if (addr >= 0x0000 && addr <= 0x1FFF)
			{
				// least significant bit of upper byte in address must be zero 
				if (IS_CLR(addr, 0x0100))
				{
					xram_enable_ = ((value & 0x0F) == 0x0A);
				}
			}
			else if (addr >= 0x2000 && addr <= 0x3FFF)
			{
				// least significant bit of upper byte in address must be one
				if (IS_SET(addr, 0x0100))
				{
					rom_bank_ = value & 0x0F;
				}
			}
		}
Exemple #3
0
void Agc_sweep(SEGCTLPTR *heap_segments)
{
  SEGCTLPTR segctlp, *segctlpp;
  ELPTR elp;
  CODEDPTR *elpp;
  
  GC_SWEEP();

  for ( segctlpp = heap_segments; (segctlp = *segctlpp) != NIL; )
    /*  At end of loop so it can be skipped by continue: segctlpp = &((segctlp)->next ) */
  {
    PTR		elstart, elend;
    BITMAPPTR	bitmap = segctlp->bitmap;
    PTR		old_elend;
    ASSERT_DECL( PTR last_freestart )


      REPORT6(5,"Agc_collect{free list reconstruct}: segctlp=0x%p, elsize=%d, start=0x%p, end=0x%p, size=%d,els=%d\n",
	      (void *)segctlp,SEGELSIZE(segctlp),(void *)SEGSTART(segctlp),(void *)SEGEND(segctlp),SEGSIZE(segctlp),SEGELS(segctlp));


    /*
     ** First, clear bitmap (to indicate unused) from free list.
     ** This is essential for the freelist reconstruction algorithm to work.
     ** It ensures that all free list elements are enclosed in an unused heap area
     ** as identified by the bitmap.
     */

    /*
     ** Note that sweeping algorithm relies on the fact that the free list elements are
     ** in ascending address order, and there is some allocated space between elements.
     */

    ASSERT(bitmap == segctlp->bitmap,Agc_collect,'bitmap' out of sync);
    ASSERT(TSTMARK(bitmap,SEGELS(segctlp)+0),Agc_collect,bitmap trailer clear);
    ASSERT(!TSTMARK(bitmap,SEGELS(segctlp)+1),Agc_collect,bitmap trailer set);
    ASSERT(TSTMARK(bitmap,SEGELS(segctlp)+2),Agc_collect,bitmap trailer clear);

    elpp = &segctlp->free;
    elp = DECODEPTR(*elpp);
    old_elend = SEGSTART( segctlp );
    ASSERT_INIT( last_freestart = SEGSTART(segctlp) - 1 );
    if ( elp != NIL )
    {
      elstart = (PTR)elp;
      elend = (PTR)ELEND( elp, segctlp );
		
      CHECK_EL( segctlp, elp, elend );
    }
    else
    {
      elstart = elend = (char *)(SEGEND( segctlp )) + 1; /* well beyond any free space */
    }
		
    for (;;)
    {
		
      PTR		freestart, freeend;
      SIZE	freed_bytes;
		
      ASSERT(elp == DECODEPTR(*elpp),Agc_collect,elpp and elp out of step);
		
      ASSERT(elp == NIL || ((PTR)elp >= (PTR)SEGSTART(segctlp) && (PTR)elp < (PTR)SEGEND(segctlp))
	     ,Agc_collect,elp not within segment);
      ASSERT(elp == NIL || ((PTR)ELEND(elp,segctlp) <= (PTR)SEGEND(segctlp))
	     ,Agc_collect,elp end not within segment);
      ASSERT(elp == NIL || elend > elstart,Agc_collect,empty free list element);
		
      /*
       ** First, set 'freestart' to be the start of either the next:
       **
       **	free space starting outside a free list element
       ** or
       **	free space starting at the start of a free list element
       **	but finishing beyond the end of that element
       ** or
       **	an adress beyond the end of the segment
       */
		
      SCAN_TO_CLR( freestart, segctlp, bitmap, old_elend, elstart );
		
      ASSERT( freestart > last_freestart,Agc_collect,not progressing in sweep);
      ASSERT_INIT( last_freestart = freestart );
		
      if ( freestart >= SEGEND( segctlp ) ) break;
		
      while ( freestart == elstart && TSTMARK( bitmap, ELNUM( elend, segctlp ) ) )
      {
	/*
	 ** Freespace is identical to free list element.
	 ** Skip on to next free list element.
	 */
		
	ASSERT(freestart <= SEGEND(segctlp),Agc_collect,freestart beyond segend);
		
	/* step on to next free list element */
		
	ASSERT(elp != NIL,Agc_collect,elp nil at elpp update);
	elpp = &elp->next;
	elp = DECODEPTR(*elpp);
	old_elend = elend;
	if ( elp != NIL )
	{
	  elstart = (PTR)elp;
	  elend = (PTR)ELEND( elp, segctlp );

	  CHECK_EL( segctlp, elp, elend );
		
	  ASSERT(elend > elstart,Agc_collect,empty free list element);
	}
	else
	{
	  elstart = elend = (char *)(SEGEND( segctlp )) + 1; /* well beyond any free space */
	}
	ASSERT(old_elend < elstart,Agc_collect,free list not in order);
		
	SCAN_TO_CLR( freestart, segctlp, bitmap, old_elend, elstart );
      }
		
      if ( freestart >= SEGEND( segctlp ) ) break;
		
      ASSERT(freestart == (PTR)SEGSTART( segctlp ) || freestart > old_elend,Agc_collect,freestart before old_elend);
		
      ASSERT(freestart <= elstart,Agc_collect,freestart > elstart);
		
      ASSERT(elp == NIL || elstart == (PTR)DECODEPTR(*elpp),Agc_collect,elstart != *elpp);
		
		
      /*
       ** Secondly, set 'freeend' to be the end of the freespace
       */

      if ( freestart < elstart )
      {
	SCAN_TO_SET( freeend, segctlp, bitmap, freestart, elstart );
		
	freed_bytes = (char *)freeend - (char *)freestart;
	CLR_AT_FREE( freestart, SEGELSIZE(segctlp), freed_bytes );
      }
      else
      {
	ASSERT(freestart == elstart,Agc_collect,freestart == elstart);
		
	freed_bytes = 0;
	freeend = freestart;
      }

      while ( freeend == elstart )
      {
	/* step on to next free list element */
		
	ASSERT(freeend <= SEGEND(segctlp),Agc_collect,freeend beyond segend);
		
	elp = DECODEPTR(elp->next);
	old_elend = elend;
		
	if ( elp != NIL )
	{
	  elend = (PTR)ELEND( elp, segctlp );
	  CLR_ELHEADER_AT_FREE( (ELPTR)elstart, SEGELSIZE(segctlp) );
	  elstart = (PTR)elp;
		
	  CHECK_EL( segctlp, elp, elend );
		
	  ASSERT(elend > elstart,Agc_collect,empty free list element);
	}
	else
	{
	  CLR_ELHEADER_AT_FREE( (ELPTR)elstart, SEGELSIZE(segctlp) );
	  elstart = elend = (char *)(SEGEND( segctlp )) + 1; /* well beyond any free space */
	}
	ASSERT(old_elend < elstart,Agc_collect,free list not in order);
		
	ASSERT(freeend < elstart,Agc_collect,freeend not less than elstart);
		
	SCAN_TO_SET( freeend, segctlp, bitmap, old_elend, elstart );
		
	ASSERT(freeend >= old_elend,Agc_collect,freeend before old_elend);
	ASSERT(freeend <= elstart,Agc_collect,freeend beyond elstart limit);
	ASSERT(freeend <= SEGEND(segctlp),Agc_collect,freeend beyond segend);
		
	if ( freeend != old_elend )
	{
	  freed_bytes += (char *)freeend - (char *)old_elend;
	  CLR_AT_FREE( old_elend, SEGELSIZE(segctlp), (char *)freeend-(char *)old_elend );
	}
      }
		
      ASSERT(freeend < elstart,Agc_collect,freeend beyond elstart);
		
		
      /* freestart -> freeend is the new element */
      /* elp is freelist element beyond freeend, or NIL */
      /* elpp points to el pointer before freestart */
		
      ASSERT(freeend > freestart,Agc_collect,empty bitmap area);
      ASSERT(elp == NIL || (PTR)elp > freeend,Agc_collect,elp before freeend);
      ASSERT(freeend <= SEGEND(segctlp),Agc_collect,freeend beyond segend);
		
      ASSERT((PTR)elpp < freestart,Agc_collect,elpp beyond freestart);

      ASSERT(bitmap == segctlp->bitmap,Agc_collect,'bitmap' out of sync);
      ASSERT(TSTMARK(bitmap,SEGELS(segctlp)+0),Agc_collect,bitmap trailer clear);
      ASSERT(!TSTMARK(bitmap,SEGELS(segctlp)+1),Agc_collect,bitmap trailer set);
      ASSERT(TSTMARK(bitmap,SEGELS(segctlp)+2),Agc_collect,bitmap trailer clear);
		
      if ( freestart == SEGSTART( segctlp ) && freeend == SEGEND( segctlp ) )
      {
	/* Whole segment is free */
	/* +++ put segment at end of list rather than freeing */
		
	REPORT1(3,"Agc_collect: freeing seg=0x%p\n",(void *)segctlp);
		
	ASSERT(bitmap == segctlp->bitmap,Agc_collect,'bitmap' out of sync);

	FREE_BITMAP( bitmap, SEGELS( segctlp ) + 3 );
		
	ASSERT_INIT( segctlp->bitmap = bitmap = NIL );
		
	*segctlpp = segctlp->next; /* remove segctlp from list */
		
	Agc_b_allocated -= freed_bytes;
	Agc_s_grabbed--;
	Agc_b_grabbed -= SEGSIZE(segctlp);
		
	REP_DO(Agc_s_freed++);
		
	FREE_SEG( segctlp );
		
	ASSERT_INIT( segctlp = NIL );
		
	goto sweep_next_seg;
      }
      else if ( ELPTRENOUGH( freestart, freeend ) )
      {
#define				freeelp	((ELPTR)freestart)
		
	/* care needed because of possible overlap between new and old element header */
		
	REPORT5(6,"Agc_collect: adding free list element (0x%p -> 0x%p : size %d) after elpp 0x%p, before 0x%p\n",
		(void *)freestart,(void *)freeend,(char *)freeend-(char *)freestart,(void *)elpp,(void *)elp);
		
	ASSERT( IS_CLR(freestart,SEGELSIZE(segctlp),(char *)freeend-(char *)freestart)
	       ,Agc_collect,recreated free list element not clear);
		
	ASSERT( ((char *)freeend - (char *)freestart) % SEGELSIZE( segctlp ) == 0,Agc_collect,space recovered not multiple of elsize);
		
	freeelp->next = ENCODEPTR( elp );
	freeelp->elements = ((char *)freeend - (char *)freestart) / SEGELSIZE( segctlp );
		
	ASSERT(DECODEPTR(*elpp) == NIL || (PTR)DECODEPTR(*elpp) >= freestart,Agc_collect,discarding space already in free list);
		
	*elpp = ENCODEPTR( freestart );
		
	/* elp is still correct as next element, we have just inserted preceding it */
	/* however elpp now needs to point at new element */
	elpp = &freeelp->next;
		
	Agc_b_allocated -= freed_bytes;
		
	ASSERT( freeend == (PTR)ELEND(freeelp,segctlp)
	       ,Agc_collect,freeend not ELEND);
	ASSERT( freeelp->next == CODEDNIL || DECODEPTR(freeelp->next) > ELEND(freeelp,segctlp)
	       ,Agc_collect,free list elements overlap);
	ASSERT( freeelp->next == CODEDNIL || (PTR)DECODEPTR(freeelp->next) > freeend
	       ,Agc_collect,freeelp->next not past freeend);
		
#undef				freeelp
      }
      /* else ( ! ELPTRENOUGH( freestart, freeend ) )			*/
      /* 	do nothing, forget the few bytes of free space we found */
		
      old_elend = freeend;
		
    }

#ifdef	A_DEBUG
    if ( ELPTRENOUGH( (PTR)NIL, (char *)NIL+SEGELSIZE(segctlp) ) )
      /* if ( SEGELSIZE(segctlp) >= sizeof( EL ) ) */
    {
      SIZE	i;

      elp = DECODEPTR( segctlp->free );

      for ( i = 0; i < SEGELS(segctlp); i++ )
      {
	if ( !TSTMARK(bitmap,i) )
	{
	  while ( i > ELNUM( ELEND( elp, segctlp ), segctlp ) )
	  {
	    elp = DECODEPTR( elp->next );
	    ASSERT( elp != NIL,Agc_collect,free element beyond free list end at end of sweep);
	  }
	  ASSERT( i >= ELNUM( elp, segctlp ) && i < ELNUM( ELEND( elp, segctlp ), segctlp ),Agc_collect,free element not in free list at end of sweep);
	}
      }
    }
#endif

    ASSERT(bitmap == segctlp->bitmap,Agc_collect,'bitmap' out of sync);

    FREE_BITMAP( bitmap, SEGELS( segctlp ) + 3 );

    ASSERT_INIT( segctlp->bitmap = bitmap = NIL );

    segctlpp = &((segctlp)->next);

  sweep_next_seg:	;

  }

}
Exemple #4
0
char sci_read()
{
	while(IS_CLR(SCISR1, SCISR1_RDRF_MASK));
	return SCIDRL;
}
Exemple #5
0
void sci_write(char c)
{
	while(IS_CLR(SCISR1, SCISR1_TDRE_MASK));
	SCIDRL = c;
}
Exemple #6
0
loff_t btp_llseek(
    struct file *file_p,
    loff_t offset,
    int which
    )
{
    FUNCTION("btp_llseek");
    LOG_DEVID(file_p);
    bt_dev_t type = GET_LDEV_TYPE(file_p);

    bt_unit_t *unit_p = GET_UNIT_PTR(file_p);

    loff_t retval = 0;
    loff_t f_pos, end_pos;

    FENTRY;

    /* Determine where the end of the various logical devices are */
    switch(type) {
      case BT_DEV_RDP:
        if (IS_CLR(unit_p->bt_status, BT_PCI2PCI)) {
            end_pos = 8 * SIZE_1MB;
        } else if (IS_SET(unit_p->bt_status, BT_NEXT_GEN)) {
            end_pos = 192 * SIZE_1KB;
        } else {
            end_pos = 0;
        }
        break;
      case BT_DEV_LDP:
        if (IS_CLR(unit_p->bt_status, BT_NEXT_GEN)) {
            end_pos = 0;
        } else {
            end_pos = 192 * SIZE_1KB;
        }
        break;
      case BT_DEV_A24:
        /* 24 address bits */
        end_pos = 16 * SIZE_1MB;
        break;

      case BT_DEV_IO:
        /* 16 address bits */
        end_pos = 64 * SIZE_1KB;
        break;

      case BT_DEV_A32:
        /* 32 address bits */
        end_pos = ((loff_t) 1)<<32;
        break;

      case BT_DEV_RE:
        /* 31 address bits, only provided for compatibility */
        end_pos = ((loff_t) 1)<<31;
        break;

      case BT_DEV_LM:
        /* User determined when device was loaded */
        end_pos = unit_p->lm_size;
        if (0 == end_pos) {
            INFO_STR("Local Memory device not enabled.\n");
            retval = -ENXIO;
            goto llseek_end;
        }
        break;

      default:
        TRC_MSG(BT_TRC_RD_WR, (LOG_FMT "Unrecognized device type: %d.\n",
            LOG_ARG, type));
        retval = -ENXIO;
        goto llseek_end;
    }

    /* Determine what the new address would be */
    switch(which) {
      case SEEK_SET:
        f_pos = offset;
        break;

      case SEEK_CUR:
        f_pos = file_p->f_pos + offset;
        break;

      case SEEK_END:
        f_pos = end_pos + offset;       /* Better be a negative offset */
        break;

      default:  /* Should never happen */
        INFO_STR("Invalid SEEK type.\n");
        retval = -EINVAL;
        goto llseek_end;
    }

    if (f_pos >= end_pos) {
        INFO_STR("Seek past end of logical device.\n");
        retval = -EINVAL;
        goto llseek_end;
    }

    file_p->f_pos = f_pos;
    retval = f_pos;

llseek_end:
    FEXIT(retval);
    return retval;
}
Exemple #7
0
static int btp_xfer(
    bt_unit_t *unit_p, 
    bt_dev_t type, 
    bt_accessflag_t dir, 
    void * usr_data_p, 
    unsigned long dest_addr, 
    size_t length,
    size_t *xferred_bytes_p
    )
{
    FUNCTION("btp_xfer");
    LOG_UNIT(unit_p->unit_number);

    void            *data_p;
    int             dma_flag; 
    int             data_width; 
    size_t          length_remaining = length;
    unsigned int    start, need;
    bt_data32_t     mreg_value;
    bt_error_t      retval = BT_SUCCESS;
    unsigned int    inx;
    unsigned long   pci_addr;
    bt_data32_t     ldma_addr;
    struct page     **pages;
    int ret, i,     write;
    bt_data32_t     usr_curr_offset;
    caddr_t         kbuf_p;
    unsigned int    nr_pages;

    FENTRY;

    /* 
    ** Haven't transferred any data yet 
    */
    *xferred_bytes_p = 0;       

    /*
    **  Adjust for the extended remote ram window.
    */
    if (type == BT_AXSRE) {
        dest_addr |= RE_ADJUST;
    }
    

    /*
    ** Normally you would have the while loop in the read and write routines.
    **
    ** Since both would require the same loop, I've decided to just put it
    ** in this routine instead.
    */
    while ((length_remaining > 0) && (BT_SUCCESS == retval)) {
        int  xferred_length = 0;
        int  requested_length = length_remaining;

        /*
        ** Setup direction and current offset
        */
        if (dir == BT_WR) {
            write = 1;
        } else {
            write = 0;
        }
        usr_curr_offset = (bt_data32_t) ((bt_devaddr_t) usr_data_p & (PAGE_SIZE -1));

        /*
        ** Malloc a scatter/gather list
        */
        nr_pages = (usr_curr_offset + requested_length + ~PAGE_MASK) >> PAGE_SHIFT;
        pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
        if (!pages) {
            WARN_STR("Failed to kmalloc scatter/gather list.\n");
            retval = BT_EIO;
            goto btp_xfer_end;
        }

        /*
        ** Translate the user pages to physical addresses
        ** store in scatter/gather list
        */
        down_read(&current->mm->mmap_sem);
        ret = get_user_pages(current, current->mm, (unsigned long) usr_data_p,
            nr_pages, write, 1, pages, NULL);
        up_read(&current->mm->mmap_sem);
        if (ret < nr_pages) {
            WARN_STR("Failed to create scatter/gather list for user buffer.\n");
            for (i = 0; i < ret; i++) {
                page_cache_release(pages[i]);
            }
            kfree(pages);
            retval = BT_EIO;
            goto btp_xfer_end;
        }
        
        /*
        ** Determine whether we do DMA or PIO
        */
        btk_dma_pio(unit_p, type, (bt_devaddr_t) usr_data_p, dest_addr, &requested_length, &dma_flag, &data_width, &start, &need);
#define BTP_FREE_MREG  if (dma_flag) { \
                           btk_mutex_enter(&unit_p->mreg_mutex); \
                           (void) btk_bit_free(unit_p->sdma_aval_p, start, need); \
                           btk_mutex_exit(&unit_p->mreg_mutex); \
                           btk_mutex_exit(&unit_p->dma_mutex);  \
                       } \
                       for (i = 0; i < nr_pages; i++) { \
                           if (BT_RD == dir) { \
                               set_page_dirty_lock(pages[i]); \
                           } \
                           page_cache_release(pages[i]); \
                       } \
                       kfree(pages);
                       

        /*
        ** Can't let PIO go past one page
        */
        if (!dma_flag) {
            if ((usr_curr_offset + requested_length) > PAGE_SIZE) {
                requested_length = PAGE_SIZE - usr_curr_offset;
            }
            need = 1;
        }
        
        TRC_MSG(BT_TRC_RD_WR, 
                (LOG_FMT "Transferring %d bytes data to 0x%lx using %s.\n",
                LOG_ARG, requested_length, dest_addr, ((dma_flag) ? "DMA" : "PIO")));
            
        if (dma_flag) {

            /*
            **  Setup vme address, address modifier, and function code
            */
            mreg_value = 0;
            btk_setup_mreg(unit_p, type, &mreg_value, BT_OP_DMA);

            /*
            ** Program up mapping RAM
            */
            for (inx = start, i = 0; inx < (start + need); inx++, i++) {
                pci_addr = (unsigned long) page_to_phys(pages[i]);
                if (0 == pci_addr) {
                    WARN_STR("Kernel to PCI address translation failed.\n");
                    retval = BT_EIO;
                    goto end_xfer_loop;
                }
                mreg_value &= ~BT_MREG_ADDR_MASK;
                mreg_value |= (pci_addr & BT_MREG_ADDR_MASK);
                btk_put_mreg(unit_p, inx, BT_LMREG_DMA_2_PCI, mreg_value);
                if ( (btk_get_mreg(unit_p, inx, BT_LMREG_DMA_2_PCI)) != mreg_value ) {
                    WARN_MSG((LOG_FMT "Verify Write BT_LMREG_DMA_2_PCI mapping register mr_idx = 0x%.1X failed.\n",
                                                                                 LOG_ARG, inx));
                    retval = BT_EIO;
                    goto end_xfer_loop;
                }
            }

            /*
            ** Now we need to get the DMA semaphore 
            ** Note this routines does nothing in a single driver situtation
            */
            retval = btk_take_drv_sema(unit_p);
            if (retval != BT_SUCCESS) {
                goto end_xfer_loop;
            }

            /*
            ** If old Nanobus card, we must stop PIO from occuring
            */
            if (IS_CLR(unit_p->bt_status, BT_NEXT_GEN)) {
                btk_rwlock_wr_enter(&unit_p->hw_rwlock);
            }
        
            /*
            ** Do the DMA
            */
            ldma_addr = (bt_data32_t) ((start * BT_PAGE_SIZE) + usr_curr_offset);
            xferred_length = requested_length;
            retval = btk_dma_xfer(unit_p, type, ldma_addr, (bt_data32_t) dest_addr, &xferred_length, (dir == BT_RD) ? BT_READ : BT_WRITE, data_width);
            if (IS_CLR(unit_p->bt_status, BT_NEXT_GEN)) {
                btk_rwlock_wr_exit(&unit_p->hw_rwlock);
            }
            btk_give_drv_sema(unit_p);

        /*
        ** Do a PIO
        */
        } else {

            /* 
            ** Perform the proper direction PIO data transfer 
            */
            kbuf_p = kmap(pages[0]);
            if (kbuf_p == NULL) {
                INFO_STR("Failed to get kernel pointer to PIO user buffer");
                retval = BT_EIO;
            } else {
                data_p = (void *) (kbuf_p + usr_curr_offset); 
                xferred_length = requested_length;
                retval = btk_pio_xfer(unit_p, type, data_p, (unsigned long) dest_addr,
                                    &xferred_length, (dir == BT_RD) ? BT_READ : BT_WRITE);
                kunmap(pages[0]);
            }
        }

end_xfer_loop:
        BTP_FREE_MREG;
        TRC_MSG(BT_TRC_RD_WR, 
                (LOG_FMT "%s transfer done 0x%x bytes transferred, retval %d\n",
                LOG_ARG, ((dma_flag) ? "DMA" : "PIO"), xferred_length, retval));

        usr_data_p = (caddr_t) usr_data_p + xferred_length;
        dest_addr += xferred_length;
        length_remaining -= xferred_length;
    }

btp_xfer_end:
    *xferred_bytes_p = length - length_remaining;

    FEXIT(retval);
    return retval;
}