/* * irq.c -- demonstrate basic irq functionality in the kernel */ #include #include /* printk() */ #include /* error codes */ #include #include #include #include #include #include #define LED_BASE 0x378 #define IRQ_LED_ON 7 #define IRQ_LED_OFF 10 struct tq_struct led_on_tq; struct tq_struct led_off_tq; int irq_read_proc(char *buf, char **start, off_t offset, int len, int unused) { len = sprintf(buf, "Fill in with you desired information...\n"); return len; } struct proc_dir_entry irq_proc_entry = { 0, 3, "irq", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL, &irq_read_proc, }; void led_on_handler(int irq, void *dev_id, struct pt_regs *regs) { /* * if this was a real device we would need to do some kind of * interrupt_acknowledge here (disable hardware that generated this * interrupt), but here we don't have to do that because it's free running * anyway (expect to service this interrupt in much less time than 1/50 * sec.) */ printk("<1>led_on_handler: top half; interrupt recieved...\n"); /* * here are the 2 lines of code to queue and mark the bottom half */ queue_task(&led_on_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); printk("<1>led_on_handler: top half; bottom half queued and marked...\n"); } void led_off_handler(int irq, void *dev_id, struct pt_regs *regs) { /* * if this was a real device we would need to do some kind of * interrupt_acknowledge here (disable hardware that generated this * interrupt), but here we don't have to do that because it's free running * anyway (expect to service this interrupt in much less time than 1/50 * sec.) */ printk("<1>led_off_handler: top half; interrupt recieved...\n"); /* * here are the 2 lines of code to queue and mark the bottom half */ queue_task(&led_off_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); printk("<1>led_off_handler: top half; bottom half queued and marked...\n"); } void bh_led_on(void *unused) { /* * turn LED on */ printk("<1>led_on_handler: bottom half; writing 0xaa into %i...\n", LED_BASE); outb(0xaa, LED_BASE); } void bh_led_off(void *unused) { /* * turn LED off */ printk("<1>led_off_handler: bottom half; writing 0x55 into %i...\n", LED_BASE); outb(0x55, LED_BASE); } int init_module(void) { int result = check_region(LED_BASE, 32); if (result) { printk(KERN_INFO "irq: can't get I/O address 0x%x\n", LED_BASE); return result; } request_region(LED_BASE, 32, "irq"); // outb(0x30, LED_BASE+2); /* irq enable and set bidirectional (input) */ outb(0x10, LED_BASE+2); /* to enable IRQ for happening on ack (pin10) */ // outb(0x20, LED_BASE+2); /* to get bidirectional (e.g. as input) */ /* * set up irq hadling */ led_on_tq.routine = bh_led_on; led_on_tq.data = NULL; led_off_tq.routine = bh_led_off; led_off_tq.data = NULL; /* * request led on irq number and install handler */ result = request_irq(IRQ_LED_ON, led_on_handler, 0, "LED on", NULL); if (result) { printk("<1>led_on_handler: failed install of irq %i handler...\n", IRQ_LED_ON); return result; } printk("<1>led_on_handler: irq %i handler installed...\n", IRQ_LED_ON); /* * request led off irq number and install handler */ result = request_irq(IRQ_LED_OFF, led_off_handler, 0, "LED off", NULL); if (result) { printk("<1>led_off_handler: failed install of irq %i handler...\n", IRQ_LED_OFF); return result; } printk("<1>led_off_handler: irq %i handler installed...\n", IRQ_LED_OFF); /* * register the proc fs inode */ //proc_register_dynamic(&proc_root, &irq_proc_entry); return 0; } void cleanup_module(void) { release_region(LED_BASE, 32); /* * unregister the proc fs inode */ //proc_unregister(&proc_root, irq_proc_entry.low_ino); /* * release grabbed irq lines */ free_irq(IRQ_LED_ON, NULL); free_irq(IRQ_LED_OFF, NULL); printk("<1>irq removed...\n"); }