예제 #1
0
/***************************************************************************
 * exit_zion_dmaif
 **************************************************************************/
void
exit_zion_dmaif(void)
{
	zion_params_t *zion_params;
	
	PINFO("Cleanup ZION DMAIF module ...");
	
	/* get ZION parameters */
	zion_params = find_zion (0);
	if (zion_params == NULL)
    {
		return;
    }

  /* Check Fireball */
  if((zion_params->revision & 0xF000) == 0xF000)
    {
      return;
    }
	/* Disable backend interrupts */
	mbus_writew(0, MBUS_ADDR(zion_params, ZION_MBUS_INTGEN_B));	/* INT Gen B Enable */
	zion_disable_mbus_interrupt(zion_params, Dmaif_Int);
	mbus_writew(0, MBUS_ADDR(zion_params, ZION_MBUS_IOSEL));	/* DMA select */
	
	free_zion_dmaif_private_space(ZION_DMAIF_PARAM (zion_params));
	
	PINFO( "done.\n" );
	
	return;
}
예제 #2
0
void zion_audio_proc_event(zion_params_t *zion_params, int bit,
		      int irq, void *dev_id, u16 pci_status)
{
  u16 int_status_12;
  u16 int_status_34;

  /* Read Interrupt Status */
  int_status_12 = mbus_readw(MBUS_ADDR(zion_params, DMA12_Interrupt_Status));
  int_status_34 = mbus_readw(MBUS_ADDR(zion_params, DMA34_Interrupt_Status));

  /* Memorize it ! */
  zion_params->interrupt_bits.AUDIO_INT[0] |= int_status_12;
  zion_params->interrupt_bits.AUDIO_INT[1] |= int_status_34;

  /* Do Nothing Now... */


  /* Clear them */

  if(int_status_12)
    {
      mbus_writew(int_status_12, MBUS_ADDR(zion_params, DMA12_Interrupt_Clear));
    }

  if(int_status_34)
    {
      mbus_writew(int_status_34, MBUS_ADDR(zion_params, DMA34_Interrupt_Clear));
    }

  zion_mbus_int_clear(zion_params, AudioProc_Int);

  return;
}
예제 #3
0
/***************************************************************************
 * init_zion_dmaif
 **************************************************************************/
