Date: Sun, 21 Jan 2001 17:10:30 +0100 From: "Alex" <d_f0rce@gmx.de> To: <freebsd-hackers@freebsd.org> Subject: Problems attaching an interrupt handler Message-ID: <NEBBIKIHMLCDHCFEOMAHOEKCCAAA.d_f0rce@gmx.de>
index | next in thread | raw e-mail
[-- Attachment #1 --]
Hi,
I started experimenting with kernel hacking to write an
infrared device driver. Therfore I read Alexander Langer's
article on DaemonNews and started modifying the led.c
example code.
Unfortunately I can't get my interrupt handler working.
Could anyone please have a short look on my code.
On loading the module the first time everything stays
stable and vmstat -i shows 1 INT on my device. After
unloading the module and reloading it the kernel
crashes on the next incoming interrupt.
Any ideas?
Alex
[-- Attachment #2 --]
/*
* Copyright (c) 2000. M. Warner Losh. All Rights Reserved.
*
* "THE BEER-WARE LICENSE" (Revision 42):
* <imp@FreeBSD.ORG> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. M. Warner Losh
*/
/*
* Simple driver for the I-Opener LED, but likely could be adapted
* to any led driver. This is intended to be a thought excersize
* as well as a useful sample driver. Since I don't have a hackable
* iopener around to test it out on.
*
* The LED is located at 0x404c on the iopener. Likely we should find this
* in the pci space, and then do stuff from tehre. However, it appears to
* be controlled in some way by acpi, so I'm going to try to write this driver
* to not interfere with that.
*
* the lower two bits of this register control the state of the LED. The left
* led, with the mail ICON, is controlled by bit 0. The phone led is
* controlled by bit 1.
*
* This is a bog simple ISA driver... Would make a useful example, imho.
*
* Since I'm lazy, I have only a write interface. The characters recieved
* by the driver are masked and the results sent to these gpios. This
* allows things like '1' to turn on the led and '0' to turn off the led.
* There is a minor number for each led controlled.
*
* The read interface returns 1 character ('0' off '1' on) for the state
* of the led.
*
* thanks to "roastbeef" who posted technical information about this to the
* I-Opener BBS web site.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/module.h>
#include <sys/uio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
struct ir_softc
{
bus_space_tag_t bst;
bus_space_handle_t bsh;
dev_t dev0;
dev_t dev1;
u_int32_t open_mask;
u_int32_t read_mask;
struct resource *res;
int rid;
struct resource *irq;
void *ih;
int irqid;
};
static devclass_t ir_devclass;
#define IR_IOADDR 0x3f8
static void ir_intr( void *p );
void get_sio_status( struct ir_softc *sc );
static void
ir_identify (driver_t *driver, device_t parent)
{
devclass_t dc;
device_t child;
dc = devclass_find("ir");
if (devclass_get_device(dc, 0) == NULL) {
child = BUS_ADD_CHILD(parent, 0, "ir", -1);
bus_set_resource(child, SYS_RES_IOPORT, 0, IR_IOADDR, 7);
bus_set_resource(child, SYS_RES_IRQ, 0, 4, 1);
}
uprintf("IR Ident\n");
}
static int
ir_probe(device_t dev)
{
if (device_get_unit(dev) != 0)
return (ENXIO);
if (bus_get_resource_start(dev, SYS_RES_IOPORT, 0) == 0)
return (ENXIO);
uprintf("IR Probe\n");
return (0);
}
static int
ir_attach(device_t dev)
{
struct ir_softc *sc;
u_int8_t old;
sc = (struct ir_softc *) device_get_softc(dev);
sc->rid = 0;
sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid, 0ul, ~0ul, 7,
RF_ACTIVE);
if (sc->res == NULL)
return ENXIO;
sc->bst = rman_get_bustag(sc->res);
sc->bsh = rman_get_bushandle(sc->res);
sc->open_mask = 0;
sc->read_mask = 0;
uprintf("IR Attach\nTrying to access device ....\n");
get_sio_status( sc );
/* FIFO Puffer aktivieren */
bus_space_write_1(sc->bst, sc->bsh,2,(u_int8_t) 7);
/* keine Kontrolle, da IIR fuer FIFO-Operation write only */
/* LCR Bit 7 auf 0 */
old = bus_space_read_1(sc->bst, sc->bsh,3);
old &= ~128; /* Bit 7 ausnullen */
bus_space_write_1(sc->bst, sc->bsh,3,(u_int8_t) old);
/* IER setzen, um Interrupt bei Modem Status Aenderung auszuloesen */
old = bus_space_read_1(sc->bst, sc->bsh,1);
old &= ~1; /* Bit 0 ausnullen => kein INT ausloesen, sobald ein neues Zeichen im RBR */
old &= ~2; /* Bit 1 ausnullen => kein INT sobald THR leer */
old &= ~4; /* Bit 2 ausnullen => kein INT sobald Aenderung im LSR */
old |= 8; /* Bit 3 setzen => INT bei Aenderung im MSR */
bus_space_write_1(sc->bst, sc->bsh,1,(u_int8_t) old);
/* RTS im MCR auf high setzen */
old = bus_space_read_1(sc->bst, sc->bsh,4);
old |= 1; /* Bit 0 setzen - DTR auf 0 -> PC bereit */
old |= 2; /* Bit 1 setzen - RTS auf 0 -> PC will senden */
old |= 8; /* Bit 3 setzen - UART loest INTs gemaess den Einstellungen im IER aus */
old &= ~16; /* Bit 4 ausnullen => Selbsttest aus. */
bus_space_write_1(sc->bst, sc->bsh,4,(u_int8_t) old);
get_sio_status( sc );
/* Interrupt Handler */
sc->irqid=0;
sc->irq = bus_alloc_resource( dev, SYS_RES_IRQ, &sc->irqid, 0ul, ~0ul, 1, RF_SHAREABLE | RF_ACTIVE );
uprintf("IRQID: %d\n",sc->irqid);
if( !sc->irq )
return ENXIO;
if( BUS_SETUP_INTR(device_get_parent(dev), dev, sc->irq, INTR_TYPE_MISC, ir_intr, sc, &sc->ih) != 0){
uprintf("Failed to init INT\n");
}
return 0;
}
static int
ir_detach(device_t dev)
{
struct ir_softc *sc;
sc = (struct ir_softc *) device_get_softc(dev);
/* deactivate Interrupt Handler */
bus_teardown_intr(dev, sc->irq, sc->ih) != 0 );
bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
/* release resources */
bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->res);
uprintf("IR Detach\n");
return 0;
}
static device_method_t ir_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, ir_identify),
DEVMETHOD(device_probe, ir_probe),
DEVMETHOD(device_attach, ir_attach),
DEVMETHOD(device_detach, ir_detach),
{ 0, 0 }
};
static driver_t ir_driver = {
"ir",
ir_methods,
sizeof(struct ir_softc),
};
static void ir_intr( void *p ){
uprintf("GOT INTERUPT!\n");
}
void get_sio_status( struct ir_softc *sc ){
u_int8_t old;
uprintf("--------------------------------\n");
/* Erstmal Bit 7 im LCR auf 0 um alle Register auszulesen,
die dieses Bit auf 0 verlangen */
old = bus_space_read_1(sc->bst, sc->bsh,3);
old &= ~128; /* Bit 7 ausnullen */
bus_space_write_1(sc->bst, sc->bsh,3,(u_int8_t) old);
/* RBR auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,0);
uprintf("RBR: %d\n", old);
/* IER auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,1);
uprintf("IER: %d\n", old);
/* Bit 7 im LCR wieder setzen, um Register abzufragen, die
dieses Bit auf 1 brauchen */
old = bus_space_read_1(sc->bst, sc->bsh,3);
old |= 128; /* Bit 7 setzen */
bus_space_write_1(sc->bst, sc->bsh,3,(u_int8_t) old);
/* DLL Register auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,0);
uprintf("DLL: %d\n", old);
/* DLM Register auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,1);
uprintf("DLM: %d\n", old);
/* Jetzt noch die Register, denen das Bit 7 wurscht ist. */
/* IIR Register auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,2);
uprintf("IIR: %d\n", old);
/* LCR Register auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,3);
uprintf("LCR: %d\n", old);
/* MCR Register auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,4);
uprintf("MCR: %d\n", old);
/* LSR Register auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,5);
uprintf("LSR: %d\n", old);
/* DLM Register auslesen */
old = bus_space_read_1(sc->bst, sc->bsh,6);
uprintf("MSR: %d\n", old);
uprintf("--------------------------------\n");
}
DRIVER_MODULE(ir, isa, ir_driver, ir_devclass, 0, 0);
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?NEBBIKIHMLCDHCFEOMAHOEKCCAAA.d_f0rce>
