Ejemplo n.º 1
0
void debug_print_stts( zion_params_t *params, int ch, char *str )
{
	unsigned short edma_stts
		= (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_EDMA_STATE(ch)) );
	unsigned char sbus_stts
		= mbus_readb( MBUS_ADDR(params, (ZION_MBUS_EDMA_INT_SBUS_STATE(ch)+1)) );
/* 	unsigned short sbus_stts */
/* 		= mbus_readw( MBUS_ADDR(params, (ZION_MBUS_EDMA_INT_SBUS_STATE(ch))) ); */
	PDEBUG( "%sCH%d EDMA state: 0x%04X, SBUS state: 0x%02X\n",
			str, ch ,edma_stts, sbus_stts );
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
/***************************************************************************
 * zion_dmaif_port_ioctl
 **************************************************************************/
int
zion_dmaif_port_ioctl(zion_params_t * params,
					  struct inode *inode, struct file *file,
					  unsigned int function, unsigned long arg)
{
	switch (function)
    {
		
    case ZION_EDMA_IOC_OPEN:
	{
		unsigned char ucReg = 0;
		zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data;
		int ch = -1;
		int rw = -1;
		unsigned long irq_flags = 0;
		
		/* Check EDMA parameters */
		if (NULL == edma_prms)
		{
			PERROR("Private data is NULL!\n");
			return (-ENODEV);
		}
		
		/* Get and check EDMA channel number */
		ch = edma_prms->ch_no;
		if (ch < 0 || ZION_EDMA_NR_CH <= ch)
		{
			PERROR("Invalid ZION EDMA channel number(%d)!", ch);
			return (-ENODEV);
		}
		
		/* Get argument: I/O direction */
		if (copy_from_user((void *)&rw, (void *)arg, sizeof(int)))
			return (-EFAULT);
		
		/* Check argument: I/O direction */
		if ((ZION_EDMA_READ != rw) && (ZION_EDMA_WRITE != rw))
		{
			PERROR("[CH%d] Invalid I/O direction(%d)!\n", ch, rw);
			return (-EINVAL);
		}
		
		/* Read EDMA command register */
		ucReg = mbus_readb(MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1));
		
		/* Write EDMA command register: DmaOpen=1 */
		ucReg |= (ZION_MBUS_EDMA_OPEN | (rw << 2)) & 0x0F;
/* 		PDEBUG("[CH%d] EDMA open(0x%02X)\n", ch, ucReg); */
		mbus_writeb(ucReg, MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1));

		/* Clear interrupt status */
		spin_lock_irqsave( &(edma_prms->params_lock), irq_flags );
		edma_prms->int_status = 0x0000;
		spin_unlock_irqrestore( &(edma_prms->params_lock), irq_flags );
		
		break;
	}
	
    case ZION_EDMA_IOC_CLOSE:
	{
		unsigned char ucReg = 0;
		zion_edma_params_t *edma_prms =
			(zion_edma_params_t *)file->private_data;
		int ch = -1;
		
		/* Check EDMA parameters */
		if (NULL == edma_prms)
		{
			PERROR("Private data is NULL!\n");
			return (-ENODEV);
		}
		
		/* Get and check EDMA channel number */
		ch = edma_prms->ch_no;
		if (ch < 0 || ZION_EDMA_NR_CH <= ch)
		{
			PERROR("Invalid ZION EDMA channel number(%d)!", ch);
			return (-ENODEV);
		}
		
		/* Read EDMA command register */
		ucReg = mbus_readb( MBUS_ADDR(params, (ZION_MBUS_EDMA_DMACMD(ch)+1)) );
		
		/* Write EDMA command register: DmaOpen=0 */
		ucReg &= ZION_MBUS_EDMA_CLOSE & 0x0F;
/* 		PDEBUG("[CH%d] EDMA close(0x%02X)\n", ch, ucReg); */
		mbus_writeb( ucReg, MBUS_ADDR(params, (ZION_MBUS_EDMA_DMACMD(ch)+1)) );
		
		/* Success */
		break;
	}
	
    case ZION_EDMA_IOC_RUN:
	{
		unsigned char ucReg = 0;
		zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data;
		int ch = -1;

		unsigned short usCmdReg = 0;
		
		/* Check EDMA parameters */
		if (NULL == edma_prms)
		{
			PERROR("Private data is NULL!\n");
			return (-ENODEV);
		}
		
		/* Get and check EDMA channel number */
		ch = edma_prms->ch_no;
		if (ch < 0 || ZION_EDMA_NR_CH <= ch)
		{
			PERROR("Invalid ZION EDMA channel number(%d)!", ch);
			return (-ENODEV);
		}
		
		/* Read EDMA command register */
		ucReg = mbus_readb(MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1));
		
		/* Write EDMA command register: DmaRun=1 */
		ucReg |= ZION_MBUS_EDMA_RUN;
		PDEBUG ("[CH%d] EDMA run(0x%02X)\n", ch, ucReg);
		mbus_writeb(ucReg, MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1));