int
init_zion_dmaif(void)
{
	zion_params_t *zion_params;
	int ret, i;
	
	/* get ZION parameters */
	zion_params = find_zion(0);
	if (zion_params == NULL)
	{
		return -ENODEV;
    }

  /* Check Fireball */
  if((zion_params->revision & 0xF000) == 0xF000)
    {
      PINFO("This is fireball! ZION DMA IF cannot be used!!\n");
      return 0;
    }
	
	/* register fuctions for operation */
	for (i = 0; i < ZION_EDMA_PORT; i++)
    {
		zion_params->zion_operations[ZION_DMAIF + i] = &zion_dmaif_port_fops;
    }
	
	/* Set Private Data Area */
	zion_params->zion_private[ZION_DMAIF] = kmalloc(sizeof(zion_dmaif_params_t), GFP_KERNEL);
	if (ZION_DMAIF_PARAM(zion_params) == NULL)
    {
		PERROR ("Can't get enough space for private data.\n");
		return -ENOMEM;
    }
	
	initialize_zion_dmaif_private_space(ZION_DMAIF_PARAM (zion_params));

#ifndef NEO_DEBUG
	PINFO("ZION DMAIF(EDMA) module ver. %d.%d Installed.\n",
		   DMAIF_MAJORVER, DMAIF_MINORVER);
#else /* NEO_DEBUG */
	PINFO("ZION DMAIF(EDMA) module ver. %d.%d-DEBUG Installed.\n",
		   DMAIF_MAJORVER, DMAIF_MINORVER);
#endif /* !NEO_DEBUG */

	/* enable interruption */
	mbus_writew(ZION_MBUS_DMASEL_ENB, MBUS_ADDR(zion_params, ZION_MBUS_IOSEL));	/* DMA select */
	ret = zion_enable_mbus_interrupt(zion_params, Dmaif_Int, zion_dmaif_event);
	if (ret)
    {
		PERROR ("registering interruption failed.\n");
		return -EINVAL;
    }
	mbus_writew(ZION_MBUS_INTGB_MPU1ENB, MBUS_ADDR(zion_params, ZION_MBUS_INTGEN_B));	/* INT Gen B Enable */

	return 0;
}
예제 #4
0
void debug_print_debugstts( zion_params_t *params, int ch, char *str )
{
	unsigned short extmode = 0;
	int itr = 0;

	for ( itr = 0; itr < 3; ++itr ) {
		/* Disable TestEn all channel */
		mbus_writew( 0, MBUS_ADDR(params, ZION_MBUS_EDMA_EXT_MODE(itr)) );
	}

	/* Test mode 2 */
	mbus_writeb( 0x21, MBUS_ADDR(params, ZION_MBUS_EDMA_EXT_MODE(ch)+1) );
	extmode = (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_EXT_MODE(ch)) );
	PDEBUG( "%sCH%d ExtMode mode 2: 0x%04X\n", str, ch, extmode );

	/* Test mode 5 */
	mbus_writeb( 0x51, MBUS_ADDR(params, ZION_MBUS_EDMA_EXT_MODE(ch)+1) );
	extmode = (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_EXT_MODE(ch)) );
	PDEBUG( "%sCH%d ExtMode mode 5: 0x%04X\n", str, ch, extmode );

	/* Test mode 6 */
	mbus_writeb( 0x61, MBUS_ADDR(params, ZION_MBUS_EDMA_EXT_MODE(ch)+1) );
	extmode = (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_EXT_MODE(ch)) );
	PDEBUG( "%sCH%d ExtMode mode 6: 0x%04X\n", str, ch, extmode );
}
예제 #5
0
static int zionvga_image_reflection(int frame)
{
  u16 reg;
  zion_params_t *params = find_zion(0);
  if(params == NULL){
	return -ENODEV;
  }

  reg = mbus_readw(MBUS_ADDR(params,ZIONVGA_VGA_SETTING));

  if(frame==0)
    {
      reg &= ~(VGA_SEL);
    }
  else
    {
      reg |= VGA_SEL;
    }

  //reg |= (VGA_RSTR_EN|CSC_EN|TRS_ON);
#if defined(CONFIG_P2PF_K240) || defined(CONFIG_P2PF_K202) || defined(CONFIG_P2PF_K246A)
  reg |= (CSC_EN);
#else
  reg |= (CSC_EN|TRS_ON);  //VGA_RSTR_EN is supporsed to be set by TX
#endif //CONFIG_P2PF_K240 || CONFIG_P2PF_K246A

  mbus_writew(reg, MBUS_ADDR(params,ZIONVGA_VGA_SETTING));
  
  //Just for assurance
  reg = mbus_readw(MBUS_ADDR(params,ZIONVGA_VGA_SETTING));

  return 0;
}
예제 #6
0
/***************************************************************************
 * zion_edma_timeout
 * @func
 *		Timedout function of ZION-NEO EDMA
 * @args
 *		unsigned long	*prms	[in/out]:	parameters of ZION driver
 * @return
 * 		void
 * @comment
 * 		static function
 * @author
 * 		H. Hoshino
 **************************************************************************/
