Registered ISR is not invoked

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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");

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux