Merge branch 'dev' into new_dpf
[kernel/swap-modules.git] / driver / device_driver.c
1 ////////////////////////////////////////////////////////////////////////////////////
2 //
3 //      FILE:           device_driver.c
4 //
5 //      DESCRIPTION:
6 //      This file is C source for SWAP driver.
7 //
8 //      SEE ALSO:       device_driver.h
9 //      AUTHOR:         L.Komkov, S.Dianov, S.Grekhov, A.Gerenkov
10 //      COMPANY NAME:   Samsung Research Center in Moscow
11 //      DEPT NAME:      Advanced Software Group
12 //      CREATED:        2008.02.15
13 //      VERSION:        1.0
14 //      REVISION DATE:  2008.12.03
15 //
16 ////////////////////////////////////////////////////////////////////////////////////
17
18 #include "module.h"
19 #include "device_driver.h"      // device driver
20 #include "handlers_core.h"
21 #include <linux/notifier.h>
22
23 #ifdef OVERHEAD_DEBUG
24 extern unsigned long swap_sum_time;
25 extern unsigned long swap_sum_hit;
26 #endif
27
28
29 extern unsigned long imi_sum_time;
30 extern unsigned long imi_sum_hit;
31
32
33 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
34 static BLOCKING_NOTIFIER_HEAD(swap_notifier_list);
35 #endif
36 pid_t gl_nNotifyTgid;
37 EXPORT_SYMBOL_GPL(gl_nNotifyTgid);
38
39 DECLARE_WAIT_QUEUE_HEAD (notification_waiters_queue);
40 volatile unsigned notification_count;
41
42 static int device_mmap (struct file *filp, struct vm_area_struct *vma);
43 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
44 static int device_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
45 #else
46 static long device_ioctl (struct file *file, unsigned int cmd, unsigned long arg);
47 #endif
48 static int device_open(struct inode *, struct file *);
49 static int device_release(struct inode *, struct file *);
50 static ssize_t device_read(struct file *, char *, size_t, loff_t *);
51 static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
52
53 static int gl_nDeviceOpened = 0;
54 static struct file_operations device_fops = {
55         .owner = THIS_MODULE,
56         .mmap = device_mmap,
57 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
58         .ioctl = device_ioctl,
59 #else
60         .unlocked_ioctl = device_ioctl,
61 #endif
62         .read = device_read,
63         .write = device_write,
64         .open = device_open,
65         .release = device_release
66 };
67
68 typedef void (* dbi_module_callback)();
69
70 int device_init (void)
71 {
72         int nReserved = 0;
73         int nRetVal = register_chrdev(device_major, device_name, &device_fops);
74         if (nRetVal < 0) {
75                 EPRINTF("Cannot register character device! [%s, %d]", device_name, device_major);
76                 nReserved = register_chrdev(0, device_name, &device_fops);
77                 if(nReserved >= 0)
78                 {
79                         unregister_chrdev(nReserved, device_name);
80                         EPRINTF("Please, create a new device node with major number [%d],\n\tand pass it as module parameter!", nReserved);
81                 }
82                 return -1;
83         } else if(nRetVal > 0) {
84                 EPRINTF("Cannot register this device major number! [%d]\n\tTrying a new one. [%d]", device_major, nRetVal);
85                 device_major = nRetVal;
86         }
87         return 0;
88 }
89
90 void device_down (void)
91 {
92         unregister_chrdev(device_major, device_name);
93 }
94
95 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
96 void swap_register_notify (struct notifier_block *nb)
97 {
98         blocking_notifier_chain_register(&swap_notifier_list, nb);
99 }
100 EXPORT_SYMBOL_GPL(swap_register_notify);
101
102 void swap_unregister_notify (struct notifier_block *nb)
103 {
104         blocking_notifier_chain_unregister(&swap_notifier_list, nb);
105 }
106 EXPORT_SYMBOL_GPL(swap_unregister_notify);
107 #endif
108
109 void notify_user (event_id_t event_id)
110 {
111         ec_info.events_counters[event_id] += 1;
112
113         if (EVENT_EC_PROBE_RECORD == event_id)
114         {
115                 // EC_PROBE_RECORD events happen to often. To reduce overhead user
116                 // space will be notified only once per each EVENTS_AGGREGATION_USEC
117                 static uint64_t timestamp_usec = 0;
118
119                 uint64_t current_usec;
120                 uint64_t delta_usec;
121
122                 struct timeval tv;
123
124                 do_gettimeofday (&tv);
125                 current_usec = 1000000ULL * (unsigned) tv.tv_sec + (unsigned) tv.tv_usec;
126
127                 if (current_usec < timestamp_usec)
128                 {
129                         // Note: time from do_gettimeofday() may go backward
130                         EPRINTF ("current_usec=%llu timestamp_usec=%llu", current_usec, timestamp_usec);
131                 }
132                 else
133                 {
134                         delta_usec = current_usec - timestamp_usec;
135                         if (EVENTS_AGGREGATION_USEC > delta_usec)
136                         {
137                                 // wait the time left
138 #if defined(__DEBUG)
139                                 unsigned UNUSED left_usec = EVENTS_AGGREGATION_USEC - delta_usec;
140 #endif /* defined(__DEBUG) */
141                                 return; // supress notification
142                         }
143                 }
144                 timestamp_usec = current_usec;  // remember new time for the future use
145         } else if (EVENT_EC_START_CONDITION_SEEN == event_id) {
146                 return;         // supress notification
147         } else if (EVENT_EC_STOP_CONDITION_SEEN == event_id) {
148                 return;         // supress notification
149         }
150
151         ++notification_count;
152         wake_up_interruptible (&notification_waiters_queue);
153 }
154
155 static int device_mmap (struct file *filp UNUSED, struct vm_area_struct *vma)
156 {
157         if(!p_buffer) {
158                 EPRINTF("Null pointer to buffer!");
159                 return -1;
160         }
161         return remap_vmalloc_range (vma, p_buffer, 0);
162 }
163
164 static int device_open(struct inode *inode, struct file *file)
165 {
166         /*if (gl_nDeviceOpened)
167                 return -EBUSY;*/
168         gl_nDeviceOpened++;
169         // TODO
170         try_module_get(THIS_MODULE);
171         return 0;
172 }
173
174 static int device_release(struct inode *inode, struct file *file)
175 {
176         gl_nDeviceOpened--;
177         module_put(THIS_MODULE);
178         return 0;
179 }
180
181 static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t * offset)
182 {
183         EPRINTF("Operation <<read>> not supported!");
184         return -1;
185 }
186
187 static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
188 {
189         EPRINTF("Operation <<write>> not supported!");
190         return -1;
191 }
192
193 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
194 static int device_ioctl (struct inode *inode UNUSED, struct file *file UNUSED, unsigned int cmd, unsigned long arg)
195 #else
196 static long device_ioctl (struct file *file UNUSED, unsigned int cmd, unsigned long arg)
197 #endif
198 {
199         unsigned long spinlock_flags = 0L;
200         int result = -1;
201 //      DPRINTF("Command=%d", cmd);
202         switch (cmd)
203         {
204         case EC_IOCTL_SET_EC_MODE:
205                 {
206                         ioctl_general_t param;
207                         unsigned long nIgnoredBytes = 0;
208                         memset(&param, '0', sizeof(ioctl_general_t));
209                         nIgnoredBytes = copy_from_user (&param, (void*)arg, sizeof(ioctl_general_t));
210                         if (nIgnoredBytes > 0) {
211                                 result = -1;
212                                 break;
213                         }
214                         if(SetECMode(param.m_unsignedLong) == -1) {
215                                 result = -1;
216                                 break;
217                         }
218                         result = 0;
219                         DPRINTF("Set EC Mode = %lu", param.m_unsignedLong);
220                         break;
221                 }
222         case EC_IOCTL_GET_EC_MODE:
223                 {
224                         ioctl_general_t param;
225                         unsigned long nIgnoredBytes = 0;
226                         memset(&param, '0', sizeof(ioctl_general_t));
227                         param.m_unsignedLong = GetECMode();
228                         nIgnoredBytes = copy_to_user ((void*)arg, &param, sizeof (ioctl_general_t));
229                         if (nIgnoredBytes > 0) {
230                                 result = -1;
231                                 break;
232                         }
233                         result = 0;
234 //                      DPRINTF("Get EC Mode = %lu", param.m_unsignedLong);  // Frequent call
235                         break;
236                 }
237         case EC_IOCTL_SET_BUFFER_SIZE:
238                 {
239                         ioctl_general_t param;
240                         unsigned long nIgnoredBytes = 0;
241                         memset(&param, '0', sizeof(ioctl_general_t));
242                         nIgnoredBytes = copy_from_user (&param, (void*)arg, sizeof(ioctl_general_t));
243                         if (nIgnoredBytes > 0) {
244                                 result = -1;
245                                 break;
246                         }
247                         if (SetBufferSize(param.m_unsignedLong) == -1) {
248                                 result = -1;
249                                 break;
250                         }
251                         result = 0;
252                         DPRINTF("Set Buffer Size = %lu", param.m_unsignedLong);
253                         break;
254                 }
255         case EC_IOCTL_GET_BUFFER_SIZE:
256                 {
257                         ioctl_general_t param;
258                         unsigned long nIgnoredBytes = 0;
259                         memset(&param, '0', sizeof(ioctl_general_t));
260                         param.m_unsignedLong = GetBufferSize();
261                         nIgnoredBytes = copy_to_user ((void*)arg, &param, sizeof (ioctl_general_t));
262                         if (nIgnoredBytes > 0) {
263                                 result = -1;
264                                 break;
265                         }
266                         result = 0;
267                         DPRINTF("Get Buffer Size = %lu", param.m_unsignedLong);
268                         break;
269                 }
270         case EC_IOCTL_RESET_BUFFER:
271                 {
272                         if (ResetBuffer() == -1) {
273                                 result = -1;
274                                 break;
275                         }
276                         result = 0;
277                         DPRINTF("Reset Buffer");
278                         break;
279                 }
280         case EC_IOCTL_GET_EC_INFO:
281                 {
282                         if (copy_ec_info_to_user_space ((ec_info_t *) arg) != 0) {
283                                 result = -1;
284                                 break;
285                         }
286                         result = 0;
287 //                      DPRINTF("Get Buffer Status"); // Frequent call
288                         break;
289                 }
290         case EC_IOCTL_CONSUME_BUFFER:
291                 {
292                         static ec_info_t ec_info_copy;
293                         int nIgnoredBytes = 0;
294 #ifndef __DISABLE_RELAYFS
295                         struct rchan* pRelayChannel = NULL;
296                         struct rchan_buf *buf = NULL;
297                         unsigned int nNumOfSubbufs = 0;
298                         void* pConsume = NULL;
299                         unsigned int nPaddingLength = 0;
300                         unsigned int nSubbufSize = 0;
301                         unsigned int nDataSize = 0;
302                         unsigned int nEffectSize = 0;
303                         unsigned int nSubbufDiscardedCount = 0;
304 #endif
305                         nIgnoredBytes = copy_from_user (&ec_info_copy, (ec_info_t *) arg, sizeof (ec_info_t));
306                         if(nIgnoredBytes > 0)
307                         {
308                                 EPRINTF ("copy_from_user(%08X,%08X)=%d", (unsigned) arg, (unsigned) &ec_info_copy, nIgnoredBytes);
309                                 result = -1;
310                                 break;
311                         }
312
313                         spin_lock_irqsave (&ec_spinlock, spinlock_flags);
314                         if((ec_info_copy.m_nMode & MODEMASK_MULTIPLE_BUFFER) == 0) {
315                                 // Original buffer
316                                 if(ec_info.after_last > ec_info.first) {
317                                         ec_info.buffer_effect = ec_info.buffer_size;
318                                 }
319                                 if (ec_info.after_last == ec_info.buffer_effect) {
320                                      ec_info.first = 0;
321                                 } else {
322                                      ec_info.first = ec_info_copy.after_last;
323                                 }
324                                 ec_info.trace_size = ec_info.trace_size - ec_info_copy.trace_size;
325
326                         } else {
327                                 // Relay FS buffer
328 #ifndef __DISABLE_RELAYFS
329                                 pRelayChannel = GetRelayChannel();
330                                 if(pRelayChannel == NULL) {
331                                         EPRINTF("Null pointer to relay channel!");
332                                         result = -1;
333                                         break;
334                                 }
335                                 buf = pRelayChannel->buf[0];
336                                 nNumOfSubbufs = pRelayChannel->n_subbufs;
337
338                                 nSubbufSize = pRelayChannel->subbuf_size;
339                                 pConsume = buf->start + buf->subbufs_consumed % nNumOfSubbufs * nSubbufSize;
340                                 memcpy(&nPaddingLength, pConsume, sizeof(unsigned int));
341                                 memcpy(&nSubbufDiscardedCount, pConsume + sizeof(unsigned int), sizeof(unsigned int));
342                                 nEffectSize = nSubbufSize - nPaddingLength;
343                                 nDataSize = nEffectSize - RELAY_SUBBUF_HEADER_SIZE;
344                                 relay_subbufs_consumed(pRelayChannel, 0, 1);
345                                 ec_info.m_nBeginSubbufNum = buf->subbufs_consumed % nNumOfSubbufs;
346                                 ec_info.m_nEndSubbufNum = buf->subbufs_produced % nNumOfSubbufs;
347                                 ec_info.buffer_effect -= nEffectSize;
348                                 ec_info.trace_size -= nDataSize;
349                                 buf->dentry->d_inode->i_size = ec_info.trace_size;
350 #endif
351                         }
352                         spin_unlock_irqrestore (&ec_spinlock, spinlock_flags);
353                         result = 0;
354 //                      DPRINTF("Consume Buffer"); // Frequent call
355                         break;
356                 }
357         case EC_IOCTL_ADD_PROBE:
358                 {
359                         unsigned long addr = arg;
360                         result = add_probe(addr);
361
362                         break;
363                 }
364         //@AGv: remove_probe expects probe address instead of name
365         /*case EC_IOCTL_REMOVE_PROBE:
366                 {
367                         char *probe_name = (char *) arg;
368                         result = remove_probe (probe_name);
369
370                         break;
371                 }*/
372         case EC_IOCTL_SET_APPDEPS:
373         {
374                 size_t size;
375                 result = copy_from_user(&size, (void *)arg, sizeof(size_t));
376                 if (result) {
377                         EPRINTF("Cannot copy deps size!");
378                         result = -1;
379                         break;
380                 }
381                 DPRINTF("Deps size has been copied (%d)", size);
382
383                 if (size == 0) {
384                         DPRINTF("Deps are size of 0");
385                         break;
386                 }
387
388                 deps = vmalloc(size);
389                 if (deps == NULL) {
390                         EPRINTF("Cannot alloc mem for deps!");
391                         result = -1;
392                         break;
393                 }
394                 DPRINTF("Mem for deps has been allocated");
395
396                 result = copy_from_user(deps, (void *)arg, size);
397                 if (result) {
398                         EPRINTF("Cannot copy deps!");
399                         result = -1;
400                         break;
401                 }
402                 DPRINTF("Deps has been copied successfully");
403
404                 break;
405         }
406         case EC_IOCTL_SET_PID:
407         {
408                 unsigned int _pid;
409
410                 result = copy_from_user(&_pid, (void *)arg, sizeof(unsigned int));
411                 if (result) {
412                         EPRINTF("Cannot copy pid!");
413                         result = -1;
414                         break;
415                 }
416
417                 inst_pid = _pid;
418
419                 DPRINTF("EC_IOCTL_SET_PID pid:%d", inst_pid);
420
421                 break;
422         }
423         case EC_IOCTL_SET_PROFILEBUNDLE:
424         {
425                 size_t size;
426
427                 result = copy_from_user(&size, (void *)arg, sizeof(size_t));
428                 if (result) {
429                         EPRINTF("Cannot copy bundle size!");
430                         result = -1;
431                         break;
432                 }
433                 DPRINTF("Bundle size has been copied");
434
435                 bundle = vmalloc(size);
436                 if (bundle == NULL) {
437                         EPRINTF("Cannot alloc mem for bundle!");
438                         result = -1;
439                         break;
440                 }
441                 DPRINTF("Mem for bundle has been alloced");
442
443                 result = copy_from_user(bundle, (void *)arg, size);
444                 if (result) {
445                         EPRINTF("Cannot copy bundle!");
446                         result = -1;
447                         break;
448                 }
449                 DPRINTF("Bundle has been copied successfully");
450
451                 if (link_bundle() == -1) {
452                         EPRINTF("Cannot link profile bundle!");
453                         result = -1;
454                         break;
455                 }
456
457                 break;
458         }
459         case EC_IOCTL_RESET_PROBES:
460                 {
461                         result = reset_probes();
462
463                         break;
464                 }
465         case EC_IOCTL_UPDATE_CONDS:
466                 {
467                         int args_cnt, i;
468                         struct cond *c, *c_tmp, *p_cond;
469                         unsigned char *p_data;
470                         int err;
471                         result = 0;
472                         err = copy_from_user(&args_cnt, (void *)arg, sizeof(int));
473                         if (err) {
474                                 result = -1;
475                                 break;
476                         }
477                         /* first, delete all the conds */
478                         list_for_each_entry_safe(c, c_tmp, &cond_list.list, list) {
479                                 list_del(&c->list);
480                                 kfree(c);
481                         }
482                         /* second, add new conds */
483                         p_data = (unsigned char *)(arg + sizeof(int));
484                         for (i = 0; i < args_cnt; i++) {
485                                 p_cond = kmalloc(sizeof(struct cond), GFP_KERNEL);
486                                 if (!p_cond) {
487                                         DPRINTF("Cannot alloc cond!");
488                                         result = -1;
489                                         break;
490                                 }
491                                 err = copy_from_user(&p_cond->tmpl, p_data, sizeof(struct event_tmpl));
492                                 if (err) {
493                                         DPRINTF("Cannot copy cond from user!");
494                                         result = -1;
495                                         break;
496                                 }
497                                 p_cond->applied = 0;
498                                 list_add(&(p_cond->list), &(cond_list.list));
499                                 p_data += sizeof(struct event_tmpl);
500                         }
501                         break;
502                 }
503         case EC_IOCTL_ATTACH:
504                 {
505                         unsigned long dbi_flags;
506                         struct dbi_modules_handlers *local_mh;
507                         struct dbi_modules_handlers_info *local_mhi;
508                         int j;
509                         dbi_module_callback dmc_start;
510
511                         // call "start"-callback for all modules according module priority
512                         local_mh = get_dbi_modules_handlers();
513                         spin_lock_irqsave(&local_mh->lock, dbi_flags);
514                         for (j = 0; j <= MAX_PRIORITY; j++) {
515                                 list_for_each_entry_rcu(local_mhi, &local_mh->modules_handlers, dbi_list_head) {
516                                         if (local_mhi->dbi_module_priority_start == j) {
517                                                 if (local_mhi->dbi_module_callback_start != NULL) {
518                                                         printk("Started module callback (start) %s\n", local_mhi->dbi_module->name);
519                                                         dmc_start = (dbi_module_callback )local_mhi->dbi_module_callback_start;
520                                                         dmc_start();
521                                                 }
522                                         }
523                                 }
524                         }
525                         spin_unlock_irqrestore(&local_mh->lock, dbi_flags);
526
527                         result = ec_user_attach ();
528 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
529                         DPRINTF("EC_IOCTL_ATTACH calling notification chain");
530                         blocking_notifier_call_chain(&swap_notifier_list, EC_IOCTL_ATTACH, (void*)NULL);
531 #endif
532                         DPRINTF("Attach Probes");
533                         break;
534                 }
535         case EC_IOCTL_ACTIVATE:
536                 result = ec_user_activate ();
537                 DPRINTF("Activate Probes");
538                 break;
539         case EC_IOCTL_STOP_AND_DETACH:
540         {
541                 unsigned long nIgnoredBytes = 0;
542                 unsigned long dbi_flags;
543                 struct dbi_modules_handlers *local_mh;
544                 struct dbi_modules_handlers_info *local_mhi;
545                 unsigned int local_module_refcount = 0;
546                 int j;
547                 dbi_module_callback dmc_stop;
548
549 #ifdef OVERHEAD_DEBUG
550                 printk("\nswap_sum_time = %ld in kprobe_handler()\n", swap_sum_time);
551                 printk("swap_sum_hit = %ld in kprobe_handler()\n", swap_sum_hit);
552                 swap_sum_time = 0;
553                 swap_sum_hit = 0;
554 #endif
555
556                 printk("\n### imi_sum_time = %ld in install_mapped_ips()\n", imi_sum_time);
557                 printk("### imi_sum_hit = %ld in install_mapped_ips()\n", imi_sum_hit);
558
559                 if (imi_sum_hit != 0) {
560                         printk("### time = %ld in install_mapped_ips()\n", imi_sum_time/imi_sum_hit);
561                 }
562
563                 imi_sum_time = 0;
564                 imi_sum_hit = 0;
565
566                 local_mh = get_dbi_modules_handlers();
567                 if(ec_user_stop() != 0) {
568                         result = -1;
569                         goto sad_cleanup;
570                 }
571                 nIgnoredBytes = copy_ec_info_to_user_space ((ec_info_t*)arg);
572                 if(nIgnoredBytes > 0) {
573                         result = -1;
574                         goto sad_cleanup;
575                 }
576                 vfree(bundle);
577                 result = 0;
578                 DPRINTF("Stop and Detach Probes");
579 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
580                 DPRINTF("EC_IOCTL_STOP_AND_DETACH calling notification chain");
581                 blocking_notifier_call_chain(&swap_notifier_list, EC_IOCTL_STOP_AND_DETACH, (void*)&gl_nNotifyTgid);
582 #endif
583                 // call "stop"-callback for all modules according module priority
584                 spin_lock_irqsave(&local_mh->lock, dbi_flags);
585                 for (j = 0; j <= MAX_PRIORITY; j++) {
586                         list_for_each_entry_rcu(local_mhi, &local_mh->modules_handlers, dbi_list_head) {
587                                 if (local_mhi->dbi_module_priority_stop == j) {
588                                         if (local_mhi->dbi_module_callback_stop != NULL) {
589                                                 printk("Started module callback (stop) %s\n", local_mhi->dbi_module->name);
590                                                 dmc_stop = (dbi_module_callback )local_mhi->dbi_module_callback_stop;
591                                                 dmc_stop();
592                                         }
593                                 }
594                         }
595                 }
596                 spin_unlock_irqrestore(&local_mh->lock, dbi_flags);
597 sad_cleanup:
598                 spin_lock_irqsave(&local_mh->lock, dbi_flags);
599                 list_for_each_entry_rcu(local_mhi, &local_mh->modules_handlers, dbi_list_head) {
600                         local_module_refcount = module_refcount(local_mhi->dbi_module);
601                         if (local_module_refcount == 1) {
602                                 module_put(local_mhi->dbi_module);
603                         }
604                         else if (local_module_refcount > 1) {
605                                 printk("local_module_refcount too much - force set refcount to zero\n");
606                                 while (local_module_refcount--)
607                                         module_put(local_mhi->dbi_module);
608                         }
609                 }
610                 spin_unlock_irqrestore(&local_mh->lock, dbi_flags);
611                 break;
612         }
613         case EC_IOCTL_WAIT_NOTIFICATION:
614                 {
615                         static ec_info_t ec_info_copy;
616
617                         ioctl_wait_notification_t ioctl_args;
618
619                         result = copy_from_user (&ioctl_args, (void *) arg, sizeof (ioctl_args));
620                         if (result)
621                         {
622                                 result = -1;
623                                 break;
624                         }
625
626                         result = wait_event_interruptible (notification_waiters_queue, ioctl_args.notification_count != notification_count);
627                         if (result)
628                         {
629                                 result = -EINTR;        // woken by signal (ERESTARTSYS 512)
630                                 break;
631                         }
632
633                         ioctl_args.notification_count = notification_count;
634
635                         result = copy_to_user ((void *) arg, &ioctl_args, sizeof (ioctl_args));
636                         if (result)
637                         {
638                                 result = -1;
639                                 break;
640                         }
641
642                         // FIXME: synchronization is necessary here (ec_info must be locked).
643                         // ENTER_CRITICAL_SECTION
644                         memcpy (&ec_info_copy, &ec_info, sizeof (ec_info_copy));
645                         // LEAVE_CRITICAL_SECTION
646
647                         result = copy_to_user ((void *) ioctl_args.p_ec_info, &ec_info_copy, sizeof (ec_info_t));
648                         if (result)
649                         {
650                                 EPRINTF ("copy_to_user(%08X,%08X)=%d", (unsigned) ioctl_args.p_ec_info, (unsigned) &ec_info_copy, result);
651                                 result = -1;
652                                 break;
653                         }
654                         DPRINTF("Wake up");
655                         break;
656                 }
657         case EC_IOCTL_US_EVENT:
658                 {
659                         ioctl_us_event_t ioctl_args;
660                         result = copy_from_user (&ioctl_args, (void *) arg, sizeof (ioctl_args));
661                         if (result)
662                         {
663                                 result = -1;
664                                 EPRINTF ("copy_from_user() failure");
665                         }
666                         else
667                         {
668                                 if(ioctl_args.len == 0){
669                                         result = -EINVAL;
670                                         EPRINTF ("invalid event length!");
671                                 }
672                                 else {
673                                         char *buf = kmalloc(ioctl_args.len, GFP_KERNEL);
674                                         if(!buf){
675                                                 result = -ENOMEM;
676                                                 EPRINTF ("failed to alloc mem for event!");
677                                         }
678                                         else {
679                                                 result = copy_from_user (buf, (void *) ioctl_args.data, ioctl_args.len);
680                                                 if (result){
681                                                         result = -1;
682                                                         EPRINTF ("failed to copy event from user space!");
683                                                 }
684                                                 else
685                                                         result = put_us_event(buf, ioctl_args.len);
686                                                 kfree(buf);
687                                         }
688                                 }
689                         }
690 //                      DPRINTF("User Space Event"); // Frequent call
691                         break;
692                 }
693
694         case EC_IOCTL_SET_EVENT_MASK:
695                 {
696                         int mask;
697                         result = copy_from_user (&mask, (void *) arg, sizeof (mask));
698                         if (result)
699                         {
700                                 result = -EFAULT;
701                                 break;
702                         }
703
704                         result = set_event_mask (mask);
705                         if (result)
706                         {
707                                 break;
708                         }
709                         DPRINTF("Set Event Mask = %d", mask);
710                         break;
711                 }
712
713         case EC_IOCTL_GET_EVENT_MASK:
714                 {
715                         int mask = 0;
716                         result = get_event_mask(&mask);
717                         if (result)
718                         {
719                                 result = -EFAULT;
720                         }
721                         result = copy_to_user ((void *) arg, &mask, sizeof (mask));
722                         if (result)
723                         {
724                                 result = -EFAULT;
725                         }
726                         DPRINTF("Get Event Mask = %d", mask);
727                         break;
728                 }
729
730         case EC_IOCTL_SET_PREDEF_UPROBES:
731                 {
732                         ioctl_predef_uprobes_info_t data;
733                         result = copy_from_user (&data, (void *) arg, sizeof (data));
734                         if (result)
735                         {
736                                 result = -EFAULT;
737                                 break;
738                         }
739
740                         result = set_predef_uprobes (&data);
741                         if (result)
742                         {
743                                 break;
744                         }
745                         DPRINTF("Set Predefined User Space Probes");
746                         break;
747                 }
748
749         case EC_IOCTL_GET_PREDEF_UPROBES:
750                 {
751                         result = get_predef_uprobes((ioctl_predef_uprobes_info_t *)arg);
752                         if (result)
753                         {
754                                 result = -EFAULT;
755                         }
756                         DPRINTF("Get Predefined User Space Probes");
757                         break;
758                 }
759
760         case EC_IOCTL_GET_PREDEF_UPROBES_SIZE:
761                 {
762                         int size = 0;
763                         result = get_predef_uprobes_size(&size);
764                         if (result)
765                         {
766                                 result = -EFAULT;
767                         }
768                         result = copy_to_user ((void *) arg, &size, sizeof (size));
769                         if (result)
770                         {
771                                 result = -EFAULT;
772                         }
773                         DPRINTF("Get Size of Predefined User Space Probes");
774                         break;
775                 }
776
777         default:
778                 EPRINTF ("Unknown driver command = %u", cmd);
779                 result = -EINVAL;
780                 break;
781         }
782
783         return result;
784 }