#ifdef NEO_WRITEBACK
		/* for DEBUG -- write back XXX */
		usCmdReg = (unsigned short)mbus_readw( MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(edma_prms->ch_no)) );
/* 		PDEBUG( "[CH%d] Write back DMA RUN: 0x%04X\n", */
/* 				edma_prms->ch_no, usCmdReg ); */
#endif /* NEO_WRITEBACK */
		
		/* Success */
		break;
	}
	
    case ZION_EDMA_IOC_STOP:
	{
		unsigned char ucReg = 0;
		zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data;
		int ch = -1;
		
		/* Check EDMA parameters */
		if (NULL == edma_prms)
		{
			PERROR("Private data is NULL!\n");
			return (-ENODEV);
		}
		
		/* Get and check EDMA channel number */
		ch = edma_prms->ch_no;
		if (ch < 0 || ZION_EDMA_NR_CH <= ch)
		{
			PERROR("Invalid ZION EDMA channel number(%d)!", ch);
			return (-ENODEV);
		}
		
		/* Read EDMA command register */
		ucReg = mbus_readb(MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1));
		
		/* Write EDMA command register: DmaRun=0 */
		ucReg &= ZION_MBUS_EDMA_STOP & 0x0F;
/* 		PDEBUG("[CH%d] EDMA stop(0x%02X)\n", ch, ucReg); */
		mbus_writeb(ucReg, MBUS_ADDR(params, ZION_MBUS_EDMA_DMACMD(ch) + 1));
		
		/* Success */
		break;
	}
	
    case ZION_EDMA_IOC_READ:
	{
		/* EDMA read */
		return (zion_edma_run(params, inode, file, ZION_EDMA_READ));
	}
	
	
    case ZION_EDMA_IOC_WRITE:
	{
		/* EDMA write */
		return (zion_edma_run(params, inode, file, ZION_EDMA_WRITE));
	}
	
	
    case ZION_EDMA_IOC_SET_REGION:
	{
		struct zion_edma_region s_zion_edma_region;
		
		if (copy_from_user((void *)&s_zion_edma_region,
						   (void *)arg, sizeof(struct zion_edma_region)))
			return (-EFAULT);
		
		return zion_edma_set_region(params,
									s_zion_edma_region.dma_ch,
									s_zion_edma_region.num,
									s_zion_edma_region.lower,
									s_zion_edma_region.upper);
	}
	
	
    case ZION_EDMA_IOC_GET_REGION:
	{
		struct zion_edma_region s_zion_edma_region;
		
		if (copy_from_user((void *)&s_zion_edma_region,
						   (void *)arg, sizeof(struct zion_edma_region)))
			return (-EFAULT);
		
		if (zion_edma_get_region(params,
								 s_zion_edma_region.dma_ch,
								 s_zion_edma_region.num,
								 &s_zion_edma_region.lower,
								 &s_zion_edma_region.upper))
			return -EINVAL;
		
		if (copy_to_user((void *)arg,
						 (void *)&s_zion_edma_region,
						 sizeof(struct zion_edma_region)))
			return -EFAULT;
		
		/* Success */
		break;
	}
	
	/* Get interrupt status for poll-select */
    case ZION_EDMA_IOC_GET_INTSTTS:
	{
		zion_edma_params_t *edma_prms = (zion_edma_params_t *)file->private_data;
		int ch = -1;
		unsigned long irq_flags = 0;
		
		/* Check EDMA parameters */
		if (NULL == edma_prms)
		{
			PERROR("Invalid ZION EDMA parameters!\n");
			return (-ENODEV);
		}
		
		/* Set and check EDMA channel number */
		ch = edma_prms->ch_no;
		if (ch < 0 || ZION_EDMA_NR_CH <= ch)
		{
			PERROR("Invalid ZION EDMA channel number(%d)!", ch);
			return (-ENODEV);
		}
		
		/* Set interrupt status */
		if (copy_to_user((void *)arg, (void *)&(edma_prms->int_status),
						 sizeof(unsigned short)))
			return (-EFAULT);

		/* Clear interrupt status */
		spin_lock_irqsave( &(edma_prms->params_lock), irq_flags );
		edma_prms->int_status = 0x0000;
		spin_unlock_irqrestore( &(edma_prms->params_lock), irq_flags );
		
		/* Success */
		break;
	}
	
    default:
		PERROR("No such Ioctl command!\n");
		return (-EINVAL);
		
    } /* The end of SWITCH(function) */
	
	return 0;
}
Ejemplo n.º 4
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;
}