summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2000-10-24 16:45:58 +0000
committerjulian <julian@FreeBSD.org>2000-10-24 16:45:58 +0000
commit91414848a3546de4630424632cbcf19ba357ee7d (patch)
tree91d6f36cd83631e29205a7a89818542cc254ea94
parenta98dcfa204fc59a4a4944347061647956fdcdac1 (diff)
downloadFreeBSD-src-91414848a3546de4630424632cbcf19ba357ee7d.zip
FreeBSD-src-91414848a3546de4630424632cbcf19ba357ee7d.tar.gz
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.
-rwxr-xr-xshare/examples/drivers/make_device_driver.sh565
1 files 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} <<DONE
-i386/isa/${1}.c optional ${1} device-driver
+#######################################################################
+#######################################################################
+#
+# Create configuration information needed to create a kernel
+# containing this driver.
+#
+# Not really needed if we are going to do this as a module.
+#######################################################################
+# First add the file to a local file list.
+#######################################################################
+
+cat >${TOP}/i386/conf/files.${UPPER} <<DONE
+i386/isa/${1}.c optional ${1} device-driver
DONE
-cat >${UPPER} <<DONE
+#######################################################################
+# Then create a configuration file for a kernel that contains this driver.
+#######################################################################
+cat >${TOP}/i386/conf/${UPPER} <<DONE
# Configuration file for kernel type: ${UPPER}
ident ${UPPER}
# \$FreeBSD$"
DONE
-grep -v GENERIC < GENERIC >>${UPPER}
+grep -v GENERIC < /sys/i386/conf/GENERIC >>${TOP}/i386/conf/${UPPER}
-cat >>${UPPER} <<DONE
-# trust me, you'll need this
-options DDB
-device ${1}0 at isa? port 0x234 bio irq 5
+cat >>${TOP}/i386/conf/${UPPER} <<DONE
+options DDB # trust me, you'll need this
+device ${1} at isa?
DONE
-cat >../isa/${1}.c <<DONE
+if [ ! -d ${TOP}/dev/${1} ]
+then
+ mkdir -p ${TOP}/dev/${1}
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+cat >${TOP}/dev/${1}/${1}.c <<DONE
/*
* Copyright ME
*
@@ -49,222 +105,250 @@ cat >../isa/${1}.c <<DONE
*/
-#include "${1}.h" /* generated file.. defines N${UPPER} */
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/kernel.h> /* SYSINIT stuff */
#include <sys/conf.h> /* cdevsw stuff */
+#include <sys/kernel.h> /* SYSINIT stuff */
+#include <sys/uio.h> /* SYSINIT stuff */
#include <sys/malloc.h> /* malloc region definitions */
-#include <machine/clock.h> /* DELAY() */
-#include <i386/isa/isa.h> /* ISA bus port definitions etc. */
-#include <i386/isa/isa_device.h>/* ISA bus configuration structures */
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+
+#include <isa/isavar.h>
+#include "isa_if.h"
#include <sys/${1}io.h> /* ${1} IOCTL definitions */
-#ifdef DEVFS
-#include <sys/devfsext.h> /* 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 <sys/exec.h>
-#include <sys/sysent.h>
-#include <sys/lkm.h>
-
-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 <<DONE
+cat >${TOP}/sys/${1}io.h <<DONE
/*
* Definitions needed to access the ${1} device (ioctls etc)
* see mtio.h , ioctl.h as examples
@@ -440,48 +443,34 @@ cat >../../sys/${1}io.h <<DONE
/*
* define an ioctl here
*/
-#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */
+#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */
#endif
DONE
-if [ -d /usr/src/lkm/${1} ]
+if [ ! -d ${TOP}/modules/${1} ]
then
- cat >/usr/src/lkm/${1}/Makefile <<DONE
+ mkdir -p ${TOP}/modules/${1}
+fi
+
+cat >${TOP}/modules/${1}/Makefile <<DONE
# ${UPPER} Loadable Kernel Module
#
-# This happens not to work, actually. It's written for
-# a character ISA device driver, but they cannot be
-# be made into lkm's, because you have to hard code
-# everything you'll otherwise enter into the kernel
-# configuration file.
-
-.PATH: \${.CURDIR}/../../sys/i386/isa
-KMOD = ${1}_mod
-SRCS = ${1}.c ${1}.h
-
-CFLAGS += -I. -D${UPPER}_MODULE
-CLEANFILES += ${1}.h
-
-BASE_IO=0 # Base IO address
-IRQ=0 # IRQ number
-DMA=-1 # DMA channel
-PHYS_IO=0 # Physical IO Memory base address
-PHYS_IO_SIZE=0 # Physical IO Memory size
-INT_INT=0 # Interrupt interface
-FLAGS=0 # Flags
-
-CFLAGS+= -DBASE_IO=\${BASE_IO} -DIRQ=\${IRQ} -DDMA=\${DMA} -DPHYS_IO=\${PHYS_IO} -DPHYS_IO_SIZE=\${PHYS_IO_SIZE} -DINT_INT=\${INT_INT} -DFLAGS=\${FLAGS}
-
-${1}.h:
- echo "#define N${UPPER} 1" > ${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 <bsd.kmod.mk>
DONE
-fi
+
+(cd ${TOP}/modules/${1}; make depend; make )
+exit
config ${UPPER}
cd ../../compile/${UPPER}
OpenPOWER on IntegriCloud