示例#1
0
static ssize_t
immersion_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	if (sscanf(buf, "%d", &val) != 1)
		return -EINVAL;

	if(val == 1) {
		printk("immersion_enable_store() : vibrator enable\n");
		vibrator_power_set(1);
		vibratror_pwm_gpio_OnOFF(1);
		vibrator_pwm_set(1, 80, GP_CLK_N_DEFAULT);
		vibrator_ic_enable_set(1);

		DbgRecorderReset((val));
		DbgRecord((val,";------- TSPDRV_ENABLE_AMP ---------\n"));
	}
	else if (val == 0) {
		printk("immersion_enable_store() : vibrator disable\n");
		vibrator_ic_enable_set(0);
		vibrator_pwm_set(0, 0, GP_CLK_N_DEFAULT);
        vibratror_pwm_gpio_OnOFF(0);
		vibrator_power_set(0);
	}

	return count;
}
示例#2
0
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;
}
示例#3
0
文件: tspdrv.c 项目: myfluxi/xxKernel
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 ssize_t
immersion_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	if (sscanf(buf, "%d", &val) != 1)
		return -EINVAL;

	if (val == 0) {
		printk("immersion_enable_store() : vibrator disable\n");
		sm100_ic_enable_set(0, &vib);
		sm100_pwm_set(0, 0);
		sm100_power_set(0, &vib);
		clk_disable_unprepare(cam_gp1_clk);
	} else if((val >> 7) <= 0) {
		printk("immersion_enable_store() : vibrator enable\n");
		clk_prepare_enable(cam_gp1_clk);
		sm100_power_set(1, &vib);
		sm100_pwm_set(1, val);
		sm100_ic_enable_set(1, &vib);
		DbgRecorderReset((val));
		DbgRecord((val,";------- TSPDRV_ENABLE_AMP ---------\n"));
	} else  {
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;
}
示例#7
0
static int ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
#endif
{
	switch (cmd)
	{
	case TSPDRV_SET_MAGIC_NUMBER:
		file->private_data = (void*)TSPDRV_MAGIC_NUMBER;
		break;

	case TSPDRV_ENABLE_AMP:
		ImmVibeSPI_ForceOut_AmpEnable(arg);
#ifdef VIBE_RUNTIME_RECORD
		if (atomic_read(&g_bRuntimeRecord)) {
			DbgRecord((arg,";------- TSPDRV_ENABLE_AMP ---------\n"));
		}
#else
		DbgRecorderReset((arg));
		DbgRecord((arg,";------- TSPDRV_ENABLE_AMP ---------\n"));
#endif
		break;

	case TSPDRV_DISABLE_AMP:
		ImmVibeSPI_ForceOut_AmpDisable(arg);
#ifdef VIBE_RUNTIME_RECORD
		if (atomic_read(&g_bRuntimeRecord)) {
			DbgRecord((arg,";------- TSPDRV_DISABLE_AMP ---------\n"));
		}
#endif
		break;

	case TSPDRV_GET_NUM_ACTUATORS:
		return NUM_ACTUATORS;

	case TSPDRV_SET_DBG_LEVEL:
	{
		long nDbgLevel;
		if (0 != copy_from_user((void *)&nDbgLevel, (const void __user *)arg, sizeof(long))) {
			/* Error copying the data */
			DbgOut((DBL_ERROR, "copy_from_user failed to copy debug level data.\n"));
			return -1;
		}

		if (DBL_TEMP <= nDbgLevel &&  nDbgLevel <= DBL_OVERKILL)
			atomic_set(&g_nDebugLevel, nDbgLevel);
		else
			DbgOut((DBL_ERROR, "Invalid debug level requested, ignored."));

		break;
	}

	case TSPDRV_GET_DBG_LEVEL:
		return atomic_read(&g_nDebugLevel);

#ifdef VIBE_RUNTIME_RECORD
	case TSPDRV_SET_RUNTIME_RECORD_FLAG:
	{
		long nRecordFlag;
		if (0 != copy_from_user((void *)&nRecordFlag, (const void __user *)arg, sizeof(long))) {
			/* Error copying the data */
			DbgOut((DBL_ERROR, "copy_from_user failed to copy runtime record flag.\n"));
			return -1;
		}
		atomic_set(&g_bRuntimeRecord, nRecordFlag);
		if (nRecordFlag) {
			int i;
			for (i = 0; i < NUM_ACTUATORS; i++) {
				DbgRecorderReset((i));
			}
		}
		break;
	}
	case TSPDRV_GET_RUNTIME_RECORD_FLAG:
		return atomic_read(&g_bRuntimeRecord);
	case TSPDRV_SET_RUNTIME_RECORD_BUF_SIZE:
	{
		long nRecorderBufSize;
		if (0 != copy_from_user((void *)&nRecorderBufSize, (const void __user *)arg, sizeof(long))) {
			/* Error copying the data */
			DbgOut((DBL_ERROR, "copy_from_user failed to copy recorder buffer size.\n"));
			return -1;
		}
		if (0 == DbgSetRecordBufferSize(nRecorderBufSize)) {
			DbgOut((DBL_ERROR, "DbgSetRecordBufferSize failed.\n"));
			return -1;
		}
		break;
	}
	case TSPDRV_GET_RUNTIME_RECORD_BUF_SIZE:
		return DbgGetRecordBufferSize();
#endif

	case TSPDRV_SET_DEVICE_PARAMETER:
	{
		device_parameter deviceParam;

		if (0 != copy_from_user((void *)&deviceParam, (const void __user *)arg, sizeof(deviceParam))) {
			/* Error copying the data */
			DbgOut((DBL_ERROR, "tspdrv: copy_from_user failed to copy kernel parameter data.\n"));
			return -1;
		}

		switch (deviceParam.nDeviceParamID) {
		case VIBE_KP_CFG_UPDATE_RATE_MS:
			/* Update the timer period */
			g_nTimerPeriodMs = deviceParam.nDeviceParamValue;
#ifdef CONFIG_HIGH_RES_TIMERS
			/* For devices using high resolution timer we need to update the ktime period value */
			g_ktTimerPeriod = ktime_set(0, g_nTimerPeriodMs * 1000000);
#endif
			break;

		case VIBE_KP_CFG_FREQUENCY_PARAM1:
		case VIBE_KP_CFG_FREQUENCY_PARAM2:
		case VIBE_KP_CFG_FREQUENCY_PARAM3:
		case VIBE_KP_CFG_FREQUENCY_PARAM4:
		case VIBE_KP_CFG_FREQUENCY_PARAM5:
		case VIBE_KP_CFG_FREQUENCY_PARAM6:
			if (0 > ImmVibeSPI_ForceOut_SetFrequency(deviceParam.nDeviceIndex,
					deviceParam.nDeviceParamID, deviceParam.nDeviceParamValue)) {
				DbgOut((DBL_ERROR, "tspdrv: cannot set device frequency parameter.\n"));
				return -1;
			}
			break;
		}
	}
	}
	return 0;
}
示例#8
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 long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{

	/* DbgOut(KERN_INFO "tspdrv: ioctl cmd[0x%x].\n", cmd); */
	switch (cmd) {
		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:
			ImmVibeSPI_ForceOut_AmpDisable(arg);
                     wake_unlock(&vib_wake_lock);
			break;

	case TSPDRV_GET_NUM_ACTUATORS:
		return NUM_ACTUATORS;
		case TSPDRV_SET_DBG_LEVEL:
			{
				long nDbgLevel;
				if (0 != copy_from_user((void *)&nDbgLevel, (const void __user *)arg, sizeof(long))) {
					/* Error copying the data */
					DbgOut((KERN_ERR "copy_from_user failed to copy debug level data.\n"));
					return -1;
				}

				if (DBL_TEMP <= nDbgLevel &&  nDbgLevel <= DBL_OVERKILL) {
					atomic_set(&g_nDebugLevel, nDbgLevel);
				} else {
					DbgOut((KERN_DEBUG "Invalid debug level requested, ignored."));
				}

				break;
			}

		case TSPDRV_GET_DBG_LEVEL:
			return atomic_read(&g_nDebugLevel);

		case TSPDRV_SET_DEVICE_PARAMETER:
			{
				device_parameter deviceParam;

				if (0 != copy_from_user((void *)&deviceParam, (const void __user *)arg, sizeof(deviceParam)))
				{
					/* Error copying the data */
					DbgOut((KERN_ERR "tspdrv: copy_from_user failed to copy kernel parameter data.\n"));
					return -1;
				}

				switch (deviceParam.nDeviceParamID)
				{
					case VIBE_KP_CFG_UPDATE_RATE_MS:
						/* Update the timer period */
						g_nTimerPeriodMs = deviceParam.nDeviceParamValue;



#ifdef CONFIG_HIGH_RES_TIMERS
						/* For devices using high resolution timer we need to update the ktime period value */
						g_ktTimerPeriod = ktime_set(0, g_nTimerPeriodMs * 950000/*1000000*/);
#endif
						break;

					case VIBE_KP_CFG_FREQUENCY_PARAM1:
					case VIBE_KP_CFG_FREQUENCY_PARAM2:
					case VIBE_KP_CFG_FREQUENCY_PARAM3:
					case VIBE_KP_CFG_FREQUENCY_PARAM4:
					case VIBE_KP_CFG_FREQUENCY_PARAM5:
					case VIBE_KP_CFG_FREQUENCY_PARAM6:
						if (0 > ImmVibeSPI_ForceOut_SetFrequency(deviceParam.nDeviceIndex, deviceParam.nDeviceParamID, deviceParam.nDeviceParamValue))
						{
							DbgOut((KERN_ERR "tspdrv: cannot set device frequency parameter.\n"));
							return -1;
						}
						break;
				}
			}
		}
	return 0;
}
//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;
}