static void
zion_edma_timeout(unsigned long prms)
{
	zion_params_t *params = (zion_params_t *)prms;
	int ch = 0;
	zion_edma_params_t *edma_prms = NULL;
	
	/* Check argument */
	if (NULL == params)
    {
		PERROR("Invalid ZION parameters!\n");
		return;
    }
	
	/* Print error message */
	PERROR("Timedout occured!\n");
	
	for (ch = 0; ch < ZION_EDMA_NR_CH; ++ch)
    {
		/* Get EDMA parameters */
		edma_prms =
			&(ZION_DMAIF_PARAM(params)->port_params[ZION_EDMA_DMA_PORTNO(ch)]);
		
		/* Clear DMA command */
      /*  NOTE: Need not write 0 to DmaRun the case of SyncMode = 0 */
		mbus_writew(0, MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch)));
		
		/* Clear interrupt status: DMA done */
		mbus_writew(ZION_MBUS_EDMA_DMADONEINT,
					MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch)));
		
		/* Wake up */
		edma_prms->condition = ZION_DMAIF_DISPATCH_TIMEOUT;
		wake_up(&(edma_prms->zion_dmaif_wait_queue));
    }


	/* for DEBUG XXX */
	debug_print_debugstts( params, 0, "" );
	debug_print_debugstts( params, 2, "" );
	
	debug_print_stts( params, 0, "" );
	debug_print_stts( params, 1, "" );
	debug_print_stts( params, 2, "" );
}
예제 #7
0
static int zionvga_init_phase(struct zionvga_phase_arg *phase)
{
  zion_params_t *params = find_zion(0);
  unsigned short v_phase = phase->v_phase;
  unsigned short h_phase = phase->h_phase;
  if(params == NULL){
	return -ENODEV;
  }

  mbus_writew(v_phase, MBUS_ADDR(params, ZIONVGA_VIDEO_V_PHASE));
  mbus_writew(v_phase, MBUS_ADDR(params, ZIONVGA_SYSTEM_V_PHASE));
  mbus_writew(h_phase, MBUS_ADDR(params, ZIONVGA_VIDEO_H_PHASE));
  mbus_writew(h_phase, MBUS_ADDR(params, ZIONVGA_SYSTEM_H_PHASE));

  // Just for Assurance
  v_phase = mbus_readw(MBUS_ADDR(params, ZIONVGA_VIDEO_V_PHASE));
  v_phase = mbus_readw(MBUS_ADDR(params, ZIONVGA_SYSTEM_V_PHASE));
  h_phase = mbus_readw(MBUS_ADDR(params, ZIONVGA_VIDEO_H_PHASE));
  h_phase = mbus_readw(MBUS_ADDR(params, ZIONVGA_SYSTEM_H_PHASE));

  return 0;
}
예제 #8
0
static int zionvga_rstr_enable(void)
{
  u16 reg;
  zion_params_t *params = find_zion(0);
  if(params == NULL){
	return -ENODEV;
  }

  reg = mbus_readw(MBUS_ADDR(params,ZIONVGA_VGA_SETTING));
  reg |= VGA_RSTR_EN;
  mbus_writew(reg, MBUS_ADDR(params,ZIONVGA_VGA_SETTING));  
  reg = mbus_readw(MBUS_ADDR(params,ZIONVGA_VGA_SETTING)); //Just for assurance
  return 0;
}
예제 #9
0
/***************************************************************************
 * zion_edma_set_region
 * @func
 *		set EDMA buffer addresses
 * @args
 *		zion_params_t	*params	[in]:	parameters of ZION driver
 *		int				dma_ch	[in]:	channel
 *		int				num		[in]:	buffer number
 *		unsigned long	lower	[in]:	lower address
 *		unsigned long	upper	[in]:	upper address
 * @return
 * 		int
 * 		   0		:	success
 * 		   -EINVAL	:	invalid argument
 * @comment
 * 		static function
 * @author
 * 		H. Hoshino
 **************************************************************************/
static int
zion_edma_set_region(zion_params_t * params, int dma_ch,
					 int num, unsigned long lower, unsigned long upper)
{
	unsigned short tlower = (unsigned short)( (lower&0x07FF0000L) >> 16 );
	
	/* Check channel number */
	if (dma_ch >= ZION_EDMA_NR_CH)
    {
		PERROR("Invalid EDMA Channel.\n");
		return (-EINVAL);
    }

	/* for DEBUG */
	PDEBUG( "[CH%d Buf%d] lower: 0x%08lX, tlower: 0x%04X, upper: 0x%08lX\n",
			dma_ch, num, lower, tlower, upper );
	
	/* Set addresses */
	mbus_writew(tlower, MBUS_ADDR(params, ZION_MBUS_EDMA_BUFF_LWR_ADRS(dma_ch, num)));
	mbus_writel(upper,  MBUS_ADDR(params, ZION_MBUS_EDMA_BUFF_UPR_ADRS(dma_ch, num)));
	
	return (0);
}
예제 #10
0
/***************************************************************************
 * zion_dmaif_event
 * @func
 *		Interruption handler for EDMA
 * @args
 *		zion_params_t	*params	[in/out]:	parameters of ZION driver
 *		int				irq		[in]	:	IRQ number
 *		void			*dev_id	[in]	:	Device ID
 *		u16				pci_status[in]	:	PCI config interrupt status
 * @return
 * 		void
 * @comment
 * 		
 * @author
 * 		H. Hoshino
 **************************************************************************/
