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