From bd62efe166e88da257281ff4cf38609fad2bcdcb Mon Sep 17 00:00:00 2001 From: julian Date: Sun, 2 Feb 1997 07:19:30 +0000 Subject: [PATCH] These two shell scripts will create a skeleton device driver. one for a real device and the other for a pseudo device. they each take one argument which is the name (prefix) for the driver. they add the new file to the /sys tree and add appropriate config files etc for a build. hopefully others will build on this so that we get 1/ these drivers improved and the shell scripts improved in how/where that hook the new code in. 2/ similar tools for providing skeletons for other modules (I'm tempted to do a VFS filesystem skeleton :) please take a look and fix anything that maybe should be added. they compile and link fine, but I think I wouldn't trust them, as faar as RUNNING yet :) (well they really wouldn't do very much being skeletons.. we need to add PCI and EISA skeletons as well followed by a SCSI driver skeleton. --- share/examples/drivers/make_device_driver.sh | 400 +++++++++++++++++++ share/examples/drivers/make_pseudo_driver.sh | 321 +++++++++++++++ 2 files changed, 721 insertions(+) create mode 100755 share/examples/drivers/make_device_driver.sh create mode 100644 share/examples/drivers/make_pseudo_driver.sh diff --git a/share/examples/drivers/make_device_driver.sh b/share/examples/drivers/make_device_driver.sh new file mode 100755 index 000000000000..e07338d33c4b --- /dev/null +++ b/share/examples/drivers/make_device_driver.sh @@ -0,0 +1,400 @@ +#!/bin/sh +# This writes a skeleton driver and puts it into the kernel tree for you +#arg1 is lowercase "foo" +# +# Trust me, RUN THIS SCRIPT :) +# +#-------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:]"` +cat >files.${UPPER} <${UPPER} <>${UPPER} + +cat >>${UPPER} <../isa/${1}.c < +#include +#include /* SYSINIT stuff */ +#include /* cdevsw stuff */ +#include /* malloc region definitions */ +#include /* DELAY() */ +#include /* ISA bus port definitions etc. */ +#include /* ISA bus configuration structures */ +#include /* ${1} IOCTL definitions */ +#ifdef DEVFS +#include /* DEVFS defintitions */ +#endif /* DEVFS */ + + + +/* Function prototypes (these should all be static except for ${1}intr()) */ +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_select_t ${1}select; +static int ${1}probe (struct isa_device *); +static int ${1}attach (struct isa_device *); +/* void ${1}intr(int unit);*//* actually defined in ioconf.h (generated file) */ + +#define CDEV_MAJOR 20 +static struct cdevsw ${1}_cdevsw = { + ${1}open, + ${1}close, + ${1}read, + ${1}write, + ${1}ioctl, + nullstop, + nullreset, + nodevtotty, + ${1}select, + ${1}mmap, + NULL, + "${1}", + NULL, + -1 }; + +struct isa_driver ${1}driver = { + ${1}probe, + ${1}attach, + "${1}" }; + +/* + * 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; + char buffer[BUFFERSIZE]; +#ifdef DEVFS + static void *devfs_token; +#endif +} ; + +typedef struct ${1}_softc *sc_p; + +static sc_p sca[N${UPPER}]; + +/* add your own test to see if it exists */ +/* should return the number of ports needed */ +static int +${1}probe (struct isa_device *dev) +{ + char val; + int unit = dev->id_unit; + sc_p scp = sca[unit]; + + /* + * 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); + } + + /* + * 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 ; +} + +/* + * 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) +{ + int unit = dev->id_unit; + sc_p scp = sca[unit]; + + /* + * 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; +} + +/* + * 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 */ + +void +${1}intr(int unit) +{ + sc_p scp = sca[unit]; + + /* + * 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) +{ + int unit = UNIT (dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(ENXIO); + + switch (cmd) { + case DHIOCRESET: + /* whatever resets it */ + outb(scp->dev->id_iobase, 0xff); + break; + default: + return ENXIO; + } + return (0); +} +/* + * You also need read, write, open, close routines. + * This should get you started + */ +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); + + /* + * Do processing + */ + return (0); +} + +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); + + /* + * Do processing + */ + return (0); +} + +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); + + /* + * Do processing + * read from buffer + */ + toread = (min(uio->uio_resid, sizeof(scp->buffer))); + return(uiomove(scp->buffer, toread, uio)); +} + +static int +${1}write(dev_t dev, struct uio *uio, int ioflag) +{ + int unit = UNIT (dev); + sc_p scp = sca[unit]; + int towrite; + + CHECKUNIT_DIAG(ENXIO); + + /* + * Do processing + * write to buffer + */ + towrite = (min(uio->uio_resid, sizeof(scp->buffer))); + return(uiomove(scp->buffer, towrite, uio)); +} + +static int +${1}mmap(dev_t dev, int offset, int nprot) +{ + int unit = UNIT (dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(-1); + + /* + * Do processing + */ +#if 0 /* if we had a frame buffer or whatever.. do this */ + if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) { + return (-1); + } + return i386_btop((FRAMEBASE + offset)); +#else + return (-1); +#endif +} + +static int +${1}select(dev_t dev, int which, struct proc *p) +{ + int unit = UNIT (dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(ENXIO); + + /* + * Do processing + */ + return (0); /* this is the wrong value I'm sure */ +} + +/* + * Now for some driver initialisation. + * Occurs ONCE during boot (very early). + */ +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) + + +DONE + +cat >../../sys/${1}io.h < +#endif +#include + +/* + * define an ioctl here + */ +#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */ +#endif +DONE + +config ${UPPER} +cd ../../compile/${UPPER} +make depend +make ${1}.o +make +exit + +#--------------end of script--------------- +# +#you also need to add an entry into the cdevsw[] +#array in conf.c, but it's too hard to do in a script.. +# +#edit to your taste.. +# +# + + + + diff --git a/share/examples/drivers/make_pseudo_driver.sh b/share/examples/drivers/make_pseudo_driver.sh new file mode 100644 index 000000000000..72f9fc2f5fef --- /dev/null +++ b/share/examples/drivers/make_pseudo_driver.sh @@ -0,0 +1,321 @@ +#!/bin/sh +# This writes a skeleton driver and puts it into the kernel tree for you +#arg1 is lowercase "foo" +# +# Trust me, RUN THIS SCRIPT :) +# +#-------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:]"` +cat >files.${UPPER} <${UPPER} <>${UPPER} + +cat >>${UPPER} <../../dev/${1}.c < +#include +#include /* SYSINIT stuff */ +#include /* cdevsw stuff */ +#include /* malloc region definitions */ +#include /* DELAY() */ +#include /* ${1} IOCTL definitions */ +#ifdef DEVFS +#include /* DEVFS defintitions */ +#endif /* DEVFS */ + + + +/* Function prototypes (these should all be static except for ${1}intr()) */ +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_select_t ${1}select; + +#define CDEV_MAJOR 20 +static struct cdevsw ${1}_cdevsw = { + ${1}open, + ${1}close, + ${1}read, + ${1}write, + ${1}ioctl, + nullstop, + nullreset, + nodevtotty, + ${1}select, + ${1}mmap, + NULL, + "${1}", + NULL, + -1 }; + +/* + * device specific Misc defines + */ +#define BUFFERSIZE 1024 +#define UNIT(dev) minor(dev) /* assume one minor number per unit */ + +/* + * One of these per allocated device + */ +struct ${1}_softc { + struct isa_device *dev; + char buffer[BUFFERSIZE]; +#ifdef DEVFS + static void *devfs_token; +#endif +} ; + +typedef struct ${1}_softc *sc_p; + +static sc_p sca[N${UPPER}]; + +/* + * 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 */ + +int ${1}ioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +{ + int unit = UNIT (dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(ENXIO); + + switch (cmd) { + case DHIOCRESET: + /* whatever resets it */ + outb(scp->dev->id_iobase, 0xff); + break; + default: + return ENXIO; + } + return (0); +} +/* + * You also need read, write, open, close routines. + * This should get you started + */ +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); + + /* + * Do processing + */ + return (0); +} + +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); + + /* + * Do processing + */ + return (0); +} + +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); + + /* + * Do processing + * read from buffer + */ + toread = (min(uio->uio_resid, sizeof(scp->buffer))); + return(uiomove(scp->buffer, toread, uio)); +} + +static int +${1}write(dev_t dev, struct uio *uio, int ioflag) +{ + int unit = UNIT (dev); + sc_p scp = sca[unit]; + int towrite; + + CHECKUNIT_DIAG(ENXIO); + + /* + * Do processing + * write to buffer + */ + towrite = (min(uio->uio_resid, sizeof(scp->buffer))); + return(uiomove(scp->buffer, towrite, uio)); +} + +static int +${1}mmap(dev_t dev, int offset, int nprot) +{ + int unit = UNIT (dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(-1); + + /* + * Do processing + */ +#if 0 /* if we had a frame buffer or whatever.. do this */ + if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) { + return (-1); + } + return i386_btop((FRAMEBASE + offset)); +#else + return (-1); +#endif +} + +static int +${1}select(dev_t dev, int which, struct proc *p) +{ + int unit = UNIT (dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(ENXIO); + + /* + * Do processing + */ + return (0); /* this is the wrong value I'm sure */ +} + +/* + * Now for some driver initialisation. + * Occurs ONCE during boot (very early). + */ +static void +${1}_drvinit(void *unused) +{ + dev_t dev; + int unit; + sc_p scp = sca[unit]; + + dev = makedev(CDEV_MAJOR, 0); + cdevsw_add(&dev, &${1}_cdevsw, NULL); + for (unit = 0; unit < N${UPPER}; unit++) { + /* + * Allocate storage for this instance . + */ + scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT); + if( scp == NULL) { + printf("${1}%d failed to allocate strorage\n", unit); + return ; + } + bzero(scp, sizeof(*scp)); + sca[unit] = scp; +#if DEVFS + scp->devfs_token = devfs_add_devswf(&${1}_cdevsw, unit, DV_CHR, + UID_ROOT, GID_KMEM, 0640, "${1}%d", unit); +#endif + } +} + +SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR, + ${1}_drvinit, NULL) + + +DONE + +cat >../../sys/${1}io.h < +#endif +#include + +/* + * define an ioctl here + */ +#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */ +#endif +DONE + +config ${UPPER} +cd ../../compile/${UPPER} +make depend +make ${1}.o +make +exit + +#--------------end of script--------------- +# +#you also need to add an entry into the cdevsw[] +#array in conf.c, but it's too hard to do in a script.. +# +#edit to your taste.. +# +# + +