static int
vaudio_thread (void* data)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
    daemonize();
#else
    daemonize("vaudio-fe");
#endif
    data = (void*) vaudio;
    while (!vaudio_thread_aborted) {
	down (&vaudio_thread_sem);

	if ( (vaudio_thread_init_now & 2) ) {
	    vaudio_thread_init_now &= ~2;
	    snd_card_free(vaudio_card);
	    if (vaudio_snd_probe() < 0) {
		ETRACE ("virtual audio ALSA card initialization failed\n");
	    }
	}

	if ( (vaudio_thread_init_now & 1) ) {
	    vaudio_thread_init_now &= ~1;
	    vaudio_snd_init_card(data);
	}
    }
    complete_and_exit(&vaudio_thread_completion, 0);
	/*NOTREACHED*/
    return 0;
}
    static int __init
vaudio_init (void)
{
    ADEBUG();
    sema_init(&vaudio_thread_sem, 0);
    if (vaudio_snd_probe() < 0) {
	ETRACE ("virtual audio ALSA card initialization failed\n");
	return -ENODEV;
    }
    vaudio_thread_id = kernel_thread(vaudio_thread, 0, 0);
    if (vaudio_thread_id < 0) {
	ETRACE ("virtual audio kernel thread creation failure \n");
	return vaudio_thread_id;
    }

#if VAUDIO_PROC_SYNC
    vaudio_proc_create("close");
#endif
    return 0;
}
    static int
vaudio_thread (void* data)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
    daemonize();
#else
    daemonize("vaudio-fe");
#endif
    data = (void*) vaudio;
    while (!vaudio_thread_aborted) {
	down (&vaudio_thread_sem);

#if 0
	if ( (vaudio_thread_init_now & 2) ) {
	    vaudio_thread_init_now &= ~2;
#else
        if ( test_and_clear_bit(1, &vaudio_thread_init_now) ) {
#endif
	    snd_card_free(vaudio_card);
	    if (vaudio_snd_probe() < 0) {
		ETRACE ("virtual audio ALSA card initialization failed\n");
	    }
	}

#if 0
	if ( (vaudio_thread_init_now & 1) ) {
	    vaudio_thread_init_now &= ~1;
#else
        if ( test_and_clear_bit(0, &vaudio_thread_init_now) ) {
#endif
	    data= vaudio_card->private_data;
	    vaudio_snd_init_card(data);
	}
    }
    complete_and_exit(&vaudio_thread_completion, 0);
	/*NOTREACHED*/
    return 0;
}

    static void
vaudio_sysconf_trigger (NkVaudio dev)
{
    DTRACE ("Sending sysconf OS#%d(%d)->OS#%d(%d)\n",
	    dev->vlink->c_id, dev->vlink->c_state,
	    dev->vlink->s_id, dev->vlink->s_state);
    nkops.nk_xirq_trigger(NK_XIRQ_SYSCONF, dev->vlink->s_id);
}

    static int
vaudio_handshake (NkVaudio dev)
{
    volatile int* my_state   = &dev->vlink->c_state;
    const int	  peer_state =  dev->vlink->s_state;

    DTRACE ("handshake OS#%d(%d)->OS#%d(%d)\n",
	    dev->vlink->s_id, peer_state,
	    dev->vlink->c_id, *my_state);

    switch (*my_state) {
    case NK_DEV_VLINK_OFF:
	if (peer_state != NK_DEV_VLINK_ON) {
	    *my_state = NK_DEV_VLINK_RESET;
	    vaudio_sysconf_trigger(dev);
	}
	break;

    case NK_DEV_VLINK_RESET:
	if (peer_state != NK_DEV_VLINK_OFF) {
	    *my_state = NK_DEV_VLINK_ON;
#if 0
	    vaudio_thread_init_now |= 1;
#else
	    set_bit(0, &vaudio_thread_init_now);
#endif
	    up(&vaudio_thread_sem);
	    vaudio_sysconf_trigger(dev);
	}
	break;

    case NK_DEV_VLINK_ON:
	if (peer_state == NK_DEV_VLINK_OFF) {
	    *my_state = NK_DEV_VLINK_OFF;
#if 0
	    vaudio_thread_init_now |= 2;
#else
	    set_bit(1, &vaudio_thread_init_now);
#endif
	    up(&vaudio_thread_sem);
	    vaudio_sysconf_trigger(dev);
	}
	break;
    }
    return (*my_state  == NK_DEV_VLINK_ON) &&
	   (peer_state == NK_DEV_VLINK_ON);
}

    static void
vaudio_sysconf_intr (void* cookie, NkXIrq xirq)
{
    (void) xirq;
    vaudio_handshake ((NkVaudio) cookie);
}