void
zion_dmaif_event(zion_params_t * params, int bit,
		 int irq, void *dev_id, u16 pci_status)
{
	unsigned short int_status = 0;
	unsigned short int_mask = 0;
	int ch = 0;
	zion_edma_params_t *edma_prms = NULL;
	
	/*** Check EDMA interruption for each channel ***/
	for (ch = 0; ch < ZION_EDMA_NR_CH; ++ch)
    {
		/* Get interrupt status and mask(enable) */
		int_status =
			(unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_INTSTTS(ch)) );
		int_mask =
			(unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_INTENB(ch)) );
		
		/* Memorize it ! */
		params->interrupt_bits.DMA_INT[ch] |= int_status;

		/* for DEBUG */
/* 		PDEBUG( "CH%d int_status: 0x%04X, mask: 0x%04X\n", */
/* 				ch, int_status, int_mask ); */

		/** Check interruptions (Common port) **/
		if ( int_status & int_mask ) {
			/* Get EDMA params */
			edma_prms = &(ZION_DMAIF_PARAM(params)->port_params[ZION_EDMA_CMN_PORTNO(ch)]);

			/* for DEBUG */
/* 			PDEBUG( "[CH%d port%d] Get interruptions!\n", */
/* 					ch, ZION_EDMA_CMN_PORTNO(ch) ); */

			if ( NULL == edma_prms ) {
				PERROR( "[CH%d port%d] EDMA params is NULL!!\n",
						ch, ZION_EDMA_CMN_PORTNO(ch) );

				mbus_writew( (ZION_MBUS_EDMA_DMADONEINT |
							  ZION_MBUS_EDMA_SYNCFRMINT |
							  ZION_MBUS_EDMA_BUFFINT_MASK |
							  ZION_MBUS_EDMA_ERRINT_MASK),
							 MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch)));

				/** Clear interrupt status INT B reg **/
				zion_mbus_int_clear(params, Dmaif_Int);
				
				return;
			}
			
			/* Set interrupt status */
			spin_lock( &(edma_prms->params_lock) ); /* Spin lock */
			edma_prms->int_status |= int_status;
