1 ////////////////////////////////////////////////////////////////////////////////////
3 // FILE: device_driver.c
6 // This file is C source for SWAP driver.
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
14 // REVISION DATE: 2008.12.03
16 ////////////////////////////////////////////////////////////////////////////////////
19 #include "device_driver.h" // device driver
21 #include <linux/notifier.h>
23 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
24 static BLOCKING_NOTIFIER_HEAD(inperfa_notifier_list);
27 EXPORT_SYMBOL_GPL(gl_nNotifyTgid);
29 DECLARE_WAIT_QUEUE_HEAD (notification_waiters_queue);
30 volatile unsigned notification_count;
32 static int device_mmap (struct file *filp, struct vm_area_struct *vma);
33 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
34 static int device_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
36 static int device_ioctl (struct file *file, unsigned int cmd, unsigned long arg);
38 static int device_open(struct inode *, struct file *);
39 static int device_release(struct inode *, struct file *);
40 static ssize_t device_read(struct file *, char *, size_t, loff_t *);
41 static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
43 static int gl_nDeviceOpened = 0;
44 static struct file_operations device_fops = {
47 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
48 .ioctl = device_ioctl,
50 .unlocked_ioctl = device_ioctl,
53 .write = device_write,
55 .release = device_release
58 int device_init (void)
61 int nRetVal = register_chrdev(device_major, device_name, &device_fops);
63 EPRINTF("Cannot register character device! [%s, %d]", device_name, device_major);
64 nReserved = register_chrdev(0, device_name, &device_fops);
66 EPRINTF("Please, create a new device node with major number [%d],\n\tand pass it as module parameter!", nReserved);
68 } else if(nRetVal > 0) {
69 EPRINTF("Cannot register this device major number! [%d]\n\tTrying a new one. [%d]", device_major, nRetVal);
70 device_major = nRetVal;
75 void device_down (void)
77 unregister_chrdev(device_major, device_name);
80 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
81 void inperfa_register_notify (struct notifier_block *nb)
83 blocking_notifier_chain_register(&inperfa_notifier_list, nb);
85 EXPORT_SYMBOL_GPL(inperfa_register_notify);
87 void inperfa_unregister_notify (struct notifier_block *nb)
89 blocking_notifier_chain_unregister(&inperfa_notifier_list, nb);
91 EXPORT_SYMBOL_GPL(inperfa_unregister_notify);
94 void notify_user (event_id_t event_id)
96 ec_info.events_counters[event_id] += 1;
98 if (EVENT_EC_PROBE_RECORD == event_id)
100 // EC_PROBE_RECORD events happen to often. To reduce overhead user
101 // space will be notified only once per each EVENTS_AGGREGATION_USEC
102 static uint64_t timestamp_usec = 0;
104 uint64_t current_usec;
109 do_gettimeofday (&tv);
110 current_usec = 1000000ULL * (unsigned) tv.tv_sec + (unsigned) tv.tv_usec;
112 if (current_usec < timestamp_usec)
114 // Note: time from do_gettimeofday() may go backward
115 EPRINTF ("current_usec=%llu timestamp_usec=%llu", current_usec, timestamp_usec);
119 delta_usec = current_usec - timestamp_usec;
120 if (EVENTS_AGGREGATION_USEC > delta_usec)
122 // wait the time left
124 unsigned UNUSED left_usec = EVENTS_AGGREGATION_USEC - delta_usec;
125 #endif /* defined(__DEBUG) */
126 return; // supress notification
129 timestamp_usec = current_usec; // remember new time for the future use
130 } else if (EVENT_EC_START_CONDITION_SEEN == event_id) {
131 return; // supress notification
132 } else if (EVENT_EC_STOP_CONDITION_SEEN == event_id) {
133 return; // supress notification
136 ++notification_count;
137 wake_up_interruptible (¬ification_waiters_queue);
140 static int device_mmap (struct file *filp UNUSED, struct vm_area_struct *vma)
143 EPRINTF("Null pointer to buffer!");
146 return remap_vmalloc_range (vma, p_buffer, 0);
149 static int device_open(struct inode *inode, struct file *file)
151 /*if (gl_nDeviceOpened)
155 try_module_get(THIS_MODULE);
159 static int device_release(struct inode *inode, struct file *file)
162 module_put(THIS_MODULE);
166 static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t * offset)
168 EPRINTF("Operation <<read>> not supported!");
172 static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
174 EPRINTF("Operation <<write>> not supported!");
177 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
178 static int device_ioctl (struct inode *inode UNUSED, struct file *file UNUSED, unsigned int cmd, unsigned long arg)
180 static int device_ioctl (struct file *file UNUSED, unsigned int cmd, unsigned long arg)
183 unsigned long spinlock_flags = 0L;
185 // DPRINTF("Command=%d", cmd);
188 case EC_IOCTL_SET_EC_MODE:
190 ioctl_general_t param;
191 unsigned long nIgnoredBytes = 0;
192 memset(¶m, '0', sizeof(ioctl_general_t));
193 nIgnoredBytes = copy_from_user (¶m, (void*)arg, sizeof(ioctl_general_t));
194 if (nIgnoredBytes > 0) {
198 if(SetECMode(param.m_unsignedLong) == -1) {
203 DPRINTF("Set EC Mode = %lu", param.m_unsignedLong);
206 case EC_IOCTL_GET_EC_MODE:
208 ioctl_general_t param;
209 unsigned long nIgnoredBytes = 0;
210 memset(¶m, '0', sizeof(ioctl_general_t));
211 param.m_unsignedLong = GetECMode();
212 nIgnoredBytes = copy_to_user ((void*)arg, ¶m, sizeof (ioctl_general_t));
213 if (nIgnoredBytes > 0) {
218 // DPRINTF("Get EC Mode = %lu", param.m_unsignedLong); // Frequent call
221 case EC_IOCTL_SET_BUFFER_SIZE:
223 ioctl_general_t param;
224 unsigned long nIgnoredBytes = 0;
225 memset(¶m, '0', sizeof(ioctl_general_t));
226 nIgnoredBytes = copy_from_user (¶m, (void*)arg, sizeof(ioctl_general_t));
227 if (nIgnoredBytes > 0) {
231 if (SetBufferSize(param.m_unsignedLong) == -1) {
236 DPRINTF("Set Buffer Size = %lu", param.m_unsignedLong);
239 case EC_IOCTL_GET_BUFFER_SIZE:
241 ioctl_general_t param;
242 unsigned long nIgnoredBytes = 0;
243 memset(¶m, '0', sizeof(ioctl_general_t));
244 param.m_unsignedLong = GetBufferSize();
245 nIgnoredBytes = copy_to_user ((void*)arg, ¶m, sizeof (ioctl_general_t));
246 if (nIgnoredBytes > 0) {
251 DPRINTF("Get Buffer Size = %lu", param.m_unsignedLong);
254 case EC_IOCTL_RESET_BUFFER:
256 if (ResetBuffer() == -1) {
261 DPRINTF("Reset Buffer");
264 case EC_IOCTL_GET_EC_INFO:
266 if (copy_ec_info_to_user_space ((ec_info_t *) arg) != 0) {
271 // DPRINTF("Get Buffer Status"); // Frequent call
274 case EC_IOCTL_CONSUME_BUFFER:
276 static ec_info_t ec_info_copy;
277 int nIgnoredBytes = 0;
278 #ifndef __DISABLE_RELAYFS
279 struct rchan* pRelayChannel = NULL;
280 struct rchan_buf *buf = NULL;
281 unsigned int nNumOfSubbufs = 0;
282 void* pConsume = NULL;
283 unsigned int nPaddingLength = 0;
284 unsigned int nSubbufSize = 0;
285 unsigned int nDataSize = 0;
286 unsigned int nEffectSize = 0;
287 unsigned int nSubbufDiscardedCount = 0;
289 nIgnoredBytes = copy_from_user (&ec_info_copy, (ec_info_t *) arg, sizeof (ec_info_t));
290 if(nIgnoredBytes > 0)
292 EPRINTF ("copy_from_user(%08X,%08X)=%d", (unsigned) arg, (unsigned) &ec_info_copy, nIgnoredBytes);
297 spin_lock_irqsave (&ec_spinlock, spinlock_flags);
298 if((ec_info_copy.m_nMode & MODEMASK_MULTIPLE_BUFFER) == 0) {
300 if(ec_info.after_last > ec_info.first) {
301 ec_info.buffer_effect = ec_info.buffer_size;
303 if (ec_info.after_last == ec_info.buffer_effect) {
306 ec_info.first = ec_info_copy.after_last;
308 ec_info.trace_size = ec_info.trace_size - ec_info_copy.trace_size;
312 #ifndef __DISABLE_RELAYFS
313 pRelayChannel = GetRelayChannel();
314 if(pRelayChannel == NULL) {
315 EPRINTF("Null pointer to relay channel!");
319 buf = pRelayChannel->buf[0];
320 nNumOfSubbufs = pRelayChannel->n_subbufs;
322 nSubbufSize = pRelayChannel->subbuf_size;
323 pConsume = buf->start + buf->subbufs_consumed % nNumOfSubbufs * nSubbufSize;
324 memcpy(&nPaddingLength, pConsume, sizeof(unsigned int));
325 memcpy(&nSubbufDiscardedCount, pConsume + sizeof(unsigned int), sizeof(unsigned int));
326 nEffectSize = nSubbufSize - nPaddingLength;
327 nDataSize = nEffectSize - RELAY_SUBBUF_HEADER_SIZE;
328 relay_subbufs_consumed(pRelayChannel, 0, 1);
329 ec_info.m_nBeginSubbufNum = buf->subbufs_consumed % nNumOfSubbufs;
330 ec_info.m_nEndSubbufNum = buf->subbufs_produced % nNumOfSubbufs;
331 ec_info.buffer_effect -= nEffectSize;
332 ec_info.trace_size -= nDataSize;
333 buf->dentry->d_inode->i_size = ec_info.trace_size;
336 spin_unlock_irqrestore (&ec_spinlock, spinlock_flags);
338 // DPRINTF("Consume Buffer"); // Frequent call
341 case EC_IOCTL_ADD_PROBE:
343 unsigned long addr = arg;
344 result = add_probe(addr);
348 //@AGv: remove_probe expects probe address instead of name
349 /*case EC_IOCTL_REMOVE_PROBE:
351 char *probe_name = (char *) arg;
352 result = remove_probe (probe_name);
356 case EC_IOCTL_SET_APPDEPS:
359 result = copy_from_user(&size, (void *)arg, sizeof(size_t));
361 EPRINTF("Cannot copy deps size!");
365 DPRINTF("Deps size has been copied (%d)", size);
368 DPRINTF("Deps are size of 0");
372 deps = vmalloc(size);
374 EPRINTF("Cannot alloc mem for deps!");
378 DPRINTF("Mem for deps has been allocated");
380 result = copy_from_user(deps, (void *)arg, size);
382 EPRINTF("Cannot copy deps!");
386 DPRINTF("Deps has been copied successfully");
390 case EC_IOCTL_SET_PID:
394 result = copy_from_user(&_pid, (void *)arg, sizeof(unsigned int));
396 EPRINTF("Cannot copy pid!");
403 DPRINTF("EC_IOCTL_SET_PID pid:%d", inst_pid);
407 case EC_IOCTL_SET_PROFILEBUNDLE:
411 result = copy_from_user(&size, (void *)arg, sizeof(size_t));
413 EPRINTF("Cannot copy bundle size!");
417 DPRINTF("Bundle size has been copied");
419 bundle = vmalloc(size);
420 if (bundle == NULL) {
421 EPRINTF("Cannot alloc mem for bundle!");
425 DPRINTF("Mem for bundle has been alloced");
427 result = copy_from_user(bundle, (void *)arg, size);
429 EPRINTF("Cannot copy bundle!");
433 DPRINTF("Bundle has been copied successfully");
435 if (link_bundle() == -1) {
436 EPRINTF("Cannot link profile bundle!");
443 case EC_IOCTL_RESET_PROBES:
445 result = reset_probes();
449 case EC_IOCTL_UPDATE_CONDS:
452 struct cond *c, *c_tmp, *p_cond;
453 unsigned char *p_data;
456 err = copy_from_user(&args_cnt, (void *)arg, sizeof(int));
461 /* first, delete all the conds */
462 list_for_each_entry_safe(c, c_tmp, &cond_list.list, list) {
466 /* second, add new conds */
467 p_data = (unsigned char *)(arg + sizeof(int));
468 for (i = 0; i < args_cnt; i++) {
469 p_cond = kmalloc(sizeof(struct cond), GFP_KERNEL);
471 DPRINTF("Cannot alloc cond!");
475 err = copy_from_user(&p_cond->tmpl, p_data, sizeof(struct event_tmpl));
477 DPRINTF("Cannot copy cond from user!");
482 list_add(&(p_cond->list), &(cond_list.list));
483 p_data += sizeof(struct event_tmpl);
487 case EC_IOCTL_ATTACH:
488 result = ec_user_attach ();
489 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
490 DPRINTF("EC_IOCTL_ATTACH calling notification chain");
491 blocking_notifier_call_chain(&inperfa_notifier_list, EC_IOCTL_ATTACH, (void*)NULL);
493 DPRINTF("Attach Probes");
495 case EC_IOCTL_ACTIVATE:
496 result = ec_user_activate ();
497 DPRINTF("Activate Probes");
499 case EC_IOCTL_STOP_AND_DETACH:
501 unsigned long nIgnoredBytes = 0;
502 if(ec_user_stop() != 0) {
506 nIgnoredBytes = copy_ec_info_to_user_space ((ec_info_t*)arg);
507 if(nIgnoredBytes > 0) {
513 DPRINTF("Stop and Detach Probes");
514 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
515 DPRINTF("EC_IOCTL_STOP_AND_DETACH calling notification chain");
516 blocking_notifier_call_chain(&inperfa_notifier_list, EC_IOCTL_STOP_AND_DETACH, (void*)&gl_nNotifyTgid);
520 case EC_IOCTL_WAIT_NOTIFICATION:
522 static ec_info_t ec_info_copy;
524 ioctl_wait_notification_t ioctl_args;
526 result = copy_from_user (&ioctl_args, (void *) arg, sizeof (ioctl_args));
533 result = wait_event_interruptible (notification_waiters_queue, ioctl_args.notification_count != notification_count);
536 result = -EINTR; // woken by signal (ERESTARTSYS 512)
540 ioctl_args.notification_count = notification_count;
542 result = copy_to_user ((void *) arg, &ioctl_args, sizeof (ioctl_args));
549 // FIXME: synchronization is necessary here (ec_info must be locked).
550 // ENTER_CRITICAL_SECTION
551 memcpy (&ec_info_copy, &ec_info, sizeof (ec_info_copy));
552 // LEAVE_CRITICAL_SECTION
554 result = copy_to_user ((void *) ioctl_args.p_ec_info, &ec_info_copy, sizeof (ec_info_t));
557 EPRINTF ("copy_to_user(%08X,%08X)=%d", (unsigned) ioctl_args.p_ec_info, (unsigned) &ec_info_copy, result);
564 case EC_IOCTL_US_EVENT:
566 ioctl_us_event_t ioctl_args;
567 result = copy_from_user (&ioctl_args, (void *) arg, sizeof (ioctl_args));
571 EPRINTF ("copy_from_user() failure");
575 if(ioctl_args.len == 0){
577 EPRINTF ("invalid event length!");
580 char *buf = kmalloc(ioctl_args.len, GFP_KERNEL);
583 EPRINTF ("failed to alloc mem for event!");
586 result = copy_from_user (buf, (void *) ioctl_args.data, ioctl_args.len);
589 EPRINTF ("failed to copy event from user space!");
592 result = put_us_event(buf, ioctl_args.len);
597 // DPRINTF("User Space Event"); // Frequent call
601 case EC_IOCTL_SET_EVENT_MASK:
604 result = copy_from_user (&mask, (void *) arg, sizeof (mask));
611 result = set_event_mask (mask);
616 DPRINTF("Set Event Mask = %d", mask);
620 case EC_IOCTL_GET_EVENT_MASK:
623 result = get_event_mask(&mask);
628 result = copy_to_user ((void *) arg, &mask, sizeof (mask));
633 DPRINTF("Get Event Mask = %d", mask);
637 case EC_IOCTL_SET_PREDEF_UPROBES:
639 ioctl_predef_uprobes_info_t data;
640 result = copy_from_user (&data, (void *) arg, sizeof (data));
647 result = set_predef_uprobes (&data);
652 DPRINTF("Set Predefined User Space Probes");
656 case EC_IOCTL_GET_PREDEF_UPROBES:
658 result = get_predef_uprobes((ioctl_predef_uprobes_info_t *)arg);
663 DPRINTF("Get Predefined User Space Probes");
667 case EC_IOCTL_GET_PREDEF_UPROBES_SIZE:
670 result = get_predef_uprobes_size(&size);
675 result = copy_to_user ((void *) arg, &size, sizeof (size));
680 DPRINTF("Get Size of Predefined User Space Probes");
685 EPRINTF ("Unknown driver command = %u", cmd);