blob: b897214d9bd4f9ccd77a6c6a44fbe2da5d059827 [file] [log] [blame]
Devin Kimba0e9452012-06-21 14:09:34 -07001/*
Devin Kimc68f4162012-09-18 11:48:20 -07002 * File: tspdrv.c
3 *
4 * Description:
5 * TouchSense Kernel Module main entry-point.
6 *
7 * Portions Copyright (c) 2008-2011 Immersion Corporation. All Rights Reserved.
8 *
9 * This file contains Original Code and/or Modifications of Original Code
10 * as defined in and that are subject to the GNU Public License v2 -
11 * (the 'License'). You may not use this file except in compliance with the
12 * License. You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or contact
15 * TouchSenseSales@immersion.com.
16 *
17 * The Original Code and all software distributed under the License are
18 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19 * EXPRESS OR IMPLIED, AND IMMERSION HEREBY DISCLAIMS ALL SUCH WARRANTIES,
20 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
21 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see
22 * the License for the specific language governing rights and limitations
23 * under the License.
24 */
Devin Kimba0e9452012-06-21 14:09:34 -070025
26#include <linux/module.h>
27#include <linux/kernel.h>
28#include <linux/timer.h>
29#include <linux/fs.h>
30#include <linux/version.h>
31#include <linux/miscdevice.h>
32#include <linux/platform_device.h>
33#include <asm/uaccess.h>
34#include <tspdrv.h>
35#include <ImmVibeSPI.c>
36#if defined(VIBE_DEBUG) && defined(VIBE_RECORD)
37#include <tspdrvRecorder.c>
38#endif
39
40/* Device name and version information */
41#define VERSION_STR " v3.4.55.8\n" /* DO NOT CHANGE - this is auto-generated */
42#define VERSION_STR_LEN 16 /* account extra space for future extra digits in version number */
43static char g_szDeviceName[ (VIBE_MAX_DEVICE_NAME_LENGTH
44 + VERSION_STR_LEN)
45 * NUM_ACTUATORS]; /* initialized in init_module */
46static size_t g_cchDeviceName; /* initialized in init_module */
47
48/* Flag indicating whether the driver is in use */
49static char g_bIsPlaying = false;
50
51/* Buffer to store data sent to SPI */
52#define SPI_BUFFER_SIZE (NUM_ACTUATORS * (VIBE_OUTPUT_SAMPLE_SIZE + SPI_HEADER_SIZE))
53static int g_bStopRequested = false;
54static actuator_samples_buffer g_SamplesBuffer[NUM_ACTUATORS] = {{0}};
55static char g_cWriteBuffer[SPI_BUFFER_SIZE];
56
57/* For QA purposes */
58#ifdef QA_TEST
59#define FORCE_LOG_BUFFER_SIZE 128
60#define TIME_INCREMENT 5
61static int g_nTime = 0;
62static int g_nForceLogIndex = 0;
63static VibeInt8 g_nForceLog[FORCE_LOG_BUFFER_SIZE];
64#endif
65
66#if ((LINUX_VERSION_CODE & 0xFFFF00) < KERNEL_VERSION(2,6,0))
67#error Unsupported Kernel version
68#endif
69
70#ifndef HAVE_UNLOCKED_IOCTL
71#define HAVE_UNLOCKED_IOCTL 0
72#endif
73
74#ifdef IMPLEMENT_AS_CHAR_DRIVER
75static int g_nMajor = 0;
76#endif
77
78/* Needs to be included after the global variables because it uses them */
79#ifdef CONFIG_HIGH_RES_TIMERS
80#include <VibeOSKernelLinuxHRTime.c>
81#else
82#include <VibeOSKernelLinuxTime.c>
83#endif
84
85/* File IO */
86static int open(struct inode *inode, struct file *file);
87static int release(struct inode *inode, struct file *file);
88static ssize_t read(struct file *file, char *buf, size_t count, loff_t *ppos);
89static ssize_t write(struct file *file, const char *buf, size_t count, loff_t *ppos);
90#if HAVE_UNLOCKED_IOCTL
91static long unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
92#else
93static int ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
94#endif
95static struct file_operations fops =
96{
97 .owner = THIS_MODULE,
98 .read = read,
99 .write = write,
100#if HAVE_UNLOCKED_IOCTL
101 .unlocked_ioctl = unlocked_ioctl,
102#else
103 .ioctl = ioctl,
104#endif
105 .open = open,
106 .release = release,
107 .llseek = default_llseek /* using default implementation as declared in linux/fs.h */
108};
109
110#ifndef IMPLEMENT_AS_CHAR_DRIVER
111static struct miscdevice miscdev =
112{
113 .minor = MISC_DYNAMIC_MINOR,
114 .name = MODULE_NAME,
115 .fops = &fops
116};
117#endif
118
119static int suspend(struct platform_device *pdev, pm_message_t state);
120static int resume(struct platform_device *pdev);
121static struct platform_driver platdrv =
122{
123 .suspend = suspend,
124 .resume = resume,
125 .driver = {
126 .name = MODULE_NAME,
127 },
128};
129
130static void platform_release(struct device *dev);
131static struct platform_device platdev =
132{
133 .name = MODULE_NAME,
134 .id = -1,
135 .dev = {
136 .platform_data = NULL,
137 .release = platform_release,
138 },
139};
140
141
142int __init tspdrv_init(void)
143{
144 int nRet, i; /* initialized below */
145
146 DbgOut((KERN_INFO "tspdrv: init_module.\n"));
147
148#ifdef IMPLEMENT_AS_CHAR_DRIVER
149 g_nMajor = register_chrdev(0, MODULE_NAME, &fops);
150 if (g_nMajor < 0) {
151 DbgOut((KERN_ERR "tspdrv: can't get major number.\n"));
152 return g_nMajor;
153 }
154#else
155 nRet = misc_register(&miscdev);
156 if (nRet) {
157 DbgOut((KERN_ERR "tspdrv: misc_register failed.\n"));
158 return nRet;
159 }
160#endif
161
162 nRet = platform_device_register(&platdev);
163 if (nRet) {
164 DbgOut((KERN_ERR "tspdrv: platform_device_register failed.\n"));
165 }
166
167 nRet = platform_driver_register(&platdrv);
168 if (nRet) {
169 DbgOut((KERN_ERR "tspdrv: platform_driver_register failed.\n"));
170 }
171
172 DbgRecorderInit(());
173
174 ImmVibeSPI_ForceOut_Initialize();
175 VibeOSKernelLinuxInitTimer();
176
177 /* Get and concatenate device name and initialize data buffer */
178 g_cchDeviceName = 0;
179 for (i = 0; i < NUM_ACTUATORS; i++) {
180 char *szName = g_szDeviceName + g_cchDeviceName;
181 ImmVibeSPI_Device_GetName(i, szName, VIBE_MAX_DEVICE_NAME_LENGTH);
182
183 /* Append version information and get buffer length */
184 strcat(szName, VERSION_STR);
185 g_cchDeviceName += strlen(szName);
186
187 g_SamplesBuffer[i].nIndexPlayingBuffer = -1; /* Not playing */
188 g_SamplesBuffer[i].actuatorSamples[0].nBufferSize = 0;
189 g_SamplesBuffer[i].actuatorSamples[1].nBufferSize = 0;
190 }
191
192 return 0;
193}
194
195void __exit tspdrv_exit(void)
196{
197 DbgOut((KERN_INFO "tspdrv: cleanup_module.\n"));
198
199 DbgRecorderTerminate(());
200
201 VibeOSKernelLinuxTerminateTimer();
202 ImmVibeSPI_ForceOut_Terminate();
203
204 platform_driver_unregister(&platdrv);
205 platform_device_unregister(&platdev);
206
207#ifdef IMPLEMENT_AS_CHAR_DRIVER
208 unregister_chrdev(g_nMajor, MODULE_NAME);
209#else
210 misc_deregister(&miscdev);
211#endif
212}
213
214static int open(struct inode *inode, struct file *file)
215{
216 DbgOut((KERN_INFO "tspdrv: open.\n"));
217
218 if (!try_module_get(THIS_MODULE)) return -ENODEV;
219
220 return 0;
221}
222
223static int release(struct inode *inode, struct file *file)
224{
225 DbgOut((KERN_INFO "tspdrv: release.\n"));
226
227 /*
Devin Kimc68f4162012-09-18 11:48:20 -0700228 * Reset force and stop timer when the driver is closed, to make sure
229 * no dangling semaphore remains in the system, especially when the
230 * driver is run outside of immvibed for testing purposes.
231 */
Devin Kimba0e9452012-06-21 14:09:34 -0700232 VibeOSKernelLinuxStopTimer();
233
234 /*
Devin Kimc68f4162012-09-18 11:48:20 -0700235 * Clear the variable used to store the magic number to prevent
236 * unauthorized caller to write data. TouchSense service is the only
237 * valid caller.
238 */
Devin Kimba0e9452012-06-21 14:09:34 -0700239 file->private_data = (void*)NULL;
240
241 module_put(THIS_MODULE);
242
243 return 0;
244}
245
246static ssize_t read(struct file *file, char *buf, size_t count, loff_t *ppos)
247{
248 const size_t nBufSize = (g_cchDeviceName > (size_t)(*ppos)) ?
249 min(count, g_cchDeviceName - (size_t)(*ppos)) : 0;
250
251 /* End of buffer, exit */
252 if (0 == nBufSize)
253 return 0;
254
255 if (0 != copy_to_user(buf, g_szDeviceName + (*ppos), nBufSize)) {
256 /* Failed to copy all the data, exit */
257 DbgOut((KERN_ERR "tspdrv: copy_to_user failed.\n"));
258 return 0;
259 }
260
261 /* Update file position and return copied buffer size */
262 *ppos += nBufSize;
263 return nBufSize;
264}
265
266static ssize_t write(struct file *file, const char *buf, size_t count, loff_t *ppos)
267{
268 int i = 0;
269
270 *ppos = 0; /* file position not used, always set to 0 */
271
272 /*
Devin Kimc68f4162012-09-18 11:48:20 -0700273 * Prevent unauthorized caller to write data.
274 * TouchSense service is the only valid caller.
275 */
Devin Kimba0e9452012-06-21 14:09:34 -0700276 if (file->private_data != (void*)TSPDRV_MAGIC_NUMBER) {
277 DbgOut((KERN_ERR "tspdrv: unauthorized write.\n"));
278 return 0;
279 }
280
281 /* Copy immediately the input buffer */
282 if (0 != copy_from_user(g_cWriteBuffer, buf, count)) {
283 /* Failed to copy all the data, exit */
284 DbgOut((KERN_ERR "tspdrv: copy_from_user failed.\n"));
285 return 0;
286 }
287
288 /* Check buffer size */
289 if ((count <= SPI_HEADER_SIZE) || (count > SPI_BUFFER_SIZE)) {
290 DbgOut((KERN_ERR "tspdrv: invalid write buffer size.\n"));
291 return 0;
292 }
293
294 while (i < count) {
295 int nIndexFreeBuffer; /* initialized below */
296
297 samples_buffer* pInputBuffer = (samples_buffer*)(&g_cWriteBuffer[i]);
298
299 if ((i + SPI_HEADER_SIZE) >= count) {
300 /*
Devin Kimc68f4162012-09-18 11:48:20 -0700301 * Index is about to go beyond the buffer size.
302 * (Should never happen).
303 */
Devin Kimba0e9452012-06-21 14:09:34 -0700304 DbgOut((KERN_EMERG "tspdrv: invalid buffer index.\n"));
305 }
306
307 /* Check bit depth */
308 if (8 != pInputBuffer->nBitDepth) {
309 DbgOut((KERN_WARNING "tspdrv: invalid bit depth. Use default value (8).\n"));
310 }
311
312 /* The above code not valid if SPI header size is not 3 */
313#if (SPI_HEADER_SIZE != 3)
314#error "SPI_HEADER_SIZE expected to be 3"
315#endif
316
317 /* Check buffer size */
318 if ((i + SPI_HEADER_SIZE + pInputBuffer->nBufferSize) > count) {
319 /*
320 ** Index is about to go beyond the buffer size.
321 ** (Should never happen).
322 */
323 DbgOut((KERN_EMERG "tspdrv: invalid data size.\n"));
324 }
325
326 /* Check actuator index */
327 if (NUM_ACTUATORS <= pInputBuffer->nActuatorIndex) {
328 DbgOut((KERN_ERR "tspdrv: invalid actuator index.\n"));
329 i += (SPI_HEADER_SIZE + pInputBuffer->nBufferSize);
330 continue;
331 }
332
333 if (0 == g_SamplesBuffer[pInputBuffer->nActuatorIndex].actuatorSamples[0].nBufferSize) {
334 nIndexFreeBuffer = 0;
335 }
336 else if (0 == g_SamplesBuffer[pInputBuffer->nActuatorIndex].actuatorSamples[1].nBufferSize) {
337 nIndexFreeBuffer = 1;
338 }
339 else {
340 /* No room to store new samples */
341 DbgOut((KERN_ERR "tspdrv: no room to store new samples.\n"));
342 return 0;
343 }
344
345 /* Store the data in the free buffer of the given actuator */
346 memcpy(&(g_SamplesBuffer[pInputBuffer->nActuatorIndex].actuatorSamples[nIndexFreeBuffer]), &g_cWriteBuffer[i], (SPI_HEADER_SIZE + pInputBuffer->nBufferSize));
347
Devin Kimc68f4162012-09-18 11:48:20 -0700348 /* If the no buffer is playing,prepare to play
349 * g_SamplesBuffer[pInputBuffer->nActuatorIndex]
350 * .actuatorSamples[nIndexFreeBuffer]
351 */
Devin Kimba0e9452012-06-21 14:09:34 -0700352 if ( -1 == g_SamplesBuffer[pInputBuffer->nActuatorIndex].nIndexPlayingBuffer) {
353 g_SamplesBuffer[pInputBuffer->nActuatorIndex].nIndexPlayingBuffer = nIndexFreeBuffer;
354 g_SamplesBuffer[pInputBuffer->nActuatorIndex].nIndexOutputValue = 0;
355 }
356
357 /* Increment buffer index */
358 i += (SPI_HEADER_SIZE + pInputBuffer->nBufferSize);
359 }
360
361#ifdef QA_TEST
362 g_nForceLog[g_nForceLogIndex++] = g_cSPIBuffer[0];
363 if (g_nForceLogIndex >= FORCE_LOG_BUFFER_SIZE) {
364 for (i = 0; i < FORCE_LOG_BUFFER_SIZE; i++) {
365 printk("<6>%d\t%d\n", g_nTime, g_nForceLog[i]);
366 g_nTime += TIME_INCREMENT;
367 }
368 g_nForceLogIndex = 0;
369 }
370#endif
371
372 /* Start the timer after receiving new output force */
373 g_bIsPlaying = true;
374 VibeOSKernelLinuxStartTimer();
375
376 return count;
377}
378
379#if HAVE_UNLOCKED_IOCTL
380static long unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
381#else
382static int ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
383#endif
384{
385#ifdef QA_TEST
386 int i;
387#endif
388
389 switch (cmd) {
390 case TSPDRV_STOP_KERNEL_TIMER:
Devin Kimc68f4162012-09-18 11:48:20 -0700391 /*
392 * As we send one sample ahead of time, we need to finish
393 * playing the last samplebefore stopping the timer.
394 * So we just set a flag here.
395 */
Devin Kimba0e9452012-06-21 14:09:34 -0700396 if (true == g_bIsPlaying)
397 g_bStopRequested = true;
398
399#ifdef VIBEOSKERNELPROCESSDATA
Devin Kimc68f4162012-09-18 11:48:20 -0700400 /* Last data processing to disable amp and stop timer */
Devin Kimba0e9452012-06-21 14:09:34 -0700401 VibeOSKernelProcessData(NULL);
402#endif
403
404#ifdef QA_TEST
405 if (g_nForceLogIndex) {
Devin Kimc68f4162012-09-18 11:48:20 -0700406 for (i = 0; i < g_nForceLogIndex; i++) {
407 printk(KERN_INFO "%d\t%d\n", g_nTime,
408 g_nForceLog[i]);
Devin Kimba0e9452012-06-21 14:09:34 -0700409 g_nTime += TIME_INCREMENT;
410 }
411 }
412 g_nTime = 0;
413 g_nForceLogIndex = 0;
414#endif
415 break;
416
417 case TSPDRV_MAGIC_NUMBER:
418 file->private_data = (void*)TSPDRV_MAGIC_NUMBER;
419 break;
420
421 case TSPDRV_ENABLE_AMP:
422 ImmVibeSPI_ForceOut_AmpEnable(arg);
423 DbgRecorderReset((arg));
Devin Kimc68f4162012-09-18 11:48:20 -0700424 DbgRecord((arg,";TSPDRV_ENABLE_AMP\n"));
Devin Kimba0e9452012-06-21 14:09:34 -0700425 break;
426
427 case TSPDRV_DISABLE_AMP:
Devin Kimc68f4162012-09-18 11:48:20 -0700428 /* Small fix for now to handle proper combination of
429 * TSPDRV_STOP_KERNEL_TIMER and TSPDRV_DISABLE_AMP together
430 * If a stop was requested, ignore the request
431 * as the amp will be disabled by the timer proc
432 * when it's ready
433 */
Devin Kimba0e9452012-06-21 14:09:34 -0700434 if (!g_bStopRequested) {
435 ImmVibeSPI_ForceOut_AmpDisable(arg);
436 }
437 break;
438
439 case TSPDRV_GET_NUM_ACTUATORS:
440 return NUM_ACTUATORS;
441 }
442
443 return 0;
444}
445
446static int suspend(struct platform_device *pdev, pm_message_t state)
447{
448 if (g_bIsPlaying) {
449 DbgOut((KERN_INFO "tspdrv: can't suspend, still playing effects.\n"));
450 return -EBUSY;
451 }
452 else {
453 DbgOut((KERN_INFO "tspdrv: suspend.\n"));
454 return 0;
455 }
456}
457
458static int resume(struct platform_device *pdev)
459{
460 DbgOut((KERN_INFO "tspdrv: resume.\n"));
461
462 return 0; /* can resume */
463}
464
465static void platform_release(struct device *dev)
466{
467 DbgOut((KERN_INFO "tspdrv: platform_release.\n"));
468}
469
470module_init(tspdrv_init);
471module_exit(tspdrv_exit);
472
473/* Module info */
474MODULE_AUTHOR("Immersion Corporation");
475MODULE_DESCRIPTION("TouchSense Kernel Module");
476MODULE_LICENSE("GPL v2");