Hi!
I am writing some Diagnostics code for a UART chip.
I was able to write most of our test cases from application space using
inb/outb calls.
To test the 'interrupts' generated by this device, i decided to use the
same application space program to cause interrupts to be generated in the
device and write a simple kernel module which just registers for the static
IRQ line (4 in this case) using the request_irq() call and implements the
ISR. Please find the code as attachment.
On 'insmod', i am able to see the registered module in /proc/interrupts.
The kernel i am using is 2.6.18.
On running the application program, I can see that a interrupt is generated
in the UART.( By checking the respective register)
But, the ISR I have registered is not getting called. I have tried
registering the interrupt with and without sharing, with the same result.
Am i missing something ?
/*
* "Hello, world!" minimal kernel module
*
*
*/
/*
* The below are header files provided by the kernel which are
* required for all modules. They include things like the definition
* of the module_init() macro.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_reg.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
/*#include <linux/serial_8250.h>*/
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/serial.h>
struct old_serial_port {
unsigned int uart;
unsigned int baud_base;
unsigned int port;
unsigned int irq;
unsigned int flags;
unsigned char hub6;
unsigned char io_type;
unsigned char *iomem_base;
unsigned short iomem_reg_shift;
};
struct uart_diag_st {
char name;
};
struct uart_diag_st ust;
#ifndef SERIAL_PORT_DFNS
#define SERIAL_PORT_DFNS
#endif
static const struct old_serial_port ouart_serial_port[] = {
SERIAL_PORT_DFNS /* defined in asm/serial.h */
};
#define MPD_DIAG_CONSOLE &mpd_diag_console
static struct uart_driver uart_reg_st = {
.owner = THIS_MODULE,
.driver_name = "ttyDiag",
.dev_name = "ttyDi",
.major = TTY_MAJOR,
.minor = 164,
.nr = 1,
.cons = NULL,
};
/**
static struct platform_driver uart_isa_drv = {
.probe = mpd_uart_probe,
.remove = __devexit_p(uart_remove),
.suspend = mpd_uart_suspend,
.resume = mpd_uart_resume,
.driver = {
.name = "mpd_uart_diag",
.owner = THIS_MODULE,
},
};
**/
static struct platform_device *uart_dev;
static struct uart_port uart_port_st;
static unsigned int mpd_uart_tx_empty(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_tx_empty..\n");
return 0;
}
static void mpd_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
printk("KERN_INFO In mpd_uart_set_mctrl..\n");
}
static unsigned int mpd_uart_get_mctrl(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_get_mctrl..\n");
return 0;
}
static void mpd_uart_stop_tx(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_stop_tx..\n");
}
static void mpd_uart_start_tx(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_start_tx..\n");
}
static void mpd_uart_stop_rx(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_stop_rx..\n");
}
static void mpd_uart_enable_ms(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_enable_ms..\n");
}
static void mpd_uart_break_ctl(struct uart_port *port, int break_state)
{
printk("KERN_INFO In mpd_uart_break_ctl..\n");
}
static int mpd_uart_startup(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_startup..\n");
return 0;
}
static void mpd_uart_shutdown(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_shutdown..\n");
}
static void
mpd_uart_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
printk("KERN_INFO In mpd_uart_set_termios..\n");
}
static const char*
mpd_uart_type(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_type..\n");
return "8250";
}
static void mpd_uart_release_port(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_release_port..\n");
}
static int mpd_uart_request_port(struct uart_port *port)
{
printk("KERN_INFO In mpd_uart_request_port..\n");
return 1;
}
static int mpd_request_std_resource(struct uart_port* port)
{
unsigned int size = 8 << port->regshift;
int ret = 0;
switch (port->iotype) {
case UPIO_AU:
size = 0x100000;
/* fall thru */
case UPIO_MEM:
if (!port->mapbase)
break;
if (!request_mem_region(port->mapbase, size, "serial")) {
ret = -EBUSY;
break;
}
if (port->flags & UPF_IOREMAP) {
port->membase = ioremap(port->mapbase, size);
if (!port->membase) {
release_mem_region(port->mapbase, size);
}
}
break;
case UPIO_HUB6:
case UPIO_PORT:
if (!request_region(port->iobase, size, "serial"))
ret = -EBUSY;
break;
}
return ret;
}
static void mpd_uart_config_port(struct uart_port *port, int flags)
{
int ret;
printk("KERN_INFO In mpd_uart_config_port..\n");
ret = mpd_request_std_resource(port);
if (ret < 0)
return;
port->type = PORT_8250;
/**
if (flags & UART_CONFIG_TYPE)
autoconfig(up, probeflags);
if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
autoconfig_irq(up);
**/
/**
if (up->port.type == PORT_UNKNOWN)
mpd_release_std_resource(port);
**/
}
static int
mpd_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
printk(KERN_INFO "In mpd_uart_verify_port..\n");
return 1;
}
/**
static void
mpd_uart_console_write(struct console *co, const char *s, unsigned int count)
{
printk("In mpd_uart_console_write..\n");
}
static int mpd_uart_console_setup(struct console *co, char *options)
{
printk("In mpd_uart_console_setup..\n");
return 0;
}
static struct console mpd_diag_console = {
.name = "ttyDi",
.write = mpd_uart_console_write,
.device = uart_console_device,
.setup = mpd_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &uart_reg_st,
};
**/
static struct uart_ops uart_ops_st = {
.tx_empty = mpd_uart_tx_empty,
.set_mctrl = mpd_uart_set_mctrl,
.get_mctrl = mpd_uart_get_mctrl,
.stop_tx = mpd_uart_stop_tx,
.start_tx = mpd_uart_start_tx,
.stop_rx = mpd_uart_stop_rx,
.enable_ms = mpd_uart_enable_ms,
.break_ctl = mpd_uart_break_ctl,
.startup = mpd_uart_startup,
.shutdown = mpd_uart_shutdown,
.set_termios = mpd_uart_set_termios,
.type = mpd_uart_type,
.release_port = mpd_uart_release_port,
.request_port = mpd_uart_request_port,
.config_port = mpd_uart_config_port,
.verify_port = mpd_uart_verify_port,
};
static void __init
register_ports(struct uart_driver *drv, struct device *dev)
{
uart_port_st.ops = &uart_ops_st;
uart_port_st.iobase = ouart_serial_port[0].port;
uart_port_st.irq = irq_canonicalize(ouart_serial_port[0].irq);
uart_port_st.uartclk = ouart_serial_port[0].baud_base*16;
uart_port_st.flags = ouart_serial_port[0].flags;
uart_port_st.hub6 = ouart_serial_port[0].hub6;
uart_port_st.membase = ouart_serial_port[0].iomem_base;
uart_port_st.iotype = ouart_serial_port[0].io_type;
uart_port_st.regshift = ouart_serial_port[0].iomem_reg_shift;
uart_port_st.dev = dev;
uart_add_one_port(drv, &uart_port_st);
}
/* INTR Handler */
static irqreturn_t diag_uart_intr(int irq, void *dev_id)
{
printk(KERN_INFO "diag_uart: inside intr handler! IRQ - %d\n", irq);
return IRQ_HANDLED;
}
/*
* This is the init function, which is run when the module is first
* loaded. The __init keyword tells the kernel that this code will
* only be run once, when the module is loaded.
*/
static int __init
regi_init(void)
{
int ret;
ust.name = 'a';
ret = uart_register_driver(&uart_reg_st);
if (ret)
{
printk(KERN_ERR "Error registering Uart driver. \n");
goto out;
}
/* Regiser device with which you are communicating */
uart_dev = platform_device_alloc("mpd_uart", -1);
if (!uart_dev)
{
printk(KERN_ERR "Error allocating Uart Platform Device Struct. \n");
ret = -ENOMEM;
goto unreg_uart_drv;
}
ret = platform_device_add(uart_dev);
if (ret)
{
printk(KERN_ERR "Error adding Uart Platform Device. \n");
goto put_dev;
}
register_ports(&uart_reg_st, &uart_dev->dev);
/*ret = platform_driver_register(&uart_isa_drv);*/
/* Register for INTR 4 */
/***
if (!can_request_irq(4, SA_SHIRQ))
{
printk(KERN_INFO "can_request_irq() failed\n");
return 0;
}
****/
printk(KERN_INFO "diag_uart: Registering for INTR Line 4 ... ");
ret = request_irq(4, diag_uart_intr, IRQF_SHARED, "diag_uart", (void*) &ust);
if (ret)
{
printk(KERN_INFO "Cannot get IRQ4.\n");
}
else
{
printk(KERN_INFO "Done.\n");
goto out;
}
platform_device_del(uart_dev);
put_dev:
platform_device_put(uart_dev);
unreg_uart_drv:
uart_unregister_driver(&uart_reg_st);
out:
return ret;
}
/*
* The below macro informs the kernel as to which function to use as
* the init function.
*/
module_init(regi_init);
/*
* Similary, the exit function is run once, upon module unloading, and
* the module_exit() macro identifies which function is the exit
* function.
*/
static void __exit
regi_exit(void)
{
free_irq(4, (void*) &ust);
printk(KERN_INFO "diag_uart- Removed intr registration.!\n");
platform_device_unregister(uart_dev);
uart_unregister_driver(&uart_reg_st);
}
module_exit(regi_exit);
/*
* MODULE_LICENSE() informs the kernel what license the module source
* code is under, which affects which symbols it may access in the
* main kernel. Certain module licenses will "taint" the kernel,
* indicating that non-open or untrusted code has been loaded.
* Modules licensed under GPLv2 do not taint the kernel and can access
* all symbols, but declaring it so is a legal statement that the
* source code to this module is licensed under GPLv2, and so you must
* provide the source code if you ship a binary version of the module.
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Abhijit Verma");
MODULE_DESCRIPTION("\"Register Interrupt\" diag_uart module");
MODULE_VERSION("diag_uart");