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