1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-10-19 02:29:40 +00:00

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.
This commit is contained in:
Julian Elischer 2000-10-24 16:45:58 +00:00
parent 85e427cc94
commit 45b4f5af9e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=67505

View File

@ -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/${1}io.h> /* ${1} IOCTL definitions */
#ifdef DEVFS
#include <sys/devfsext.h> /* DEVFS defintitions */
#endif /* DEVFS */
#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 */
#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;
/* add your own test to see if it exists */
/* should return the number of ports needed */
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);
/*
* 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 */
bzero(scp, sizeof(*scp));
scp->device = device;
/*
* Check the unit makes sense.
* 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:
*/
if (unit > N${UPPER}) {
printf("bad unit (%d)\n", unit);
return (0);
}
if (scp) {
printf("unit %d already attached\n", unit);
return (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;
}
/*
* try see if the device is there.
*/
val = inb (dev->id_iobase);
if ( val != 42 ) {
return (0);
}
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);
/*
* ok, we got one we think
* do some further (this time possibly destructive) tests.
*/
outb (dev->id_iobase, 0xff);
DELAY (10000); /* 10 ms delay */
val = inb (dev->id_iobase) & 0x0f;
return ((val & 0x0f) == 0x0f)? NUMPORTS : 0 ;
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;
/*
* 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;
/*
* 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;
scp->dev = make_dev(&${1}_cdevsw, 0, 0, 0, 0600, "${1}%d", unit);
scp->dev->si_drv1 = scp;
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 int
${1}_isa_detach (device_t device)
{
sc_p scp = device_get_softc(device);
bus_release_resource(device, SYS_RES_IOPORT,
scp->port_rid, scp->port_res);
destroy_dev(scp->dev);
return (0);
}
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}