static enum hrtimer_restart VibeOSKernelTimerProc(struct hrtimer *timer)
{
    /* Return right away if timer is not supposed to run */
    if (!g_bTimerStarted) return  HRTIMER_NORESTART;

    /* Scheduling next timeout value right away */
    if (++g_nWatchdogCounter < WATCHDOG_TIMEOUT)
        hrtimer_forward_now(timer, g_ktTimerPeriod);

    if (VibeSemIsLocked(&g_hSemaphore))
    {
        up(&g_hSemaphore);
    }

   if (g_nWatchdogCounter < WATCHDOG_TIMEOUT)
   {
       return HRTIMER_RESTART;
   }
   else
   {
       /* Do not call SPI functions in this function as their implementation coud use interrupt */
       VibeOSKernelLinuxStopTimer();
       return HRTIMER_NORESTART;
   }
}
Example #2
0
static void VibeOSKernelLinuxTerminateTimer(void)
{
    VibeOSKernelLinuxStopTimer();
    del_timer_sync(&g_timerList);

    if (VibeSemIsLocked(&g_hSemaphore)) up(&g_hSemaphore);
}
static void VibeOSKernelLinuxTerminateTimer(void)
{
    VibeOSKernelLinuxStopTimer();
    hrtimer_cancel(&g_tspTimer);

    if (VibeSemIsLocked(&g_hSemaphore)) up(&g_hSemaphore);
}
static void VibeOSKernelLinuxStartTimer(void)
{
	int i;
	int res;

	/* Reset watchdog counter */
	g_nWatchdogCounter = 0;

	if (!g_bTimerStarted) {
		if (!VibeSemIsLocked(&g_hMutex))
			res = down_interruptible(&g_hMutex); /* start locked */

		g_bTimerStarted = true;

		/* Start the timer */
		hrtimer_start(&g_tspTimer, g_ktFiveMs, HRTIMER_MODE_REL);

		/* Don't block the write() function after the first sample to allow the host sending the next samples with no delay */
		for (i = 0; i < NUM_ACTUATORS; i++) {
			if ((g_SamplesBuffer[i].actuatorSamples[0].nBufferSize) || (g_SamplesBuffer[i].actuatorSamples[1].nBufferSize)) {
				g_SamplesBuffer[i].nIndexOutputValue = 0;
				return;
			}
		}
	}
	/*
	** Use interruptible version of down to be safe
	** (try to not being stuck here if the mutex is not freed for any reason)
	*/
	res = down_interruptible(&g_hMutex); /* wait for the mutex to be freed by the timer */
	if (res != 0)
		DbgOut((KERN_INFO "VibeOSKernelLinuxStartTimer: down_interruptible interrupted by a signal.\n"));
}
static void VibeOSKernelLinuxTerminateTimer(void)
{
    VibeOSKernelLinuxStopTimer();
    g_bTimerThreadStarted = false;
    complete_all(&g_tspCompletion);
    kthread_stop(g_pTspThread);
    if (VibeSemIsLocked(&g_hMutex)) up(&g_hMutex);
}
static void tsp_timer_interrupt(unsigned long param)
{
    /* Scheduling next timeout value right away */
    mod_timer(&g_timerList, jiffies + TIMER_INCR);

    if(g_bTimerStarted) {
        if (VibeSemIsLocked(&g_hMutex)) up(&g_hMutex);
    }
}
Example #7
0
static enum hrtimer_restart tsp_timer_interrupt(struct hrtimer *timer)
{
	/* Scheduling next timeout value right away */
	hrtimer_forward_now(timer, g_ktfivems);

	if (g_btimerstarted)
		if (VibeSemIsLocked(&g_mutex))
			up(&g_mutex);

	return HRTIMER_RESTART;
}
static void VibeOSKernelLinuxStartTimer(void)
{
    /* Reset watchdog counter */
    g_nWatchdogCounter = 0;

    if (!g_bTimerStarted)
    {
        /* (Re-)Initialize the semaphore used with the timer */
        sema_init(&g_hSemaphore, NUM_EXTRA_BUFFERS);

        g_bTimerStarted = true;

        /* Start the timer */
        g_ktTimerPeriod = ktime_set(0, g_nTimerPeriodMs * 1000000);
        hrtimer_start(&g_tspTimer, g_ktTimerPeriod, HRTIMER_MODE_REL);
    }
    else
    {
        int res;
        /*
        ** Use interruptible version of down to be safe
        ** (try to not being stuck here if the semaphore is not freed for any reason)
        */
        res = down_interruptible(&g_hSemaphore);  /* wait for the semaphore to be freed by the timer */
        if (res != 0)
        {
            DbgOut((DBL_INFO, "VibeOSKernelLinuxStartTimer: down_interruptible interrupted by a signal.\n"));
        }
    }
    VibeOSKernelProcessData(NULL);
    /*
    ** Because of possible NACK handling, the  VibeOSKernelProcessData() call above could take more than
    ** 5 ms on some piezo devices that are buffering output samples; when this happens, the timer
    ** interrupt will release the g_hSemaphore while VibeOSKernelProcessData is executing and the player
    ** will immediately send the new packet to the SPI layer when VibeOSKernelProcessData exits, which
    ** could cause another NACK right away. To avoid that, we'll create a small delay if the semaphore
    ** was released when VibeOSKernelProcessData exits, by acquiring the mutex again and waiting for
    ** the timer to release it.
    */
#if defined(NUM_EXTRA_BUFFERS) && (NUM_EXTRA_BUFFERS)
    if (g_bTimerStarted && !VibeSemIsLocked(&g_hSemaphore))
    {
        int res;

        res = down_interruptible(&g_hSemaphore);

        if (res != 0)
        {
            DbgOut((DBL_INFO, "VibeOSKernelLinuxStartTimer: down_interruptible interrupted by a signal.\n"));
        }
    }
#endif
}
Example #9
0
static void VibeOSKernelLinuxStartTimer(void)
{
	int i;
	int res;

	/* Reset watchdog counter */
	g_nwatchdog_counter = 0;

	if (!g_btimerstarted) {
		if (!VibeSemIsLocked(&g_mutex))
			res = down_interruptible(&g_mutex); /* start locked */

		g_btimerstarted = true;

		/* Start the timer */
		hrtimer_start(&g_tsptimer, g_ktfivems, HRTIMER_MODE_REL);

		/* Don't block the write() function after the first sample
		to allow the host sending the next samples with no delay */
		for (i = 0; i < NUM_ACTUATORS; i++) {
			if ((g_samples_buffer[i]
				.actuator_samples[0].nbuffer_size) ||
				(g_samples_buffer[i]
				.actuator_samples[1].nbuffer_size)) {
				g_samples_buffer[i].nindex_output_value = 0;
				return;
			}
		}
	}

	if (0 != VibeOSKernelProcessData(NULL))
		return;

	/*
	** Use interruptible version of down to be safe
	** (try to not being stuck here if the mutex is
	** not freed for any reason)
	*/
	/* wait for the mutex to be freed by the timer */
	res = down_interruptible(&g_mutex);
	if (res != 0)
		DbgOut((KERN_INFO
		 "tspdrv: down_interruptible interrupted by a signal.\n"));
}
Example #10
0
static void VibeOSKernelTimerProc(unsigned long param)
{
    /* Return right away if timer is not supposed to run */
    if (!g_bTimerStarted) return;

    /* Scheduling next timeout value right away */
    if (++g_nWatchdogCounter < WATCHDOG_TIMEOUT)
        mod_timer(&g_timerList, jiffies + g_nTimerPeriodMs);

    if (VibeSemIsLocked(&g_hSemaphore))
    {
        up(&g_hSemaphore);
    }

    if (g_nWatchdogCounter > WATCHDOG_TIMEOUT)
    {
        /* Do not call SPI functions in this function as their implementation coud use interrupt */
        VibeOSKernelLinuxStopTimer();
    }
}
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))
            {
                VibeInt8 cZero[1] = {0};

                /* Nothing to play for all actuators, turn off the timer when we reach the watchdog tick count limit */
                ImmVibeSPI_ForceOut_SetSamples(i, 8, 1, cZero);
                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 */
                mod_timer(&g_timerList, jiffies + TIMER_INCR);
            }

            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;
}
static void VibeOSKernelLinuxTerminateTimer(void)
{
    VibeOSKernelLinuxStopTimer();
    if (VibeSemIsLocked(&g_hMutex)) up(&g_hMutex);
}
static int VibeOSKernelTimerProc(void* data)
{
	int nActuatorNotPlaying;
	int i;
	int bReachEndBuffer = 0;

	while (!kthread_should_stop()) {
		if (g_bTimerThreadStarted) {
			/* Block until we get woken up by timer tick */
			/* . only do this if we're not exiting entirely */
			wait_for_completion(&g_tspCompletion);

			/* Reinitialized completion so it isn't free by default */
			init_completion(&g_tspCompletion);
		}

		nActuatorNotPlaying = 0;

		/* Return right away if timer is not supposed to run */
		if (g_bTimerStarted) {
			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 */
					ImmVibeSPI_ForceOut_Set(i, pCurrentActuatorSample->actuatorSamples[(int)pCurrentActuatorSample->nIndexPlayingBuffer].dataBuffer[(int)(pCurrentActuatorSample->nIndexOutputValue++)]);

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

						bReachEndBuffer = 1;

						/* Check stop request and empty buffer */
						if ((g_bStopRequested) || (0 == (pCurrentActuatorSample->actuatorSamples[(int)((pCurrentActuatorSample->nIndexPlayingBuffer) ^ 1)].nBufferSize))) {
							pCurrentActuatorSample->nIndexPlayingBuffer = -1;

							if (g_bStopRequested) {
								/* g_bStopReqested is set, so turn off all actuators */
								ImmVibeSPI_ForceOut_Set(i, 0);
								ImmVibeSPI_ForceOut_AmpDisable(i);

								/* If it's the last actuator, stop the timer */
								if (i == (NUM_ACTUATORS-1)) {
									VibeOSKernelLinuxStopTimer();

									/* Reset watchdog counter */
									g_nWatchdogCounter = 0;
								}
							}
						} else { /* The other buffer has data in it */
							/* Switch buffer */
							(pCurrentActuatorSample->nIndexPlayingBuffer) ^= 1;
							pCurrentActuatorSample->nIndexOutputValue = 0;
						}
					}
				}
			}
			/* Release the mutex if locked */
			if (bReachEndBuffer && VibeSemIsLocked(&g_hMutex)) {
				up(&g_hMutex);
			}
		}
	}
	return 0;
}
Example #14
0
static int VibeOSKernelProcessData(void *data)
{
	int i;
	int nactuator_not_playing = 0;

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

		if (-1 == pcurrent_actuator_sample->nindex_playing_buffer) {
			nactuator_not_playing++;
			if ((NUM_ACTUATORS == nactuator_not_playing) &&
				((++g_nwatchdog_counter) > WATCHDOG_TIMEOUT)) {
				int8_t czero[1] = {0};

				/*
				** Nothing to play for all actuators,
				** turn off the timer
				** when we reach the watchdog tick count limit
				*/
				ImmVibeSPI_ForceOut_SetSamples(i, 8, 1, czero);
				printk(KERN_INFO ": %s : 1.calls ImmVibeSPI_ForceOut_AmpDisable(i=%d)\n", __func__,i);

				ImmVibeSPI_ForceOut_AmpDisable(i);
				VibeOSKernelLinuxStopTimer();

				/* Reset watchdog counter */
				g_nwatchdog_counter = 0;
			}
		} else {
			/* Play the current buffer */
			if (VIBE_E_FAIL == ImmVibeSPI_ForceOut_SetSamples(
			 pcurrent_actuator_sample->actuator_samples
			  [(int)pcurrent_actuator_sample->nindex_playing_buffer]
			  .nactuator_index,
			 pcurrent_actuator_sample->actuator_samples
			  [(int)pcurrent_actuator_sample->nindex_playing_buffer]
			  .nbit_depth,
			 pcurrent_actuator_sample->actuator_samples
			  [(int)pcurrent_actuator_sample->nindex_playing_buffer]
			  .nbuffer_size,
			 pcurrent_actuator_sample->actuator_samples
			  [(int)pcurrent_actuator_sample->nindex_playing_buffer]
			  .data_buffer)) {
				/* VIBE_E_FAIL means NAK has been handled.
				Schedule timer to restart 5 ms from now */
				hrtimer_forward_now(&g_tsptimer, g_ktfivems);
			}

			pcurrent_actuator_sample->nindex_output_value +=
			 pcurrent_actuator_sample->actuator_samples
			 [(int)pcurrent_actuator_sample->nindex_playing_buffer]
			 .nbuffer_size;

			if (pcurrent_actuator_sample->nindex_output_value >=
			    pcurrent_actuator_sample->actuator_samples
			    [(int)pcurrent_actuator_sample
			    ->nindex_playing_buffer]
			    .nbuffer_size) {
				/* Reach the end of the current buffer */
			    pcurrent_actuator_sample->actuator_samples
			    [(int)pcurrent_actuator_sample
				->nindex_playing_buffer]
			    .nbuffer_size = 0;

				/* Switch buffer */
				(pcurrent_actuator_sample
					->nindex_playing_buffer) ^= 1;
				pcurrent_actuator_sample
					->nindex_output_value = 0;

				/* Finished playing,
				   disable amp for actuator (i) */
				if (g_bstoprequested) {
					pcurrent_actuator_sample
						->nindex_playing_buffer = -1;
					printk(KERN_INFO ": %s : 2.calls ImmVibeSPI_ForceOut_AmpDisable(i=%d)\n", __func__,i);

					ImmVibeSPI_ForceOut_AmpDisable(i);
				}
			}
		}
	}

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

		/* Reset watchdog counter */
		g_nwatchdog_counter = 0;

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

	return 0;
}