/* 			edma_prms->int_status = int_status; */
			spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */

			/* Wake up */
			spin_lock( &(edma_prms->params_lock) ); /* Spin lock */
			edma_prms->condition = ZION_DMAIF_DISPATCH_DONE;
			spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */
			
			wake_up(&(edma_prms->zion_dmaif_wait_queue));
		}
		
		
		/** Check sync frame pulse interruption **/
		if ( int_status & int_mask & ZION_MBUS_EDMA_SYNCFRMINT )
		{
			/* Get EDMA params */
			edma_prms = &(ZION_DMAIF_PARAM(params)->port_params[ZION_EDMA_FRM_PORTNO(ch)]);

			/* for DEBUG */
/* 			PDEBUG( "[CH%d port%d] Sync frame pulse!\n", */
/* 					ch, ZION_EDMA_FRM_PORTNO(ch) ); */

			/* Set interrupt status */
			spin_lock( &(edma_prms->params_lock) ); /* Spin lock */
			if ( 0 == edma_prms->int_status ) {
				edma_prms->int_status = int_status;
			} else {
/* 				PDEBUG( "[CH%d port%d] int_status is already set(0x%04X, 0x%04X)!\n", */
/* 						ch, ZION_EDMA_DMA_PORTNO(ch), edma_prms->int_status, int_status ); */
			}

			spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */
			
			/* Clear interrupt status: sync frame pulse */
			mbus_writew(ZION_MBUS_EDMA_SYNCFRMINT, MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch)));
			
			/* Wake up */
			spin_lock( &(edma_prms->params_lock) ); /* Spin lock */
			edma_prms->condition = ZION_DMAIF_DISPATCH_DONE;
			spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */
			
			wake_up(&(edma_prms->zion_dmaif_wait_queue));
		}
		
		/** Check DMA done interruption **/
		if ( int_status & int_mask & ZION_MBUS_EDMA_DMADONEINT )
		{
			/* Get EDMA params */
			edma_prms = &(ZION_DMAIF_PARAM(params)->port_params[ZION_EDMA_DMA_PORTNO(ch)]);
			
			/* for DEBUG */
			PDEBUG( "[CH%d port%d] DMA Done!\n",
					ch, ZION_EDMA_DMA_PORTNO(ch) );
/* 			PINFO( "[CH%d port%d] DMA Done!\n", */
/* 					ch, ZION_EDMA_DMA_PORTNO(ch) ); */
			
			/* Stop DMA for G1&G2 transfer mode */
			{
				unsigned char cmd = mbus_readb( MBUS_ADDR(params, (ZION_MBUS_EDMA_DMACMD(ch)+1)) );
				mbus_writeb( (cmd & (~0x02)),
							 MBUS_ADDR(params, (ZION_MBUS_EDMA_DMACMD(ch)+1)) );
			}

			/* for DEBUG XXX*/
/* 			{ */
/* 				unsigned short usPMT = mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_CURRPMT(ch)) ); */
/* 				PDEBUG( "[CH%d port%d] CurrPMT: 0x%04X\n", */
/* 						ch, ZION_EDMA_DMA_PORTNO(ch), usPMT ); */
/* 			} */
			
			
			spin_lock( &(edma_prms->params_lock) ); /* Spin lock */
			
			/* Set interrupt status */
/* 			PDEBUG( "[CH%d] int_status: 0x%04X, old: 0x%04X!\n", */
/* 					ch, int_status, edma_prms->int_status ); */
			if ( 0 == edma_prms->int_status ) {
				edma_prms->int_status = int_status;
			} else {
/* 				PDEBUG( "[CH%d port%d] int_status is already set(0x%04X, 0x%04X)!\n", */
/* 						ch, ZION_EDMA_DMA_PORTNO(ch), edma_prms->int_status, int_status ); */
			}

			
			/* Delete timer */
			del_timer_sync(&(edma_prms->timer));
			spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */
			
			/* Clear interrupt status: DMA done */
			mbus_writew(ZION_MBUS_EDMA_DMADONEINT,
						MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch)));
			
			/* Wake up */
			spin_lock( &(edma_prms->params_lock) ); /* Spin lock */
			edma_prms->condition = ZION_DMAIF_DISPATCH_DONE;
			spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */
			
			wake_up(&(edma_prms->zion_dmaif_wait_queue));
		}
		
		
		/** Check error and buffer empty/almost empty/almost full/full interruption **/
		if ( int_status & int_mask &
			 (ZION_MBUS_EDMA_BUFFINT_MASK | ZION_MBUS_EDMA_ERRINT_MASK) )
		{
			/* Get EDMA parameters */
			edma_prms = &(ZION_DMAIF_PARAM (params)->port_params[ZION_EDMA_BUF_PORTNO(ch)]);

			/* for DEBUG */
			PDEBUG( "[CH%d port%d] Error or warning!\n",
					ch, ZION_EDMA_BUF_PORTNO(ch) );

			/* Set interrupt status */
			spin_lock( &(edma_prms->params_lock) ); /* Spin lock */
			
/* 			PDEBUG( "[CH%d] int_status: 0x%04X, old: 0x%04X!\n", */
/* 					ch, int_status, edma_prms->int_status ); */
			if ( 0 == edma_prms->int_status ) {
				edma_prms->int_status = int_status;
			} else {
/* 				PDEBUG( "[CH%d port%d] int_status is already set(0x%04X, 0x%04X)!\n", */
/* 						ch, ZION_EDMA_BUF_PORTNO(ch), edma_prms->int_status, int_status ); */
			}
			
			spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */
			
			/* Clear interrupt status */
			mbus_writew((ZION_MBUS_EDMA_BUFFINT_MASK | ZION_MBUS_EDMA_ERRINT_MASK),
						MBUS_ADDR(params, ZION_MBUS_EDMA_INTCLR(ch)));
			
			/* Wake up */
			spin_lock( &(edma_prms->params_lock) ); /* Spin lock */
			edma_prms->condition = ZION_DMAIF_DISPATCH_DONE;
			spin_unlock( &(edma_prms->params_lock) ); /* Unlock spin lock */
			
			wake_up(&(edma_prms->zion_dmaif_wait_queue));
		}
    }	/* The end of FOR(ch) */

	/** Clear interrupt status INT B reg **/
	zion_mbus_int_clear(params, Dmaif_Int);

