Bug 8139 - [patch] missing /usr/src/share/examples/drivers/make_pci_driver.sh
Summary: [patch] missing /usr/src/share/examples/drivers/make_pci_driver.sh
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: misc (show other bugs)
Version: 2.2.7-STABLE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 1998-10-04 01:30 UTC by crb
Modified: 2001-02-20 19:27 UTC (History)
0 users

See Also:


Attachments
make_pci_driver3.0.sh (9.50 KB, text/plain; charset="iso-8859-1")
1999-03-19 04:04 UTC, crb
no flags Details
file.dat (78 bytes, text/plain; charset="us-ascii")
1999-03-19 04:04 UTC, crb
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description crb 1998-10-04 01:30:00 UTC
We have scripts for making drivers for psudeo devices and isa drivers
but none for pci drivers.  The enclosed fix is my sugestion for such a
script

Fix: 

#!/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..
#
#
Comment 1 crb 1998-12-21 04:20:57 UTC
I believe that the version in pr misc/8139 was in bogus but I think this
one is better.

#!/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/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} <<DONE
pci/${1}.c      optional ${1} device-driver
DONE
cat >${UPPER} <<DONE
# Configuration file for kernel type: ${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}
sed "s/GENERIC/${UPPER}/" 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	char	       *${1}probe(pcici_t tag, pcidi_t type);
static	void		${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, ${1}driver);
#define BUFFERSIZE 1024
#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
        char    buffer[BUFFERSIZE];
	pcici_t     tag;            /* PCI tag, for doing PCI commands */
} ;
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 char *
${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 void
${1}attach(pcici_t tag, int 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;
	}
	bzero(scp, sizeof(*scp));
	sca[unit] = scp;
	/*
	 * Store whatever seems wise.
	 */
	scp->tag = tag;
#if DEVFS
    	scp->devfs_token = devfs_add_devswf(&${1}_cdevsw, unit, DV_CHR,
	    UID_ROOT, GID_KMEM, 0600, "${1}%d", unit);
#endif
	return;
}
/* 
 * 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(void *arg)
{
	
	/* 
	 * 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 */
		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 -g ${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/
Comment 2 crb 1999-03-19 04:04:37 UTC
attached find a new version suitable for 3.1 RELEASE 
Comment 3 Poul-Henning Kamp freebsd_committer freebsd_triage 2001-02-20 19:26:54 UTC
State Changed
From-To: open->closed

Overtaken by Events, sorry.