blob: ce2b153d001eb6565ba14ba2a96dced3a747180b [file] [log] [blame]
Flemmard0604a8e2013-05-23 16:15:48 -07001/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/stat.h>
25#include <linux/signal.h>
26#include <linux/miscdevice.h>
27#include <linux/i2c.h>
28#include <linux/i2c-dev.h>
29#include <linux/poll.h>
30
31#include <linux/errno.h>
32#include <linux/fs.h>
33#include <linux/mm.h>
34#include <linux/sched.h>
35#include <linux/wait.h>
36#include <linux/uaccess.h>
37#include <linux/io.h>
38#include <linux/timer.h>
39#include <linux/slab.h>
40
41#include "mpu.h"
42#include "mltypes.h"
43#include "timerirq.h"
44
45struct timerirq_data {
46 int pid;
47 int data_ready;
48 int run;
49 int timeout;
50 unsigned long period;
51 struct mpuirq_data data;
52 struct completion timer_done;
53 wait_queue_head_t timerirq_wait;
54 struct timer_list timer;
55 struct miscdevice *dev;
56};
57
58static struct miscdevice *timerirq_dev_data;
59
60static void timerirq_handler(unsigned long arg)
61{
62 struct timerirq_data *data = (struct timerirq_data *)arg;
63 struct timeval irqtime;
64
65
66 data->data.interruptcount++;
67
68 data->data_ready = 1;
69
70 do_gettimeofday(&irqtime);
71 data->data.irqtime = (((long long) irqtime.tv_sec) << 32);
72 data->data.irqtime += irqtime.tv_usec;
73 data->data.data_type |= 1;
74
75 wake_up_interruptible(&data->timerirq_wait);
76
77 if (data->run)
78 mod_timer(&data->timer,
79 jiffies + msecs_to_jiffies(data->period));
80 else
81 complete(&data->timer_done);
82}
83
84static int start_timerirq(struct timerirq_data *data)
85{
86 dev_dbg(data->dev->this_device,
87 "%s current->pid %d\n", __func__, current->pid);
88
89
90 if (data->run)
91 return 0;
92
93
94 if (!data->period)
95 return -EINVAL;
96
97 if (data->period > 200)
98 data->period = 200;
99
100 printk(KERN_DEBUG "[GSNR][MPU3050][TIMERIRQ]%s: data->period = %lu\n",
101 __func__, data->period);
102
103 data->run = TRUE;
104 data->data_ready = FALSE;
105
106 return mod_timer(&data->timer,
107 jiffies + msecs_to_jiffies(data->period));
108}
109
110static int stop_timerirq(struct timerirq_data *data)
111{
112 int rc = -1;
113
114 dev_dbg(data->dev->this_device,
115 "%s current->pid %lx\n", __func__, (unsigned long)data);
116
117 printk(KERN_DEBUG "[GSNR][MPU3050][TIMERIRQ]%s: data->period = %lu, "
118 "data->run = %d\n",
119 __func__, data->period, data->run);
120
121 if (data->run) {
122 data->run = FALSE;
123 mod_timer(&data->timer, jiffies + 1);
124 wait_for_completion(&data->timer_done);
125
126 rc = del_timer_sync(&(data->timer));
127 }
128 return 0;
129}
130
131static int timerirq_open(struct inode *inode, struct file *file)
132{
133 struct miscdevice *dev_data = file->private_data;
134 struct timerirq_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
135 if (!data)
136 return -ENOMEM;
137
138 data->dev = dev_data;
139 file->private_data = data;
140 data->pid = current->pid;
141 init_waitqueue_head(&data->timerirq_wait);
142
143 dev_dbg(data->dev->this_device,
144 "%s current->pid %d\n", __func__, current->pid);
145
146 init_completion(&data->timer_done);
147 setup_timer(&data->timer, timerirq_handler, (unsigned long)data);
148
149 printk(KERN_DEBUG "[TIMERIRQ]%s: current->pid %d\n",
150 __func__, current->pid);
151
152 return 0;
153}
154
155static int timerirq_release(struct inode *inode, struct file *file)
156{
157 struct timerirq_data *data = file->private_data;
158 int rc = -1;
159
160 printk(KERN_DEBUG "[TIMERIRQ] %s: data->run = %d\n",
161 __func__, data->run);
162
163
164
165 if (data->run)
166 stop_timerirq(data);
167
168 rc = del_timer_sync(&(data->timer));
169 printk(KERN_DEBUG "[TIMERIRQ]%s: del_timer_sync"
170 "() return = %d\n", __func__, rc);
171
172 kfree(data);
173 return 0;
174}
175
176static ssize_t timerirq_read(struct file *file,
177 char *buf, size_t count, loff_t *ppos)
178{
179 int len, err;
180 struct timerirq_data *data = file->private_data;
181
182 if (!data->data_ready) {
183 wait_event_interruptible_timeout(data->timerirq_wait,
184 data->data_ready,
185 data->timeout);
186 }
187
188 if (data->data_ready && NULL != buf
189 && count >= sizeof(data->data)) {
190 err = copy_to_user(buf, &data->data, sizeof(data->data));
191 data->data.data_type = 0;
192 } else {
193 return 0;
194 }
195 if (err != 0) {
196 dev_err(data->dev->this_device,
197 "Copy to user returned %d\n", err);
198 return -EFAULT;
199 }
200 data->data_ready = 0;
201 len = sizeof(data->data);
202 return len;
203}
204
205unsigned int timerirq_poll(struct file *file, struct poll_table_struct *poll)
206{
207 int mask = 0;
208 struct timerirq_data *data = file->private_data;
209
210 poll_wait(file, &data->timerirq_wait, poll);
211 if (data->data_ready)
212 mask |= POLLIN | POLLRDNORM;
213 return mask;
214}
215
216static long timerirq_ioctl(struct file *file,
217 unsigned int cmd, unsigned long arg)
218{
219 int retval = 0;
220 int tmp;
221 struct timerirq_data *data = file->private_data;
222
223 dev_dbg(data->dev->this_device,
224 "%s current->pid %d, %d, %ld\n",
225 __func__, current->pid, cmd, arg);
226
227 if (!data)
228 return -EFAULT;
229
230 switch (cmd) {
231 case TIMERIRQ_SET_TIMEOUT:
232 data->timeout = arg;
233 break;
234 case TIMERIRQ_GET_INTERRUPT_CNT:
235 tmp = data->data.interruptcount - 1;
236 if (data->data.interruptcount > 1)
237 data->data.interruptcount = 1;
238
239 if (copy_to_user((int *) arg, &tmp, sizeof(int)))
240 return -EFAULT;
241 break;
242 case TIMERIRQ_START:
243 data->period = arg;
244 retval = start_timerirq(data);
245 break;
246 case TIMERIRQ_STOP:
247 retval = stop_timerirq(data);
248 break;
249 default:
250 retval = -EINVAL;
251 }
252 return retval;
253}
254
255static const struct file_operations timerirq_fops = {
256 .owner = THIS_MODULE,
257 .read = timerirq_read,
258 .poll = timerirq_poll,
259
260#if HAVE_COMPAT_IOCTL
261 .compat_ioctl = timerirq_ioctl,
262#endif
263#if HAVE_UNLOCKED_IOCTL
264 .unlocked_ioctl = timerirq_ioctl,
265#endif
266 .open = timerirq_open,
267 .release = timerirq_release,
268};
269
270static int __init timerirq_init(void)
271{
272
273 int res;
274 static struct miscdevice *data;
275
276 data = kzalloc(sizeof(*data), GFP_KERNEL);
277 if (!data)
278 return -ENOMEM;
279 timerirq_dev_data = data;
280 data->minor = MISC_DYNAMIC_MINOR;
281 data->name = "timerirq";
282 data->fops = &timerirq_fops;
283
284 res = misc_register(data);
285 if (res < 0) {
286 dev_err(data->this_device,
287 "misc_register returned %d\n",
288 res);
289 return res;
290 }
291
292 return res;
293}
294module_init(timerirq_init);
295
296static void __exit timerirq_exit(void)
297{
298 struct miscdevice *data = timerirq_dev_data;
299
300 dev_info(data->this_device, "Unregistering %s\n",
301 data->name);
302
303 printk(KERN_DEBUG "[TIMERIRQ]%s: Unregistering %s\n",
304 __func__, data->name);
305
306 misc_deregister(data);
307 kfree(data);
308
309 timerirq_dev_data = NULL;
310}
311module_exit(timerirq_exit);
312
313MODULE_AUTHOR("Invensense Corporation");
314MODULE_DESCRIPTION("Timer IRQ device driver.");
315MODULE_LICENSE("GPL");
316MODULE_ALIAS("timerirq");