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