Re: Problem with interrupt handler

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

 



Hello,

thank you very much for your answer.

Am 25. Januar 2010 20:31 schrieb Uwe Kleine-König
<u.kleine-koenig@xxxxxxxxxxxxxx>:
> On Mon, Jan 25, 2010 at 06:16:08PM +0100, Julian Fuchs wrote:
(...)
> Did you try with IRQF_NODELAY on vanilla and without it in rt?

I tried it with IRQF_NODELAY in rt and without IRQF_NODELAY on vanilla
(vanilla won't compile with IRQF_NODELAY AFAIR).

> Are you sure the irq fires in rt?

It fires in the normal kernel (i.e. the hardware is working). How can
I determine whether the interrupt fires in rt?

>  Does your interrupt appear in /proc/interrupts?

Yes, it appears there (and the name of the module is listed correctly
in the same line).

On vanilla, the counter in /proc/interrupts increases, on rt, it
doesn't. It seems that the interrupt just doesn't fire... is there any
kind of "magic" I can do on rt to "enable" the interrupt? It seems
disabled :-(

> What platform are you working on?

I'm working on a Intel Celeron 1,8 GHz board (x86) with Ubuntu Linux
9.10 as a distro.

>  Do you can send the code of a minimal example?

Sure. Below you find the code of a minimal example for a rs232
interface. If you have any suggestions for a smaller example, please
tell me and will create it (I just don't know how to create the
interrupt otherwise).

Thanks a lot for your help,

Julian

-----
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/proc_fs.h>
#include <linux/inet.h>
#include <linux/net.h>
#include <net/tcp.h>
#include <net/ip.h>
#include <net/protocol.h>


/* --- DEFITIONS AND SETTINGS --- */

// Module information
MODULE_AUTHOR("Somebody");
MODULE_DESCRIPTION("some serial interface driver");
MODULE_LICENSE("GPL");
#define MODULE_IDENT "foobar"
#define VERSION_STRING "foobar v0.1\n"

// Configurable parameters
int base_port = 0xcf00;
const int port_range = 8;
int irq = 16;

int irq_counter = 0;

module_param(base_port, int, 0644);
MODULE_PARM_DESC(base_port, "The base port address of the serial interface");
module_param(irq, int, 0644);
MODULE_PARM_DESC(irq, "IRQ of the serial interface");


// Serial port communication
// registers
#define IER 1 // interrupt enable register
#define FCR 2 // FIFO control register (write) / Interrupt
Identification Register (read)
#define LCR 3 // line control register

// serial port settings
#define PARITY_NO 0x0
#define STOPBIT_1 0
#define CS_8 0x3
#define MAX_BAUDRATE 921600

#define DIVISOR_ACCESS 0x80

// interrupt identification and enabling
#define IER_DATA_AVAILABLE 0x1
#define IER_LS_CHANGE 0x4

// Global control variables
int stage = 0;

/* --- SERIAL PORT CONFIGURATION INTERFACE --- */

void set_serial_options(void);

void set_serial_options(void) {
	unsigned int divisor;
	unsigned char parity, stopbit, cs, status;

	stopbit = STOPBIT_1;
	parity = PARITY_NO;
	cs = CS_8;

	status = parity | stopbit | cs | DIVISOR_ACCESS;
	outb(status, base_port+LCR);
	divisor = 24;
	outb(divisor & 0x00ff, base_port);
	outb(divisor & 0xff00, base_port+1);

	// reset divisor access bit
	outb(status &~ DIVISOR_ACCESS, base_port+LCR);
}


irqreturn_t interrupt_handler(int myirq, void *dev_id) {
	
	unsigned char iir_byte, bitmask;
	iir_byte = inb(base_port + FCR);
	bitmask = 1;
	if ( (iir_byte & bitmask) == 1) {
		// interrupt is not for this module
		return IRQ_NONE;
	}
	// interrupt is for this module
	unsigned char data_byte;
	data_byte = inb(base_port);
	
	irq_counter++;
	
	return IRQ_HANDLED;
}


void cleanup_module(void) {
	// I/O ports reserved
	if (stage >= 2) {
		release_region(base_port, port_range);
		printk(KERN_INFO "%s: releasing I/O ports\n", MODULE_IDENT);
	}
	// IRQ reserved
	if (stage >= 1) {
		// because of shared irq, &stage is given, otherwise NULL will do, too
		free_irq(irq, &stage);
		// disable interrupts from the card
		outb(0, base_port + IER);

		printk(KERN_INFO "%s: freeing irq %i\n", MODULE_IDENT, irq);
	}
	printk(KERN_INFO "%s: module unloaded\n", MODULE_IDENT);
	
	printk(KERN_ERR "%d irq_counter\n", irq_counter);
}

/* Setup all operations - called by kernel when module is loaded */
int init_module(void) {

	int err = 0;

	printk(KERN_INFO VERSION_STRING);

	// Stage 1. Request IRQ using shared interrupts
	// dev_id can't be NULL since the kernel needs to label the different ISRs
	// stage is just as a pointer to our address space, any other address
will do, too.
	if ((err = request_irq(irq, interrupt_handler, IRQF_SHARED |
IRQF_DISABLED | IRQF_NODELAY, MODULE_IDENT, &stage)) < 0) return err;
	stage++;

	// Stage 2. Request access to I/O ports
	if ((err = check_region(base_port, port_range)) < 0) {
		cleanup_module();
		return err;
	}
	request_region(base_port, port_range, MODULE_IDENT);
	stage++;

	printk(KERN_INFO "Using serial port at %x, IRQ %i\n", base_port, irq);

	// Configure serial port
	set_serial_options();

	// disable FIFO
	outb(0, base_port+FCR);

	// enable interrupts if data available or break signal received
	outb(IER_DATA_AVAILABLE | IER_LS_CHANGE, base_port+IER);
	
	printk(KERN_ERR "INIT MODULE DONE!\n");

	return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [RT Stable]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux