static void VibeOSKernelLinuxStartTimer(void) { /* Reset watchdog counter */ g_nWatchdogCounter = 0; wake_lock_timeout(&g_tspWakelock, 1*HZ); 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 ret = 0; /* ** Use interruptible version of down to be safe ** (try to not being stuck here if the semaphore is not freed for any reason) */ ret = down_interruptible(&g_hSemaphore); /* wait for the semaphore to be freed by the timer */ if (ret != 0) { printk(KERN_ERR "VibeOSKernelLinuxStartTimer: down_interruptible interrupted by a signal.\n"); } } VibeOSKernelProcessData(NULL); }
static int ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) #endif { #ifdef QA_TEST int i; #endif switch (cmd) { case TSPDRV_STOP_KERNEL_TIMER: /* ** As we send one sample ahead of time, we need to finish playing the last sample ** before stopping the timer. So we just set a flag here. */ if (true == g_bIsPlaying) g_bStopRequested = true; #ifdef VIBEOSKERNELPROCESSDATA /* Last data processing to disable amp and stop timer */ VibeOSKernelProcessData(NULL); #endif #ifdef QA_TEST if (g_nForceLogIndex) { for (i=0; i<g_nForceLogIndex; i++) { printk("<6>%d\t%d\n", g_nTime, g_nForceLog[i]); g_nTime += TIME_INCREMENT; } } g_nTime = 0; g_nForceLogIndex = 0; #endif break; case TSPDRV_MAGIC_NUMBER: file->private_data = (void*)TSPDRV_MAGIC_NUMBER; break; case TSPDRV_ENABLE_AMP: ImmVibeSPI_ForceOut_AmpEnable(arg); DbgRecorderReset((arg)); DbgRecord((arg,";------- TSPDRV_ENABLE_AMP ---------\n")); break; case TSPDRV_DISABLE_AMP: /* Small fix for now to handle proper combination of TSPDRV_STOP_KERNEL_TIMER and TSPDRV_DISABLE_AMP together */ /* If a stop was requested, ignore the request as the amp will be disabled by the timer proc when it's ready */ if(!g_bStopRequested) { ImmVibeSPI_ForceOut_AmpDisable(arg); } break; case TSPDRV_GET_NUM_ACTUATORS: return NUM_ACTUATORS; } return 0; }
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_timerList.expires = jiffies + g_nTimerPeriodMs; add_timer(&g_timerList); } 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((KERN_INFO "VibeOSKernelLinuxStartTimer: down_interruptible interrupted by a signal.\n")); } } VibeOSKernelProcessData(NULL); }
static int ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { #ifdef QA_TEST int i; #endif DbgOut((KERN_INFO "tspdrv: ioctl cmd[0x%x].\n", cmd)); switch (cmd) { case TSPDRV_STOP_KERNEL_TIMER: /* ** As we send one sample ahead of time, we need to finish playing the last sample ** before stopping the timer. So we just set a flag here. */ if (true == g_bIsPlaying) g_bStopRequested = true; #ifdef VIBEOSKERNELPROCESSDATA /* Last data processing to disable amp and stop timer */ VibeOSKernelProcessData(NULL); #endif #ifdef QA_TEST if (g_nForceLogIndex) { for (i = 0; i < g_nForceLogIndex; i++) { printk(KERN_DEBUG "<6>%d\t%d\n", g_nTime, g_nForceLog[i]); g_nTime += TIME_INCREMENT; } } g_nTime = 0; g_nForceLogIndex = 0; #endif break; case TSPDRV_MAGIC_NUMBER: file->private_data = (void *)TSPDRV_MAGIC_NUMBER; break; case TSPDRV_ENABLE_AMP: wake_lock(&vib_wake_lock); ImmVibeSPI_ForceOut_AmpEnable(arg); DbgRecorderReset((arg)); DbgRecord((arg, ";------- TSPDRV_ENABLE_AMP ---------\n")); break; case TSPDRV_DISABLE_AMP: if (!g_bStopRequested) ImmVibeSPI_ForceOut_AmpDisable(arg); wake_unlock(&vib_wake_lock); break; case TSPDRV_GET_NUM_ACTUATORS: return NUM_ACTUATORS; } return 0; }
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 }
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")); }
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 */ g_timerList.expires = jiffies + TIMER_INCR; add_timer(&g_timerList); /* 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; } } } 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) */ 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 long ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { #ifdef QA_TEST int i; #endif /* DbgOut(KERN_INFO "tspdrv: ioctl cmd[0x%x].\n", cmd); */ switch (cmd) { case TSPDRV_STOP_KERNEL_TIMER: /* ** As we send one sample ahead of time, we need to finish ** playing the last sample before stopping the timer. ** So we just set a flag here. */ if (true == g_bisplaying) g_bstoprequested = true; #ifdef VIBEOSKERNELPROCESSDATA /* Last data processing to disable amp and stop timer */ VibeOSKernelProcessData(NULL); #endif #ifdef QA_TEST if (g_nforcelog_index) { for (i = 0; i < g_nforcelog_index; i++) { printk(KERN_INFO "%d\t%d\n" , g_ntime, g_nforcelog[i]); g_ntime += TIME_INCREMENT; } } g_ntime = 0; g_nforcelog_index = 0; #endif break; case TSPDRV_MAGIC_NUMBER: filp->private_data = (void *)TSPDRV_MAGIC_NUMBER; break; case TSPDRV_ENABLE_AMP: wake_lock(&vib_wake_lock); ImmVibeSPI_ForceOut_AmpEnable(arg); DbgRecorderReset((arg)); DbgRecord((arg, ";------- TSPDRV_ENABLE_AMP ---------\n")); break; case TSPDRV_DISABLE_AMP: /* ** Small fix for now to handle proper combination of ** TSPDRV_STOP_KERNEL_TIMER and TSPDRV_DISABLE_AMP together ** If a stop was requested, ignore the request as the amp ** will be disabled by the timer proc when it's ready */ if (!g_bstoprequested) ImmVibeSPI_ForceOut_AmpDisable(arg); wake_unlock(&vib_wake_lock); break; case TSPDRV_GET_NUM_ACTUATORS: return NUM_ACTUATORS; } return 0; }
static ssize_t write(struct file *file, const char *buf, size_t count, loff_t *ppos) { int i = 0; *ppos = 0; /* file position not used, always set to 0 */ /* DbgOut((KERN_ERR "tspdrv: write....\n")); */ /* ** Prevent unauthorized caller to write data. ** TouchSense service is the only valid caller. */ if (file->private_data != (void *)TSPDRV_MAGIC_NUMBER) { DbgOut((KERN_ERR "tspdrv: unauthorized write.\n")); return 0; } #ifdef CONFIG_TACTILE_ASSIST /* Check buffer size */ if ((count < SPI_HEADER_SIZE) || (count > SPI_BUFFER_SIZE)) { DbgOut((KERN_ERR "tspdrv: invalid write buffer size.\n")); return 0; } if (count == SPI_HEADER_SIZE) g_bOutputDataBufferEmpty = 1; else g_bOutputDataBufferEmpty = 0; #else if ((count <= SPI_HEADER_SIZE) || (count > SPI_BUFFER_SIZE)) { DbgOut((KERN_ERR "tspdrv: invalid write buffer size.\n")); return 0; } #endif /* Copy immediately the input buffer */ if (0 != copy_from_user(g_cwrite_buffer, buf, count)) { /* Failed to copy all the data, exit */ DbgOut((KERN_ERR "tspdrv: copy_from_user failed.\n")); return 0; } while (i < count) { int nindex_free_buffer; /* initialized below */ samples_buffer *pinput_buffer = (samples_buffer *)(&g_cwrite_buffer[i]); #ifdef CONFIG_TACTILE_ASSIST if ((i + SPI_HEADER_SIZE) > count) { #else if ((i + SPI_HEADER_SIZE) >= count) { #endif /* ** Index is about to go beyond the buffer size. ** (Should never happen). */ DbgOut((KERN_EMERG "tspdrv: invalid buffer index.\n")); return 0; } /* Check bit depth */ if (8 != pinput_buffer->nbit_depth) DbgOut((KERN_WARNING "tspdrv: invalid bit depth.Use default value(8).\n")); /* The above code not valid if SPI header size is not 3 */ #if (SPI_HEADER_SIZE != 3) #error "SPI_HEADER_SIZE expected to be 3" #endif /* Check buffer size */ if ((i + SPI_HEADER_SIZE + pinput_buffer->nbuffer_size) > count) { /* ** Index is about to go beyond the buffer size. ** (Should never happen). */ DbgOut((KERN_EMERG "tspdrv: invalid data size.\n")); return 0; } /* Check actuator index */ if (NUM_ACTUATORS <= pinput_buffer->nactuator_index) { DbgOut((KERN_ERR "tspdrv: invalid actuator index.\n")); i += (SPI_HEADER_SIZE + pinput_buffer->nbuffer_size); continue; } if (0 == g_samples_buffer[pinput_buffer->nactuator_index] .actuator_samples[0].nbuffer_size) { nindex_free_buffer = 0; } else if (0 == g_samples_buffer[pinput_buffer->nactuator_index] .actuator_samples[1].nbuffer_size) { nindex_free_buffer = 1; } else { /* No room to store new samples */ DbgOut((KERN_ERR "tspdrv: no room to store new samples.\n")); return 0; } /* Store the data in the free buffer of the given actuator */ memcpy( &(g_samples_buffer[pinput_buffer->nactuator_index] .actuator_samples[nindex_free_buffer]), &g_cwrite_buffer[i], (SPI_HEADER_SIZE + pinput_buffer->nbuffer_size)); /* If the no buffer is playing, prepare to play ** g_samples_buffer[pinput_buffer->nactuator_index]. ** actuator_samples[nindex_free_buffer] */ if (-1 == g_samples_buffer[pinput_buffer->nactuator_index] .nindex_playing_buffer) { g_samples_buffer[pinput_buffer->nactuator_index] .nindex_playing_buffer = nindex_free_buffer; g_samples_buffer[pinput_buffer->nactuator_index] .nindex_output_value = 0; } /* Increment buffer index */ i += (SPI_HEADER_SIZE + pinput_buffer->nbuffer_size); } #ifdef QA_TEST g_nforcelog[g_nforcelog_index++] = g_cSPIBuffer[0]; if (g_nforcelog_index >= FORCE_LOG_BUFFER_SIZE) { for (i = 0; i < FORCE_LOG_BUFFER_SIZE; i++) { printk(KERN_INFO "%d\t%d\n", g_ntime, g_nforcelog[i]); g_ntime += TIME_INCREMENT; } g_nforcelog_index = 0; } #endif /* Start the timer after receiving new output force */ g_bisplaying = true; VibeOSKernelLinuxStartTimer(); return count; } static long ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { #ifdef QA_TEST int i; #endif printk(KERN_DEBUG "tspdrv: %s %d\n", __func__, cmd); /* DbgOut(KERN_INFO "tspdrv: ioctl cmd[0x%x].\n", cmd); */ switch (cmd) { case TSPDRV_STOP_KERNEL_TIMER: /* ** As we send one sample ahead of time, we need to finish ** playing the last sample before stopping the timer. ** So we just set a flag here. */ if (true == g_bisplaying) g_bstoprequested = true; #ifdef VIBEOSKERNELPROCESSDATA /* Last data processing to disable amp and stop timer */ VibeOSKernelProcessData(NULL); #endif #ifdef QA_TEST if (g_nforcelog_index) { for (i = 0; i < g_nforcelog_index; i++) { printk(KERN_INFO "%d\t%d\n" , g_ntime, g_nforcelog[i]); g_ntime += TIME_INCREMENT; } } g_ntime = 0; g_nforcelog_index = 0; #endif break; case TSPDRV_MAGIC_NUMBER: #ifdef CONFIG_TACTILE_ASSIST case TSPDRV_SET_MAGIC_NUMBER: #endif filp->private_data = (void *)TSPDRV_MAGIC_NUMBER; break; case TSPDRV_ENABLE_AMP: wake_lock(&vib_wake_lock); vibe_set_pwm_freq(0); vibe_pwm_onoff(1); ImmVibeSPI_ForceOut_AmpEnable(arg); DbgRecorderReset((arg)); DbgRecord((arg, ";------- TSPDRV_ENABLE_AMP ---------\n")); break; case TSPDRV_DISABLE_AMP: /* ** Small fix for now to handle proper combination of ** TSPDRV_STOP_KERNEL_TIMER and TSPDRV_DISABLE_AMP together ** If a stop was requested, ignore the request as the amp ** will be disabled by the timer proc when it's ready */ #ifdef CONFIG_TACTILE_ASSIST g_bstoprequested = true; /* Last data processing to disable amp and stop timer */ VibeOSKernelProcessData(NULL); g_bisplaying = false; #else if (!g_bstoprequested) ImmVibeSPI_ForceOut_AmpDisable(arg); #endif wake_unlock(&vib_wake_lock); break; case TSPDRV_GET_NUM_ACTUATORS: return NUM_ACTUATORS; } return 0; }
static long unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { #ifdef QA_TEST int i; #endif DbgOut((KERN_INFO "tspdrv: ioctl cmd[0x%x].\n", cmd)); switch (cmd) { case TSPDRV_STOP_KERNEL_TIMER: /* * As we send one sample ahead of time, * we need to finish playing the last sample * before stopping the timer. So we just set a flag here. */ if (true == g_bIsPlaying) g_bStopRequested = true; #ifdef VIBEOSKERNELPROCESSDATA /* Last data processing to disable amp and stop timer */ VibeOSKernelProcessData(NULL); #endif #ifdef QA_TEST if (g_nForceLogIndex) { for (i = 0; i < g_nForceLogIndex; i++) { printk(KERN_DEBUG "<6>%d\t%d\n", g_nTime, g_nForceLog[i]); g_nTime += TIME_INCREMENT; } } g_nTime = 0; g_nForceLogIndex = 0; #endif break; case TSPDRV_MAGIC_NUMBER: case TSPDRV_SET_MAGIC_NUMBER: file->private_data = (void *)TSPDRV_MAGIC_NUMBER; break; case TSPDRV_ENABLE_AMP: wake_lock(&vib_wake_lock); ImmVibeSPI_ForceOut_AmpEnable(arg); DbgRecorderReset((arg)); DbgRecord((arg, ";------- TSPDRV_ENABLE_AMP ---------\n")); break; case TSPDRV_DISABLE_AMP: /* Small fix for now to handle proper combination of * TSPDRV_STOP_KERNEL_TIMER and TSPDRV_DISABLE_AMP together * If a stop was requested, ignore the request as the amp * will be disabled by the timer proc when it's ready */ #if 0 if (!g_bStopRequested) { ImmVibeSPI_ForceOut_AmpDisable(arg); #endif g_bStopRequested = true; /* Last data processing to disable amp and stop timer */ VibeOSKernelProcessData(NULL); g_bIsPlaying = false; wake_unlock(&vib_wake_lock); break; case TSPDRV_GET_NUM_ACTUATORS: return NUM_ACTUATORS; } return 0; } static int suspend(struct platform_device *pdev, pm_message_t state) { int ret; if (g_bIsPlaying) { ret = -EBUSY; } else { ret = 0; } DbgOut((KERN_DEBUG "tspdrv: %s (%d).\n", __func__, ret)); return ret; }
//static int ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static long unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { #ifdef QA_TEST int i; #endif DbgOut((KERN_INFO "tspdrv: ioctl cmd[0x%x].\n", cmd)); switch (cmd) { #if 0 // We don't used linear motor. #ifdef VIBE_TUNING #if 1 //def CONFIG_KTTECH_MODEL_O6 case TSPDRV_TUNING_ARG1: //M // 0x52b9 printk("[tspdrv] TSPDRV_TUNING_ARG1 arg : %lu\n", arg); g_nLRA_PWM_M = arg; break; case TSPDRV_TUNING_ARG2: //N & D // ox52ba printk("[tspdrv] TSPDRV_TUNING_ARG2 arg : %lu\n", arg); g_nLRA_PWM_N = arg; g_nLRA_PWM_D= arg >> 1; break; case TSPDRV_TUNING_ARG3: //Multiplier // 0x52bb printk("[tspdrv] TSPDRV_TUNING_ARG2 arg : %lu\n", arg); g_nLRA_PWM_Multiplier = arg; break; #endif #ifdef CONFIG_KTTECH_MODEL_O3 case TSPDRV_TUNING_ARG1: g_nLRA_PWM_M = arg; /* set value of g_PWM_duty_max in ImmVibeSPI */ DbgOut((KERN_INFO "tspdrv: ioctl cmd[185].\n")); break; case TSPDRV_TUNING_ARG2: g_nLRA_PWM_N = arg; /* set value of g_PWM_ctrl in ImmVibeSPI */ g_nLRA_PWM_D = g_nLRA_PWM_N>>1; //D = N/2 DbgOut((KERN_INFO "tspdrv: ioctl cmd[186].\n")); break; case TSPDRV_TUNING_ARG3: g_nLRA_PWM_Multiplier = arg; /* set value of g_PWM_multiplier in ImmVibeSPI */ DbgOut((KERN_INFO "tspdrv: ioctl cmd[187].\n")); break; #endif #endif /* VIBE_TUNING */ #endif case TSPDRV_STOP_KERNEL_TIMER: // 0x5201 /* ** As we send one sample ahead of time, we need to finish playing the last sample ** before stopping the timer. So we just set a flag here. */ if (true == g_bIsPlaying) g_bStopRequested = true; #ifdef VIBEOSKERNELPROCESSDATA /* Last data processing to disable amp and stop timer */ VibeOSKernelProcessData(NULL); #endif #ifdef QA_TEST if (g_nForceLogIndex) { for (i=0; i<g_nForceLogIndex; i++) { printk("<6>%d\t%d\n", g_nTime, g_nForceLog[i]); g_nTime += TIME_INCREMENT; } } g_nTime = 0; g_nForceLogIndex = 0; #endif break; case TSPDRV_MAGIC_NUMBER: file->private_data = (void*)TSPDRV_MAGIC_NUMBER; break; case TSPDRV_ENABLE_AMP: // 0x5203 #ifdef CONFIG_SPIDER_SADR sadr_device_set_data(vib_dev_id,0xFFFFFFFF); #else ImmVibeSPI_ForceOut_AmpEnable(arg); #endif DbgRecorderReset((arg)); DbgRecord((arg,";------- TSPDRV_ENABLE_AMP ---------\n")); break; case TSPDRV_DISABLE_AMP: // 0x5204 /* Small fix for now to handle proper combination of TSPDRV_STOP_KERNEL_TIMER and TSPDRV_DISABLE_AMP together */ /* If a stop was requested, ignore the request as the amp will be disabled by the timer proc when it's ready */ if(!g_bStopRequested) { #ifdef CONFIG_SPIDER_SADR sadr_device_set_data(vib_dev_id,0); #else ImmVibeSPI_ForceOut_AmpDisable(arg); #endif } break; case TSPDRV_GET_NUM_ACTUATORS: // 0x5205 return NUM_ACTUATORS; } return 0; }