From 91414848a3546de4630424632cbcf19ba357ee7d Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 24 Oct 2000 16:45:58 +0000 Subject: First effort at bringing these up-to-date. This creates a skeleton ISA device driver. I don't pretend that it's fully correct or even opitimal but it at least creates (and compiles) a 'clean' ISA driver. Hopefully PCI/PCCARD/etc. support will be added when I understand it. Unlike the old version this just creates a module. The old one tried to create a new kernel with the driver to be tested. --- share/examples/drivers/make_device_driver.sh | 565 +++++++++++++-------------- 1 file changed, 277 insertions(+), 288 deletions(-) diff --git a/share/examples/drivers/make_device_driver.sh b/share/examples/drivers/make_device_driver.sh index 81a7db4..a614c8e 100755 --- a/share/examples/drivers/make_device_driver.sh +++ b/share/examples/drivers/make_device_driver.sh @@ -6,41 +6,97 @@ #loadable kernel modules, though without much use except for development. # # Trust me, RUN THIS SCRIPT :) +# $FreeBSD$" # #-------cut here------------------ -cd /sys/i386/conf - if [ "${1}X" = "X" ] then echo "Hey , how about some help here.. give me a device name!" exit 1 fi +UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"` -if [ -d /usr/src/lkm ] +HERE=`pwd` +cd /sys +TOP=`pwd` + +echo ${TOP}/modules/${1} +echo ${TOP}/i386/conf/files.${UPPER} +echo ${TOP}/i386/conf/${UPPER} +echo ${TOP}/dev/${1} +echo ${TOP}/dev/${1}/${1}.c +echo ${TOP}/sys/${1}io.h +echo ${TOP}/modules/${1} +echo ${TOP}/modules/${1}/Makefile + +rm -rf ${TOP}/dev/${1} +rm -rf ${TOP}/modules/${1} +rm ${TOP}/i386/conf/files.${UPPER} +rm ${TOP}/i386/conf/${UPPER} +rm ${TOP}/sys/${1}io.h + +if [ -d ${TOP}/modules/${1} ] then - mkdir /usr/src/lkm/${1} + echo "There appears to already be a module called ${1}" + exit 1 +else + mkdir ${TOP}/modules/${1} fi -UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"` -cat >files.${UPPER} <${TOP}/i386/conf/files.${UPPER} <${UPPER} <${TOP}/i386/conf/${UPPER} <>${UPPER} +grep -v GENERIC < /sys/i386/conf/GENERIC >>${TOP}/i386/conf/${UPPER} -cat >>${UPPER} <>${TOP}/i386/conf/${UPPER} <../isa/${1}.c <${TOP}/dev/${1}/${1}.c <../isa/${1}.c < #include -#include /* SYSINIT stuff */ #include /* cdevsw stuff */ +#include /* SYSINIT stuff */ +#include /* SYSINIT stuff */ #include /* malloc region definitions */ -#include /* DELAY() */ -#include /* ISA bus port definitions etc. */ -#include /* ISA bus configuration structures */ +#include +#include +#include +#include +#include +#include + +#include +#include "isa_if.h" #include /* ${1} IOCTL definitions */ -#ifdef DEVFS -#include /* DEVFS defintitions */ -#endif /* DEVFS */ +#define ${UPPER}DEV2SOFTC(dev) ((dev)->si_drv1) +#define ${UPPER}_INB(port) bus_space_read_1( bt, bh, (port)) +#define ${UPPER}_OUTB(port, val) bus_space_write_1( bt, bh, (port), (val)) +#define SOME_PORT 123 +#define EXPECTED_VALUE 0x42 /* Function prototypes (these should all be static) */ -static d_open_t ${1}open; -static d_close_t ${1}close; -static d_read_t ${1}read; -static d_write_t ${1}write; -static d_ioctl_t ${1}ioctl; -static d_mmap_t ${1}mmap; -static d_poll_t ${1}poll; -static int ${1}probe (struct isa_device *); -static int ${1}attach (struct isa_device *); +static int ${1}_isa_probe (device_t); +static int ${1}_isa_attach (device_t); +static int ${1}_isa_detach (device_t); + +static d_open_t ${1}open; +static d_close_t ${1}close; +static d_read_t ${1}read; +static d_write_t ${1}write; +static d_ioctl_t ${1}ioctl; +static d_mmap_t ${1}mmap; +static d_poll_t ${1}poll; #ifdef ${UPPER}_MODULE static ointhand2_t ${1}intr; /* should actually have type inthand2_t */ #endif #define CDEV_MAJOR 20 static struct cdevsw ${1}_cdevsw = { - ${1}open, - ${1}close, - ${1}read, - ${1}write, - ${1}ioctl, - nullstop, - nullreset, - nodevtotty, - ${1}poll, - ${1}mmap, - NULL, - "${1}", - NULL, - -1 }; + /* open */ ${1}open, + /* close */ ${1}close, + /* read */ ${1}read, + /* write */ ${1}write, + /* ioctl */ ${1}ioctl, + /* poll */ ${1}poll, + /* mmap */ ${1}mmap, + /* strategy */ nostrategy, /* not a block type device */ + /* name */ "${1}", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, /* not a block type device */ + /* psize */ nopsize, /* not a block type device */ + /* flags */ 0, + /* bmaj */ -1 +}; -struct isa_driver ${1}driver = { - ${1}probe, - ${1}attach, - "${1}" }; - /* - * device specific Misc defines + * device specific Misc defines */ #define BUFFERSIZE 1024 #define NUMPORTS 4 -#define UNIT(dev) minor(dev) /* assume one minor number per unit */ /* * One of these per allocated device */ struct ${1}_softc { - struct isa_device *dev; + bus_space_tag_t bt; + bus_space_handle_t bh; + int port_rid; + struct resource* port_res; /* resource for port range */ + dev_t dev; + device_t device; char buffer[BUFFERSIZE]; -#ifdef DEVFS - static void *devfs_token; -#endif } ; typedef struct ${1}_softc *sc_p; -static sc_p sca[N${UPPER}]; +devclass_t ${1}_devclass; + +static struct isa_pnp_id ${1}_ids[] = { + {0x12345678, "ABCco Widget"}, + {0xfedcba98, "shining moon Widget ripoff"}, + {0} +}; + +static device_method_t ${1}_methods[] = { + DEVMETHOD(device_probe, ${1}_isa_probe), + DEVMETHOD(device_attach, ${1}_isa_attach), + DEVMETHOD(device_detach, ${1}_isa_detach), + { 0, 0 } +}; + +static driver_t ${1}_isa_driver = { + "${1}", + ${1}_methods, + sizeof (struct ${1}_softc) +}; + +DRIVER_MODULE(${1}, isa, ${1}_isa_driver, ${1}_devclass, 0, 0); -/* add your own test to see if it exists */ -/* should return the number of ports needed */ + +/* + * The ISA code calls this for each device it knows about, + * whether via the PNP code or via the hints etc. + */ static int -${1}probe (struct isa_device *dev) +${1}_isa_probe (device_t device) { - char val; - int unit = dev->id_unit; - sc_p scp = sca[unit]; + int error; + sc_p scp = device_get_softc(device); + bus_space_handle_t bh; + bus_space_tag_t bt; + struct resource *port_res; + int rid = 0; + int size = 16; /* SIZE of port range used */ - /* - * Check the unit makes sense. - */ - if (unit > N${UPPER}) { - printf("bad unit (%d)\n", unit); - return (0); - } - if (scp) { - printf("unit %d already attached\n", unit); - return (0); - } - /* - * try see if the device is there. - */ - val = inb (dev->id_iobase); - if ( val != 42 ) { - return (0); - } + bzero(scp, sizeof(*scp)); + scp->device = device; /* - * ok, we got one we think - * do some further (this time possibly destructive) tests. + * Check for a PNP match.. + * There are several possible outcomes. + * error == 0 We match a PNP device (possibly several?). + * error == ENXIO, It is a PNP device but not ours. + * error == ENOENT, I is not a PNP device.. try heuristic probes. + * -- logic from if_ed_isa.c, added info from isa/isa_if.m: */ - outb (dev->id_iobase, 0xff); - DELAY (10000); /* 10 ms delay */ - val = inb (dev->id_iobase) & 0x0f; - return ((val & 0x0f) == 0x0f)? NUMPORTS : 0 ; + error = ISA_PNP_PROBE(device_get_parent(device), device, ${1}_ids); + switch (error) { + case 0: + /* + * We found a PNP device. + * Fall through into the code that just looks + * for a non PNP device as that should + * act as a good filter for bad stuff. + */ + case ENOENT: + /* + * Well it didn't show up in the PNP tables + * so look directly at known ports (if we have any) + * in case we are looking for an old pre-PNP card. + * + * The ports etc should come from a 'hints' section + * buried somewhere. XXX - still not figured out. + * which is read in by code in isa/isahint.c + */ + + port_res = bus_alloc_resource(device, SYS_RES_IOPORT, &rid, + 0ul, ~0ul, size, RF_ACTIVE); + if (port_res == NULL) { + error = ENXIO; + break; + } + + scp->port_rid = rid; + scp->port_res = port_res; + scp->bt = bt = rman_get_bustag(port_res); + scp->bh = bh = rman_get_bushandle(port_res); + + if ( ${UPPER}_INB(SOME_PORT) != EXPECTED_VALUE) { + /* + * It isn't what we expected, + * so release everything and quit looking for it. + */ + bus_release_resource(device, SYS_RES_IOPORT, + rid, port_res); + return (ENXIO); + } + error = 0; + break; + case ENXIO: + /* not ours, leave imediatly */ + default: + error = ENXIO; + } + return (error); } /* * Called if the probe succeeded. * We can be destructive here as we know we have the device. - * we can also trust the unit number. */ static int -${1}attach (struct isa_device *dev) +${1}_isa_attach (device_t device) { - int unit = dev->id_unit; - sc_p scp = sca[unit]; + int unit = device_get_unit(device); + sc_p scp = device_get_softc(device); - /* - * Attach our interrupt handler to the device struct. Our caller - * will attach it to the hardware soon after we return. - */ - dev->id_ointr = ${1}intr; + scp->dev = make_dev(&${1}_cdevsw, 0, 0, 0, 0600, "${1}%d", unit); + scp->dev->si_drv1 = scp; + return 0; +} - /* - * Allocate storage for this instance . - */ - scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT); - if( scp == NULL) { - printf("${1}%d failed to allocage driver strorage\n", unit); - return (0); - } - bzero(scp, sizeof(*scp)); - sca[unit] = scp; +static int +${1}_isa_detach (device_t device) +{ + sc_p scp = device_get_softc(device); - /* - * Store whatever seems wise. - */ - scp->dev = dev; -#if DEVFS - scp->devfs_token = devfs_add_devswf(&${1}_cdevsw, unit, DV_CHR, - UID_ROOT, GID_KMEM, 0600, "${1}%d", unit); -#endif - return 1; + bus_release_resource(device, SYS_RES_IOPORT, + scp->port_rid, scp->port_res); + destroy_dev(scp->dev); + return (0); } -/* - * Macro to check that the unit number is valid - * Often this isn't needed as once the open() is performed, - * the unit number is pretty much safe.. The exception would be if we - * implemented devices that could "go away". in which case all these routines - * would be wise to check the number, DIAGNOSTIC or not. - */ -#define CHECKUNIT(RETVAL) \ -do { /* the do-while is a safe way to do this grouping */ \ - if (unit > N${UPPER}) { \ - printf(__FUNCTION__ ":bad unit %d\n", unit); \ - return (RETVAL); \ - } \ - if (scp == NULL) { \ - printf( __FUNCTION__ ": unit %d not attached\n", unit);\ - return (RETVAL); \ - } \ -} while (0) -#ifdef DIAGNOSTIC -#define CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL) -#else /* DIAGNOSTIC */ -#define CHECKUNIT_DIAG(RETVAL) -#endif /* DIAGNOSTIC */ - static void -${1}intr(int unit) +${1}intr(void *arg) { - sc_p scp = sca[unit]; - + /*device_t dev = (device_t)arg;*/ + /* sc_p scp = device_get_softc(dev);*/ + /* * well we got an interupt, now what? - * Theoretically we don't need to check the unit. */ return; } -int ${1}ioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +static int +${1}ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { - int unit = UNIT (dev); - sc_p scp = sca[unit]; - - CHECKUNIT_DIAG(ENXIO); - + sc_p scp = ${UPPER}DEV2SOFTC(dev); + bus_space_handle_t bh = scp->bh; + bus_space_tag_t bt = scp->bt; + switch (cmd) { - case DHIOCRESET: - /* whatever resets it */ - outb(scp->dev->id_iobase, 0xff); + case DHIOCRESET: + /* whatever resets it */ + ${UPPER}_OUTB(SOME_PORT, 0xff) ; break; - default: + default: return ENXIO; } return (0); -} +} /* * You also need read, write, open, close routines. * This should get you started */ -static int +static int ${1}open(dev_t dev, int oflags, int devtype, struct proc *p) { - int unit = UNIT (dev); - sc_p scp = sca[unit]; - - CHECKUNIT(ENXIO); + sc_p scp = ${UPPER}DEV2SOFTC(dev); /* * Do processing @@ -272,13 +356,10 @@ ${1}open(dev_t dev, int oflags, int devtype, struct proc *p) return (0); } -static int +static int ${1}close(dev_t dev, int fflag, int devtype, struct proc *p) { - int unit = UNIT (dev); - sc_p scp = sca[unit]; - - CHECKUNIT_DIAG(ENXIO); + sc_p scp = ${UPPER}DEV2SOFTC(dev); /* * Do processing @@ -286,15 +367,12 @@ ${1}close(dev_t dev, int fflag, int devtype, struct proc *p) return (0); } -static int +static int ${1}read(dev_t dev, struct uio *uio, int ioflag) { - int unit = UNIT (dev); - sc_p scp = sca[unit]; - int toread; - - - CHECKUNIT_DIAG(ENXIO); + sc_p scp = ${UPPER}DEV2SOFTC(dev); + int toread; + /* * Do processing @@ -304,14 +382,11 @@ ${1}read(dev_t dev, struct uio *uio, int ioflag) return(uiomove(scp->buffer, toread, uio)); } -static int +static int ${1}write(dev_t dev, struct uio *uio, int ioflag) { - int unit = UNIT (dev); - sc_p scp = sca[unit]; + sc_p scp = ${UPPER}DEV2SOFTC(dev); int towrite; - - CHECKUNIT_DIAG(ENXIO); /* * Do processing @@ -321,13 +396,10 @@ ${1}write(dev_t dev, struct uio *uio, int ioflag) return(uiomove(scp->buffer, towrite, uio)); } -static int -${1}mmap(dev_t dev, int offset, int nprot) +static int +${1}mmap(dev_t dev, vm_offset_t offset, int nprot) { - int unit = UNIT (dev); - sc_p scp = sca[unit]; - - CHECKUNIT_DIAG(-1); + sc_p scp = ${UPPER}DEV2SOFTC(dev); /* * Do processing @@ -342,13 +414,10 @@ ${1}mmap(dev_t dev, int offset, int nprot) #endif } -static int +static int ${1}poll(dev_t dev, int which, struct proc *p) { - int unit = UNIT (dev); - sc_p scp = sca[unit]; - - CHECKUNIT_DIAG(ENXIO); + sc_p scp = ${UPPER}DEV2SOFTC(dev); /* * Do processing @@ -356,75 +425,9 @@ ${1}poll(dev_t dev, int which, struct proc *p) return (0); /* this is the wrong value I'm sure */ } -#ifndef ${UPPER}_MODULE - -/* - * Now for some driver initialisation. - * Occurs ONCE during boot (very early). - * This is if we are NOT a loadable module. - */ -static void -${1}_drvinit(void *unused) -{ - dev_t dev; - - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev, &${1}_cdevsw, NULL); -} - -SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR, - ${1}_drvinit, NULL) - -#else /* ${UPPER}_MODULE */ -/* Here is the support for if we ARE a loadable kernel module */ - -#include -#include -#include - -MOD_DEV (${1}, LM_DT_CHAR, CDEV_MAJOR, &${1}_cdevsw); - -static struct isa_device dev = {0, &${1}driver, BASE_IO, IRQ, DMA, (caddr_t) PHYS_IO, PHYS_IO_SIZE, INT_INT, 0, FLAGS, 0, 0, 0, 0, 1, 0, 0}; - -static int -${1}_load (struct lkm_table *lkmtp, int cmd) -{ - if (${1}probe (&dev)) { - ${1}attach (&dev); - uprintf ("${1} driver loaded\n"); - uprintf ("${1}: interrupts not hooked\n"); - return 0; - } else { - uprintf ("${1} driver: probe failed\n"); - return 1; - } -} - -static int -${1}_unload (struct lkm_table *lkmtp, int cmd) -{ - uprintf ("${1} driver unloaded\n"); - return 0; -} - -static int -${1}_stat (struct lkm_table *lkmtp, int cmd) -{ - return 0; -} - -int -${1}_mod (struct lkm_table *lkmtp, int cmd, int ver) -{ - MOD_DISPATCH(${1}, lkmtp, cmd, ver, - ${1}_load, ${1}_unload, ${1}_stat); -} - -#endif /* ${UPPER}_MODULE */ - DONE -cat >../../sys/${1}io.h <${TOP}/sys/${1}io.h <../../sys/${1}io.h </usr/src/lkm/${1}/Makefile <${TOP}/modules/${1}/Makefile < ${1}.h - -afterinstall: - \${INSTALL} -c -o \${BINOWN} -g \${BINGRP} -m \${BINMODE} \ - \${.CURDIR}/${1} \${DESTDIR}/usr/bin - +# $FreeBSD$ + +.PATH: \${.CURDIR}/../../dev/${1} +KMOD = ${1} +SRCS = ${1}.c +SRCS += opt_inet.h device_if.h bus_if.h pci_if.h isa_if.h + +# you may need to do this is your device is an if_xxx driver +opt_inet.h: + echo "#define INET 1" > opt_inet.h + .include DONE -fi + +(cd ${TOP}/modules/${1}; make depend; make ) +exit config ${UPPER} cd ../../compile/${UPPER} -- cgit v1.1