diff options
Diffstat (limited to 'drivers/mfd/ab8500-debugfs.c')
-rw-r--r-- | drivers/mfd/ab8500-debugfs.c | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 2e40e12fc687..4699fff322a0 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c | |||
@@ -23,6 +23,10 @@ static u32 debug_address; | |||
23 | 23 | ||
24 | static int irq_first; | 24 | static int irq_first; |
25 | static int irq_last; | 25 | static int irq_last; |
26 | static u32 irq_count[AB8500_NR_IRQS]; | ||
27 | |||
28 | static struct device_attribute *dev_attr[AB8500_NR_IRQS]; | ||
29 | static char *event_name[AB8500_NR_IRQS]; | ||
26 | 30 | ||
27 | /** | 31 | /** |
28 | * struct ab8500_reg_range | 32 | * struct ab8500_reg_range |
@@ -364,12 +368,15 @@ static irqreturn_t ab8500_debug_handler(int irq, void *data) | |||
364 | { | 368 | { |
365 | char buf[16]; | 369 | char buf[16]; |
366 | struct kobject *kobj = (struct kobject *)data; | 370 | struct kobject *kobj = (struct kobject *)data; |
371 | unsigned int irq_abb = irq - irq_first; | ||
367 | 372 | ||
373 | if (irq_abb < AB8500_NR_IRQS) | ||
374 | irq_count[irq_abb]++; | ||
368 | /* | 375 | /* |
369 | * This makes it possible to use poll for events (POLLPRI | POLLERR) | 376 | * This makes it possible to use poll for events (POLLPRI | POLLERR) |
370 | * from userspace on sysfs file named irq-<nr> | 377 | * from userspace on sysfs file named <irq-nr> |
371 | */ | 378 | */ |
372 | sprintf(buf, "irq-%d", irq); | 379 | sprintf(buf, "%d", irq); |
373 | sysfs_notify(kobj, NULL, buf); | 380 | sysfs_notify(kobj, NULL, buf); |
374 | 381 | ||
375 | return IRQ_HANDLED; | 382 | return IRQ_HANDLED; |
@@ -555,19 +562,26 @@ static int ab8500_subscribe_unsubscribe_open(struct inode *inode, | |||
555 | } | 562 | } |
556 | 563 | ||
557 | /* | 564 | /* |
558 | * This function is used for all interrupts and will always print | 565 | * Userspace should use poll() on this file. When an event occur |
559 | * the same string. It is however this file sysfs_notify called on. | ||
560 | * Userspace should read this file and then poll. When an event occur | ||
561 | * the blocking poll will be released. | 566 | * the blocking poll will be released. |
562 | */ | 567 | */ |
563 | static ssize_t show_irq(struct device *dev, | 568 | static ssize_t show_irq(struct device *dev, |
564 | struct device_attribute *attr, char *buf) | 569 | struct device_attribute *attr, char *buf) |
565 | { | 570 | { |
566 | return sprintf(buf, "irq\n"); | 571 | unsigned long name; |
567 | } | 572 | unsigned int irq_index; |
573 | int err; | ||
568 | 574 | ||
569 | static struct device_attribute *dev_attr[AB8500_NR_IRQS]; | 575 | err = strict_strtoul(attr->attr.name, 0, &name); |
570 | static char *event_name[AB8500_NR_IRQS]; | 576 | if (err) |
577 | return err; | ||
578 | |||
579 | irq_index = name - irq_first; | ||
580 | if (irq_index >= AB8500_NR_IRQS) | ||
581 | return -EINVAL; | ||
582 | else | ||
583 | return sprintf(buf, "%u\n", irq_count[irq_index]); | ||
584 | } | ||
571 | 585 | ||
572 | static ssize_t ab8500_subscribe_write(struct file *file, | 586 | static ssize_t ab8500_subscribe_write(struct file *file, |
573 | const char __user *user_buf, | 587 | const char __user *user_buf, |
@@ -578,6 +592,7 @@ static ssize_t ab8500_subscribe_write(struct file *file, | |||
578 | int buf_size; | 592 | int buf_size; |
579 | unsigned long user_val; | 593 | unsigned long user_val; |
580 | int err; | 594 | int err; |
595 | unsigned int irq_index; | ||
581 | 596 | ||
582 | /* Get userspace string and assure termination */ | 597 | /* Get userspace string and assure termination */ |
583 | buf_size = min(count, (sizeof(buf)-1)); | 598 | buf_size = min(count, (sizeof(buf)-1)); |
@@ -597,19 +612,23 @@ static ssize_t ab8500_subscribe_write(struct file *file, | |||
597 | return -EINVAL; | 612 | return -EINVAL; |
598 | } | 613 | } |
599 | 614 | ||
615 | irq_index = user_val - irq_first; | ||
616 | if (irq_index >= AB8500_NR_IRQS) | ||
617 | return -EINVAL; | ||
618 | |||
600 | /* | 619 | /* |
601 | * This will create a sysfs file named irq-<nr> which userspace can | 620 | * This will create a sysfs file named <irq-nr> which userspace can |
602 | * use to select or poll and get the AB8500 events | 621 | * use to select or poll and get the AB8500 events |
603 | */ | 622 | */ |
604 | dev_attr[user_val] = kmalloc(sizeof(struct device_attribute), | 623 | dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute), |
605 | GFP_KERNEL); | 624 | GFP_KERNEL); |
606 | event_name[user_val] = kmalloc(buf_size, GFP_KERNEL); | 625 | event_name[irq_index] = kmalloc(buf_size, GFP_KERNEL); |
607 | sprintf(event_name[user_val], "irq-%lu", user_val); | 626 | sprintf(event_name[irq_index], "%lu", user_val); |
608 | dev_attr[user_val]->show = show_irq; | 627 | dev_attr[irq_index]->show = show_irq; |
609 | dev_attr[user_val]->store = NULL; | 628 | dev_attr[irq_index]->store = NULL; |
610 | dev_attr[user_val]->attr.name = event_name[user_val]; | 629 | dev_attr[irq_index]->attr.name = event_name[irq_index]; |
611 | dev_attr[user_val]->attr.mode = S_IRUGO; | 630 | dev_attr[irq_index]->attr.mode = S_IRUGO; |
612 | err = sysfs_create_file(&dev->kobj, &dev_attr[user_val]->attr); | 631 | err = sysfs_create_file(&dev->kobj, &dev_attr[irq_index]->attr); |
613 | if (err < 0) { | 632 | if (err < 0) { |
614 | printk(KERN_ERR "sysfs_create_file failed %d\n", err); | 633 | printk(KERN_ERR "sysfs_create_file failed %d\n", err); |
615 | return err; | 634 | return err; |
@@ -621,6 +640,7 @@ static ssize_t ab8500_subscribe_write(struct file *file, | |||
621 | if (err < 0) { | 640 | if (err < 0) { |
622 | printk(KERN_ERR "request_threaded_irq failed %d, %lu\n", | 641 | printk(KERN_ERR "request_threaded_irq failed %d, %lu\n", |
623 | err, user_val); | 642 | err, user_val); |
643 | sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr); | ||
624 | return err; | 644 | return err; |
625 | } | 645 | } |
626 | 646 | ||
@@ -636,6 +656,7 @@ static ssize_t ab8500_unsubscribe_write(struct file *file, | |||
636 | int buf_size; | 656 | int buf_size; |
637 | unsigned long user_val; | 657 | unsigned long user_val; |
638 | int err; | 658 | int err; |
659 | unsigned int irq_index; | ||
639 | 660 | ||
640 | /* Get userspace string and assure termination */ | 661 | /* Get userspace string and assure termination */ |
641 | buf_size = min(count, (sizeof(buf)-1)); | 662 | buf_size = min(count, (sizeof(buf)-1)); |
@@ -655,12 +676,20 @@ static ssize_t ab8500_unsubscribe_write(struct file *file, | |||
655 | return -EINVAL; | 676 | return -EINVAL; |
656 | } | 677 | } |
657 | 678 | ||
658 | free_irq(user_val, &dev->kobj); | 679 | irq_index = user_val - irq_first; |
659 | kfree(event_name[user_val]); | 680 | if (irq_index >= AB8500_NR_IRQS) |
660 | kfree(dev_attr[user_val]); | 681 | return -EINVAL; |
682 | |||
683 | /* Set irq count to 0 when unsubscribe */ | ||
684 | irq_count[irq_index] = 0; | ||
685 | |||
686 | if (dev_attr[irq_index]) | ||
687 | sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr); | ||
661 | 688 | ||
662 | if (dev_attr[user_val]) | 689 | |
663 | sysfs_remove_file(&dev->kobj, &dev_attr[user_val]->attr); | 690 | free_irq(user_val, &dev->kobj); |
691 | kfree(event_name[irq_index]); | ||
692 | kfree(dev_attr[irq_index]); | ||
664 | 693 | ||
665 | return buf_size; | 694 | return buf_size; |
666 | } | 695 | } |