irq.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /*
  2. Brute force monitor every shared interrupt that will accept us.
  3. I.e. only works if for IRQs for which the other handlers are registered as IRQF_SHARED.
  4. Usage:
  5. 1. insmod and then use the keyboard and mouse. Those handlers are shared,
  6. and the messages show up whenever you do something.
  7. Does not work in text mode of course.
  8. 2. insmod some module that generates interrupts after insmod irq.,
  9. e.g. pci_min or platform_device.
  10. TODO: why does insmod in ARM lead to infinitely many interrupts handler irq = 45 dev = 252
  11. and blocks the board? Is the ARM timer shared, and x86 isn't?
  12. TODO: properly understand how each IRQ maps to what.
  13. The Linux kernel mainline also has dummy-irq for monitoring a single IRQ.
  14. Inside QEMU, also try:
  15. watch -n 1 cat /proc/interrupts
  16. Then see how clicking the mouse and keyboard affect the interrupts. This will point you to:
  17. - 1: keyboard
  18. - 12: mouse click and drags
  19. */
  20. #include <linux/fs.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/kernel.h>
  23. #include <linux/module.h>
  24. #include <linux/uaccess.h> /* copy_from_user, copy_to_user */
  25. #define NAME "lkmc_character_device"
  26. #define MAX_IRQS 256
  27. static int irqs[MAX_IRQS];
  28. static int major;
  29. /**
  30. * Return value from kernel docs:*
  31. *
  32. * enum irqreturn
  33. * @IRQ_NONE interrupt was not from this device or was not handled
  34. * @IRQ_HANDLED interrupt was handled by this device
  35. * @IRQ_WAKE_THREAD handler requests to wake the handler thread
  36. */
  37. static irqreturn_t handler(int irq, void *dev)
  38. {
  39. pr_info("handler irq = %d dev = %d\n", irq, *(int *)dev);
  40. return IRQ_NONE;
  41. }
  42. static const struct file_operations fops;
  43. static int myinit(void)
  44. {
  45. int ret, i;
  46. major = register_chrdev(0, NAME, &fops);
  47. for (i = 0; i < MAX_IRQS; ++i) {
  48. ret = request_irq(
  49. i,
  50. handler,
  51. IRQF_SHARED,
  52. "myirqhandler0",
  53. &major
  54. );
  55. irqs[i] = ret;
  56. pr_info("request_irq irq = %d ret = %d\n", i, ret);
  57. }
  58. return 0;
  59. }
  60. static void myexit(void)
  61. {
  62. int i;
  63. for (i = 0; i < MAX_IRQS; ++i) {
  64. if (!irqs[i]) {
  65. free_irq(i, &major);
  66. }
  67. }
  68. unregister_chrdev(major, NAME);
  69. }
  70. module_init(myinit)
  71. module_exit(myexit)
  72. MODULE_LICENSE("GPL");