/* 	PDEBUG ("exit %s\n", __FUNCTION__); */
	
  return;
}
예제 #11
0
int zion_set_params(struct zionvga_reset_arg *reset_arg)
{
  u16 reg = 0;
  int pal_line = reset_arg->pal_line;
  int spl_line = reset_arg->spl_line;
  zion_params_t *params = find_zion(0);
  if(params == NULL){
	return -ENODEV;
  }

  reg = mbus_readw(MBUS_ADDR(params,ZIONVGA_VGA_SETTING));

  reg &= VGA_RSTR_EN;  //Don't touch VGA_RSTR_EN bit (It should be set by TX)

  if(pal_line==576)
    {
      reg |= PAL_LINE_SEL;
      ZIONVGA_Y_RES = 576;
    }
  else if(pal_line==480)
    {
      reg &= ~PAL_LINE_SEL;
      ZIONVGA_Y_RES = 480;
    }
  else
    {
      PERROR("Unsupported VGA SIZE : PAL-Line=%d",pal_line);
      return -EINVAL;
    }

  if(spl_line==720)
    {
      reg |= SPL_SEL;
      ZIONVGA_X_RES = 720;
    }
  else if(spl_line==640)
    {
      reg &= ~SPL_SEL;
      ZIONVGA_X_RES = 640;
    }
  else
    {
      PERROR("Unsupported VGA SIZE : SPL-Line=%d",spl_line);
      return -EINVAL;      
    }

#if defined(CONFIG_P2PF_K240) || defined(CONFIG_P2PF_K202) || defined(CONFIG_P2PF_K246A)
  reg |= (CSC_EN);
#else
  reg |= (CSC_EN|TRS_ON);
#endif //CONFIG_P2PF_K240 || CONFIG_P2PF_K246A

  mbus_writew(reg, MBUS_ADDR(params,ZIONVGA_VGA_SETTING));

  // Just for assurance
  reg = mbus_readw(MBUS_ADDR(params,ZIONVGA_VGA_SETTING));

  zionvga_encode_var( &default_var );
  zion_fb_info.fb_info.var = default_var;

  return 0;
}
예제 #12
0
static int zion_common_ioctl(zion_params_t *zion_params,
			     struct inode *inode, struct file *filp,
			     unsigned int function, unsigned long arg)
{
  struct zion_config_byte zion_config_byte = {0};
  struct zion_config_word zion_config_word = {0};
  struct zion_config_dword zion_config_dword = {0};
  struct zion_buf zion_buf;
  struct ZION_Interrupt_Bits zion_interrupt = {0};
  u16 revision;

  switch(function)
    {
    case ZION_MBUS_READ_CONFIG_BYTE:

      if(copy_from_user((void *)&zion_config_byte, (void *)arg, sizeof(struct zion_config_byte)))
	return -EFAULT;

      zion_config_byte.val = (u8) mbus_readb( MBUS_ADDR(zion_params, zion_config_byte.where) );

      if(copy_to_user((void *)arg, (void *)&zion_config_byte, sizeof(struct zion_config_byte)))
	return -EFAULT;

      break;

    case ZION_MBUS_READ_CONFIG_WORD:

      if(copy_from_user((void *)&zion_config_word, (void *)arg, sizeof(struct zion_config_word)))
	return -EFAULT;

      zion_config_word.val = (u16) mbus_readw( MBUS_ADDR(zion_params,zion_config_word.where) );

      if(copy_to_user((void *)arg, (void *)&zion_config_word, sizeof(struct zion_config_word)))
	return -EFAULT;

      break;

    case ZION_MBUS_READ_CONFIG_DWORD:

      if(copy_from_user((void *)&zion_config_dword, (void *)arg, sizeof(struct zion_config_dword)))
	return -EFAULT;

      zion_config_dword.val = (u32) mbus_readl( MBUS_ADDR(zion_params,zion_config_dword.where) );

      if(copy_to_user((void *)arg, (void *)&zion_config_dword, sizeof(struct zion_config_dword)))
	return -EFAULT;

      break;

    case ZION_MBUS_WRITE_CONFIG_BYTE:

      if(copy_from_user((void *)&zion_config_byte, (void *)arg, sizeof(struct zion_config_byte)))
	return -EFAULT;

       mbus_writeb(zion_config_byte.val, MBUS_ADDR(zion_params, zion_config_byte.where) );

      if(copy_to_user((void *)arg, (void *)&zion_config_byte, sizeof(struct zion_config_byte)))
	return -EFAULT;

      break;
	
    case ZION_MBUS_WRITE_CONFIG_WORD:

      if(copy_from_user((void *)&zion_config_word, (void *)arg, sizeof(struct zion_config_word)))
	return -EFAULT;

       mbus_writew(zion_config_word.val, MBUS_ADDR(zion_params, zion_config_word.where) );

      if(copy_to_user((void *)arg, (void *)&zion_config_word, sizeof(struct zion_config_word)))
	return -EFAULT;

      break;

    case ZION_MBUS_WRITE_CONFIG_DWORD:

      if(copy_from_user((void *)&zion_config_dword, (void *)arg, sizeof(struct zion_config_dword)))
	return -EFAULT;

       mbus_writel(zion_config_dword.val, MBUS_ADDR(zion_params, zion_config_dword.where) );

      if(copy_to_user((void *)arg, (void *)&zion_config_dword, sizeof(struct zion_config_dword)))
	return -EFAULT;

      break;

    case ZION_WRAM_READ:

      if(copy_from_user((void *)&zion_buf, (void *)arg, sizeof(struct zion_buf)))
	return -EFAULT;

      if((zion_buf.size = neo_wram_pio_read(zion_params, zion_buf.addr, zion_buf.buf, zion_buf.size, zion_buf.access_type))==0)
	return -EINVAL;

      if(copy_to_user((void *)arg, (void *)&zion_buf, sizeof(struct zion_buf)))
	return -EFAULT;

      break;

    case ZION_WRAM_WRITE:

      if(copy_from_user((void *)&zion_buf, (void *)arg, sizeof(struct zion_buf)))
	return -EFAULT;

      if((zion_buf.size = neo_wram_pio_write(zion_params, zion_buf.addr, zion_buf.buf, zion_buf.size, zion_buf.access_type))==0)
	return -EINVAL;

      if(copy_to_user((void *)arg, (void *)&zion_buf, sizeof(struct zion_buf)))
	return -EFAULT;

      break;

    case ZION_WAIT_INTERRUPT:

      zion_goto_bed(zion_params, &zion_interrupt);  /* zion_interrupt.c */

      if(copy_to_user((void *)arg, (void *)&zion_interrupt, sizeof(struct ZION_Interrupt_Bits)))
	return -EFAULT;

      break;

    case ZION_WAKE_THREADS_UP:

      zion_rout_them_up(zion_params);    /* zion_interrupt.c */

      break;

    case ZION_SET_ENABLE_BITS:

      if(copy_from_user((void *)&zion_interrupt, (void *)arg, sizeof(struct ZION_Interrupt_Bits)))
	return -EFAULT;

      zion_set_enable_bits(zion_params, &zion_interrupt);  /* zion_interrupt.c */

      break;

    case ZION_GET_ENABLE_BITS:

      zion_get_enable_bits(zion_params, &zion_interrupt);  /* zion_interrupt.c */

      if(copy_to_user((void *)arg, (void *)&zion_interrupt, sizeof(struct ZION_Interrupt_Bits)))
	return -EFAULT;

      break;

    case ZION_SET_TIMEOUT:

      zion_params->wait_timeout = arg;  /* by jiffies */

      break;

    case ZION_GET_REVISION:
      revision = zion_params->revision;
      if(copy_to_user((void *)arg, (void *)&revision, sizeof(u16)))
	{
	  return -EFAULT;
	}
      break;

    default:
      PERROR("No such IOCTL.\n");
      return -EINVAL;
    }

  return 0;
}