Date: Sat, 26 Sep 1998 02:22:59 -0400 From: "Christopher R. Bowman" <crb@ChrisBowman.com> To: hackers@FreeBSD.ORG Subject: suggestion for /usr/src/share/examples/drivers/make_pci_driver.sh Message-ID: <199809260750.CAA21981@quark.ChrisBowman.com>
next in thread | raw e-mail | index | archive | help
So, I noticed that there are scripts in /usr/src/share/examples/drivers that create some skeleton drivers but none for pci drivers so included below is my attempt at this. I would appreciate any feedback that anyone has to offer and comments about how to get this into the tree if it looks acceptable. #!/bin/sh # This writes a skeleton pci driver and puts it into the kernel tree for you # arg1 is lowercase "foo" # # Trust me, RUN THIS SCRIPT :) # #-------cut here------------------ cd /sys/pci 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} <<DONE i386/pci/${1}.c optional ${1} device-driver DONE cat >${UPPER} <<DONE # Configuration file for kernel type: ${UPPER} ident ${UPPER} # \$Id: make_device_driver.sh,v 1.0 Tue Aug 18 14:09:07 EST 1998 crb Exp $" DONE grep -v GENERIC < GENERIC >>${UPPER} cat >>${UPPER} <<DONE # trust me, you'll need this options DDB device ${1}0 DONE cat >../pci/${1}.c <<DONE /* * Copyright ME * * ${1} driver * \$Id: make_device_driver.sh,v 1.0 Tue Aug 18 14:09:07 EST 1998 crb Exp $" */ include "pci.h" #if NPCI >0 #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/malloc.h> /* malloc region definitions */ #include <machine/clock.h> /* DELAY() */ #include <pci.h> /* NCPI definitions */ #include <pci/pcivar.h> /* pci variables etc. */ #include <pci/pcireg.h> /* pci register definitions etc. */ #include <sys/${1}io.h> /* ${1} IOCTL definitions */ #ifdef DEVFS #include <sys/devfsext.h> /* DEVFS defintitions */ #endif /* DEVFS */ #define ${1}_DEV_PCI_ID X /* pci device id of your device */ /* 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(pcici_t tag, pcidi_t type); static int ${1}attach(pcici_t tag, int unit); static pci_inthand_t ${1}intr; static u_long ${1}count; #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 pci_device ${1}driver = { "${1}" ${1}probe, ${1}attach, &${1}count, NULL }; /* The DATA_SET macro includes the pci device in the set of pci devices * that will be probed at config time. */ DATA_SET (pcidevice_set, met_device); #define UNIT(dev) minor(dev) /* assume one minor number per unit */ /* * One of these per allocated device */ struct ${1}_softc { #ifdef DEVFS static void *devfs_token; #endif } ; typedef struct ${1}_softc *sc_p; static sc_p sca[N${UPPER}]; /* this function should discriminate if this device is * or is not handled by this driver, often this will be * as simple as testing the pci id of the device */ static int ${1}probe(pcici_t tag, pcidi_t type) { switch (type) { case ${1}_DEV_PCI_ID: return("${1}"); }; return ((char *)0); } /* * Called if the probe succeeded. */ static int ${1}attach(pcici_t tag, int unit) { 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 */ pci_inthand_t ${1}intr { /* * 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 initialization. There are basically 2 options * here you can either use the drvinit function for initialization that * needs to occur before any probing is done, or keep state in a global * you can use in the probe routine to see if probe is being called for * the fist time, and do your initalization there. */ 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) #endif /* NPCI */ DONE cat >../../sys/${1}io.h <<DONE /* * Definitions needed to access the ${1} device (ioctls etc) * see mtio.h , ioctl.h as examples */ #ifndef SYS_DHIO_H #define SYS_DHIO_H #ifndef KERNEL #include <sys/types.h> #endif #include <sys/ioccom.h> /* * 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.. # # -------- Christopher R. Bowman crb@ChrisBowman.com http://www.ChrisBowman.com/ To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199809260750.CAA21981>