static enum acipc_return_code acipc_event_unbind(u32 user_event)
{
	u32 i;

	IPC_ENTER();

	for (i = 0; i < ACIPC_NUMBER_OF_EVENTS; i++) {
		if (acipc->acipc_db.event_db[i].mask & user_event) {
			if (acipc->acipc_db.event_db[i].IIR_bit & user_event) {
				acipc_int_disable(acipc->acipc_db.event_db[i].
						  IIR_bit);
				acipc->acipc_db.event_db[i].cb =
				    acipc_default_callback;
				acipc->acipc_db.event_db[i].mode =
				    ACIPC_CB_NORMAL;
				acipc->acipc_db.event_db[i].mask = 0;
			}
			/* clean this event from other event's mask */
			acipc->acipc_db.event_db[i].mask &= ~user_event;
		}
	}

	IPC_LEAVE();
	return ACIPC_RC_OK;
}
acipc_return_code acipc_event_bind(u32 user_event, acipc_rec_event_callback cb, 
		acipc_callback_mode cb_mode, u32 *historical_event_status)
{
	u32 i;

	IPC_ENTER();
	for (i=0;i<ACIPC_NUMBER_OF_EVENTS;i++)
	{
		if (acipc->acipc_db.event_db[i].IIR_bit & user_event)
		{
			if (acipc->acipc_db.event_db[i].cb != acipc_default_callback)
				return(ACIPC_EVENT_ALREADY_BIND);
			else
			{
				acipc->acipc_db.event_db[i].cb = cb;
				acipc->acipc_db.event_db[i].mode = cb_mode;
				acipc->acipc_db.event_db[i].mask = user_event &
					acipc->acipc_db.event_db[i].IIR_bit;
				acipc_int_enable(acipc->acipc_db.event_db[i].IIR_bit);
			}
		}
	} 
	/* if there were historical events*/
	if (acipc->acipc_db.historical_event_status & user_event)
	{
		*historical_event_status = 
			acipc->acipc_db.historical_event_status & user_event;
		/* clear the historical events from the database*/
		acipc->acipc_db.historical_event_status &= ~user_event; 
		return (ACIPC_HISTORICAL_EVENT_OCCUR);
	}

	IPC_LEAVE();
	return ACIPC_RC_OK;
}
static enum acipc_return_code acipc_event_set(enum acipc_events user_event)
{
	IPC_ENTER();
	acipc_writel_withdummy(IPC_ISRW, user_event);
	IPCTRACE("acipc_event_set userEvent 0x%x\n", user_event);

