Writing serial port interrupt handler in linux
8 comments
I'm going to assume you're doing this for intellectual curiosity, because I'm sure the existing serial port drivers work fine. That's okay; I used to do operating system development (aka "osdev") a few years back as a hobby, so I understand how you feel :)
Here are my hunches for what the problem is: you're initializing the UART wrong (it's been a while and I forget the details), you're conflicting with something else that's using the serial port, or you're registering your ISR wrong.
To test whether your UART initialization is correct, you can try removing Linux from the mix. It's pretty simple to create a binary that GRUB can boot (Google: multiboot specification), and that way you can test out your code in isolation. You'll want to use polling rather than ISRs to wait for data, and write directly into the VGA buffer (it's on the even bytes starting at 0xB8000) to print your data to screen.
You also might want to try running this through Bochs, because it can give you hardware-level logs about what's going on. Are bytes actually being received? Is the IRQ actually being raised? That sort of thing.
If that works, then your problem is with Linux itself, and I can't be much help there. I suggest looking through the source for other drivers that register IRQ handlers, or asking the linux-kernel mailing list.
Best of luck.
Here are my hunches for what the problem is: you're initializing the UART wrong (it's been a while and I forget the details), you're conflicting with something else that's using the serial port, or you're registering your ISR wrong.
To test whether your UART initialization is correct, you can try removing Linux from the mix. It's pretty simple to create a binary that GRUB can boot (Google: multiboot specification), and that way you can test out your code in isolation. You'll want to use polling rather than ISRs to wait for data, and write directly into the VGA buffer (it's on the even bytes starting at 0xB8000) to print your data to screen.
You also might want to try running this through Bochs, because it can give you hardware-level logs about what's going on. Are bytes actually being received? Is the IRQ actually being raised? That sort of thing.
If that works, then your problem is with Linux itself, and I can't be much help there. I suggest looking through the source for other drivers that register IRQ handlers, or asking the linux-kernel mailing list.
Best of luck.
Thanks for the guidelines !!
This may not be likely, but - you don't specify a level for your printk statement. It could be your message is just not getting printed to console. Check out info for "/proc/sys/kernel/printk" as well as information about syslogd and klogd as the message may be logged to somewhere else.
I also would like to mention that in general memory barriers can be useful for working with i/o irrespective of your particular situation.
I also would like to mention that in general memory barriers can be useful for working with i/o irrespective of your particular situation.
More explicit handling of error conditions is also good FWIW - don't see you doing it here. The kernel is not forgiving of using resources your don't have or failing to free resources acquired.
Also from what I know, which is not much, you should be requesting the ports via request_region. If that fails you should probably not be writing to the ports and should also mean you're sharing the port with another module.
kernel newbies is theoretically a good place to go with these kinds of questions too.
kernel newbies is theoretically a good place to go with these kinds of questions too.
Homework?
I had this assignment while studying Operating Systems Design during college. I can tell you I failed miserable. We used documentation from: http://www.beyondlogic.org/serial/serial.htm. You can find some examples there, but not for the Linux kernel.
I had this assignment while studying Operating Systems Design during college. I can tell you I failed miserable. We used documentation from: http://www.beyondlogic.org/serial/serial.htm. You can find some examples there, but not for the Linux kernel.
Kindly help !!
#include <linux/kernel.h> #include <linux/interrupt.h> #include <asm/io.h>
#define PORT 0x3F8
irq_handler_t isrSerialPort (int irq, void dev_id, struct pt_regs regs) { printk ("\nThank god !\n"); return (irq_handler_t) IRQ_HANDLED; }
int init_module () { outb (0x01, PORT + 1); outb (0x83, PORT + 3);
SA_SHIRQ, "God", (void *) (isrSerialPort));
}
MODULE_LICENSE ("GPL");