Skip site navigation (1)Skip section navigation (2)
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>