	IPC_LEAVE();
	return ACIPC_RC_OK;
}
static irqreturn_t acipc_interrupt_handler(int irq, void *dev_id)
{
	u32 i, on_events;

	IPC_ENTER();
	ACIPC_IIR_READ(acipc->IIR_val); /* read the IIR*/

	/*using ACIPCEventStatusGet might cause getting here with IIR=0*/
	if (acipc->IIR_val) 
	{	
		for (i = 0; i < ACIPC_NUMBER_OF_EVENTS; i++)
		{
			/* NOTE: if the driver state is 'NO_DDR' the following 
			 * condition will ignore events that configure to be 
			 * called only when DDR availble. currently this will 
			 * leave the event bit on meaning the LISR will be called
			 * upon release interrupts.thus the driver state must be restore 
			 * ( to NORMAL) before release the interrupts
			 */
#if 0
			if ((acipc->acipc_db.event_db[i].IIR_bit & acipc->IIR_val)&&
			   (!((acipc->acipc_db.driver_mode == ACIPC_CB_ALWAYS_NO_DDR)&&
			   (acipc->acipc_db.event_db[i].mode == ACIPC_CB_NORMAL)))){
#else
			if ((acipc->acipc_db.event_db[i].IIR_bit & acipc->IIR_val) &&
				(acipc->acipc_db.event_db[i].mode == ACIPC_CB_NORMAL)) {
#endif
				on_events = (acipc->IIR_val)&(acipc->acipc_db.event_db[i].mask);
				/* call the user callback with the status of other 
				 * events as define when the user called ACIPCEventBind
				 */
				acipc->acipc_db.event_db[i].cb(on_events);
				/* clean the event(s)*/
				acipc_writel(IPC_ICR, on_events);
				/* if more then one event exist we clear 
				 * the rest of the bits from the global 
				 * IIR_val so user callback will be called only once.
				 */ 
				
				acipc->IIR_val &= (~on_events);
			}
		}
	}

	IPC_LEAVE();

	return IRQ_HANDLED;
}

u32 user_callback(u32 events_status)
{
	acipc->bind_event_arg = events_status;
	acipc->poll_status = 1;
	wake_up_interruptible(&acipc->acipc_wait_q);

	return 0;
}
acipc_return_code acipc_event_set(acipc_events user_event)
{
	IPC_ENTER();
	acipc_writel(IPC_ISRW, user_event);
	IPCTRACE("acipc_event_set userEvent 0x%x\n", user_event);
	
	IPC_LEAVE();
	return(ACIPC_RC_OK);
}
static enum acipc_return_code acipc_data_read(acipc_data *data)
{
	IPC_ENTER();
	/* reading the data from RDR */
	*data = acipc_readl(IPC_RDR);

	IPC_LEAVE();

	return ACIPC_RC_OK;
}
static u32 acipc_default_callback(u32 status)
{
	IPC_ENTER();
	/* getting here means that the client didn't yet bind his callback.
	 * we will save the event until the bind occur
	 */
	acipc->acipc_db.historical_event_status += status;

	IPC_LEAVE();
	return 0 ;
}
static void acipc_change_driver_state(int is_DDR_ready)
{
	IPC_ENTER();

	IPCTRACE("acipc_change_driver_state isDDRReady %d\n", is_DDR_ready);
	if (is_DDR_ready)
		acipc->acipc_db.driver_mode = ACIPC_CB_NORMAL;
	else
		acipc->acipc_db.driver_mode = ACIPC_CB_ALWAYS_NO_DDR;

	IPC_LEAVE();
}
acipc_return_code acipc_data_send(acipc_events user_event, acipc_data data)
{
	IPC_ENTER();
	IPCTRACE("acipc_data_send userEvent 0x%x, data 0x%x\n", user_event, data);
	/* writing the data to WDR*/
	acipc_writel(IPC_WDR, data);
	
	/* fire the event to the other subsystem 
	 * to indicate the data is ready for read
	 */ 
	acipc_writel(IPC_ISRW, user_event);

	IPC_LEAVE();
	return ACIPC_RC_OK;
}
static irqreturn_t acipc_interrupt_handler(int irq, void *dev_id)
{
	u32 i, on_events;

	IPC_ENTER();
	ACIPC_IIR_READ(acipc->IIR_val);	/* read the IIR */
	/* using ACIPCEventStatusGet might cause getting here with IIR=0 */
	if (acipc->IIR_val) {
		for (i = 0; i < ACIPC_NUMBER_OF_EVENTS; i++) {
			if ((acipc->acipc_db.event_db[i].IIR_bit &
			     acipc->IIR_val)
			    && (acipc->acipc_db.event_db[i].mode ==
				ACIPC_CB_NORMAL)) {
				on_events =
				    (acipc->IIR_val) & (acipc->acipc_db.
							event_db[i].mask);

				/* clean the event(s) */
				acipc_writel_withdummy(IPC_ICR, on_events);

				/*
				 * call the user callback with the status
				 * of other events as define when the user
				 * called ACIPCEventBind
				 */
				acipc->acipc_db.event_db[i].cb(on_events);

				/*
				 * if more then one event exist we clear
				 * the rest of the bits from the global
				 * IIR_val so user callback will be called
				 * only once.
				 */
				acipc->IIR_val &= (~on_events);
			}
		}
	}

	IPC_LEAVE();

	return IRQ_HANDLED;
}
acipc_return_code acipc_event_status_get(u32 user_event, u32 *status)
{
	u32 IIR_local_val;

	IPC_ENTER();
	/* reading the status from IIR*/
	ACIPC_IIR_READ(IIR_local_val);

	/* clear the events hw status*/
	acipc_writel(IPC_ICR, user_event);

	/* verify that this event will be cleared from the global IIR variable. 
	 * for cases this API is called from user callback
	 */
	acipc->IIR_val &= ~(user_event);

	*status = IIR_local_val & user_event;

	IPC_LEAVE();
	return ACIPC_RC_OK;
}