static void VibeOSKernelLinuxTerminateTimer(void)
{
    VibeOSKernelLinuxStopTimer();
    if (VibeSemIsLocked(&g_hMutex)) up(&g_hMutex);
}
static int VibeOSKernelProcessData(void* data)
{
    int i;
    int nActuatorNotPlaying = 0;

    for (i = 0; i < NUM_ACTUATORS; i++) 
    {
        actuator_samples_buffer *pCurrentActuatorSample = &(g_SamplesBuffer[i]);

        if (-1 == pCurrentActuatorSample->nIndexPlayingBuffer)
        {
            nActuatorNotPlaying++;
            if ((NUM_ACTUATORS == nActuatorNotPlaying) && ((++g_nWatchdogCounter) > WATCHDOG_TIMEOUT))
            {
                /* Nothing to play for all actuators, turn off the timer when we reach the watchdog tick count limit */
                ImmVibeSPI_ForceOut_Set(i, 0);
                ImmVibeSPI_ForceOut_AmpDisable(i);
                VibeOSKernelLinuxStopTimer();

                /* Reset watchdog counter */
                g_nWatchdogCounter = 0;
            }
        }
        else
        {
            /* Play the current buffer */
            if (VIBE_E_FAIL == ImmVibeSPI_ForceOut_SetSamples(
                pCurrentActuatorSample->actuatorSamples[(int)pCurrentActuatorSample->nIndexPlayingBuffer].nActuatorIndex, 
                pCurrentActuatorSample->actuatorSamples[(int)pCurrentActuatorSample->nIndexPlayingBuffer].nBitDepth, 
                pCurrentActuatorSample->actuatorSamples[(int)pCurrentActuatorSample->nIndexPlayingBuffer].nBufferSize,
                pCurrentActuatorSample->actuatorSamples[(int)pCurrentActuatorSample->nIndexPlayingBuffer].dataBuffer))
            {
                /* VIBE_E_FAIL means NAK has been handled. Schedule timer to restart 5 ms from now */
                hrtimer_forward_now(&g_tspTimer, g_ktFiveMs);
            }

            pCurrentActuatorSample->nIndexOutputValue += pCurrentActuatorSample->actuatorSamples[(int)pCurrentActuatorSample->nIndexPlayingBuffer].nBufferSize;

            if (pCurrentActuatorSample->nIndexOutputValue >= pCurrentActuatorSample->actuatorSamples[(int)pCurrentActuatorSample->nIndexPlayingBuffer].nBufferSize)
            {
                /* Reach the end of the current buffer */
                pCurrentActuatorSample->actuatorSamples[(int)pCurrentActuatorSample->nIndexPlayingBuffer].nBufferSize = 0;

                /* Switch buffer */
                (pCurrentActuatorSample->nIndexPlayingBuffer) ^= 1;
                pCurrentActuatorSample->nIndexOutputValue = 0;

                /* Finished playing, disable amp for actuator (i) */
                if (g_bStopRequested)
                {
                    pCurrentActuatorSample->nIndexPlayingBuffer = -1; 

                    ImmVibeSPI_ForceOut_AmpDisable(i);
                }
            }
        }
    }

    /* If finished playing, stop timer */
    if (g_bStopRequested)
    {
        VibeOSKernelLinuxStopTimer();

        /* Reset watchdog counter */
        g_nWatchdogCounter = 0;

        if (VibeSemIsLocked(&g_hMutex)) up(&g_hMutex);
        return 1;   /* tell the caller this is the last iteration */
    }

	return 0;
}