xref: /freebsd/share/examples/drivers/make_device_driver.sh (revision 5e176f9a979022d3ffbc477f4efb8868e3fae322)
15e176f9aSJulian Elischer#!/bin/sh
25e176f9aSJulian Elischer# This writes a skeleton driver and puts it into the kernel tree for you
35e176f9aSJulian Elischer#arg1 is lowercase "foo"
45e176f9aSJulian Elischer#
55e176f9aSJulian Elischer# Trust me, RUN THIS SCRIPT :)
65e176f9aSJulian Elischer#
75e176f9aSJulian Elischer#-------cut here------------------
85e176f9aSJulian Elischercd /sys/i386/conf
95e176f9aSJulian Elischer
105e176f9aSJulian Elischerif [ "${1}X" = "X" ]
115e176f9aSJulian Elischerthen
125e176f9aSJulian Elischer	echo "Hey , how about some help here.. give me a device name!"
135e176f9aSJulian Elischer	exit 1
145e176f9aSJulian Elischerfi
155e176f9aSJulian Elischer
165e176f9aSJulian ElischerUPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"`
175e176f9aSJulian Elischercat >files.${UPPER} <<DONE
185e176f9aSJulian Elischeri386/isa/${1}.c      optional ${1} device-driver
195e176f9aSJulian ElischerDONE
205e176f9aSJulian Elischer
215e176f9aSJulian Elischercat >${UPPER} <<DONE
225e176f9aSJulian Elischer# Configuration file for kernel type: ${UPPER}
235e176f9aSJulian Elischerident	${UPPER}
245e176f9aSJulian Elischer# \$Id:\$"
255e176f9aSJulian ElischerDONE
265e176f9aSJulian Elischer
275e176f9aSJulian Elischergrep -v GENERIC < GENERIC >>${UPPER}
285e176f9aSJulian Elischer
295e176f9aSJulian Elischercat >>${UPPER} <<DONE
305e176f9aSJulian Elischer# trust me, you'll need this
315e176f9aSJulian Elischeroptions	DDB		
325e176f9aSJulian Elischerdevice ${1}0 at isa? port 0x234 bio irq 5 vector ${1}intr
335e176f9aSJulian ElischerDONE
345e176f9aSJulian Elischer
355e176f9aSJulian Elischercat >../isa/${1}.c <<DONE
365e176f9aSJulian Elischer/*
375e176f9aSJulian Elischer * Copyright ME
385e176f9aSJulian Elischer *
395e176f9aSJulian Elischer * ${1} driver
405e176f9aSJulian Elischer * \$Id:\$
415e176f9aSJulian Elischer */
425e176f9aSJulian Elischer
435e176f9aSJulian Elischer
445e176f9aSJulian Elischer#include "${1}.h"		/* generated file.. defines N${UPPER} */
455e176f9aSJulian Elischer#include <sys/param.h>
465e176f9aSJulian Elischer#include <sys/systm.h>
475e176f9aSJulian Elischer#include <sys/kernel.h>		/* SYSINIT stuff */
485e176f9aSJulian Elischer#include <sys/conf.h>		/* cdevsw stuff */
495e176f9aSJulian Elischer#include <sys/malloc.h>		/* malloc region definitions */
505e176f9aSJulian Elischer#include <machine/clock.h>	/* DELAY() */
515e176f9aSJulian Elischer#include <i386/isa/isa.h>	/* ISA bus port definitions etc. */
525e176f9aSJulian Elischer#include <i386/isa/isa_device.h>/* ISA bus configuration structures */
535e176f9aSJulian Elischer#include <sys/${1}io.h>		/* ${1} IOCTL definitions */
545e176f9aSJulian Elischer#ifdef DEVFS
555e176f9aSJulian Elischer#include <sys/devfsext.h>	/* DEVFS defintitions */
565e176f9aSJulian Elischer#endif /* DEVFS */
575e176f9aSJulian Elischer
585e176f9aSJulian Elischer
595e176f9aSJulian Elischer
605e176f9aSJulian Elischer/* Function prototypes (these should all be static  except for ${1}intr()) */
615e176f9aSJulian Elischerstatic  d_open_t	${1}open;
625e176f9aSJulian Elischerstatic  d_close_t	${1}close;
635e176f9aSJulian Elischerstatic  d_read_t	${1}read;
645e176f9aSJulian Elischerstatic  d_write_t	${1}write;
655e176f9aSJulian Elischerstatic  d_ioctl_t	${1}ioctl;
665e176f9aSJulian Elischerstatic  d_mmap_t	${1}mmap;
675e176f9aSJulian Elischerstatic  d_select_t	${1}select;
685e176f9aSJulian Elischerstatic	int		${1}probe (struct isa_device *);
695e176f9aSJulian Elischerstatic	int		${1}attach (struct isa_device *);
705e176f9aSJulian Elischer/* void ${1}intr(int unit);*//* actually defined in ioconf.h (generated file) */
715e176f9aSJulian Elischer 
725e176f9aSJulian Elischer#define CDEV_MAJOR 20
735e176f9aSJulian Elischerstatic struct cdevsw ${1}_cdevsw = {
745e176f9aSJulian Elischer	${1}open,
755e176f9aSJulian Elischer	${1}close,
765e176f9aSJulian Elischer	${1}read,
775e176f9aSJulian Elischer	${1}write,        
785e176f9aSJulian Elischer	${1}ioctl,
795e176f9aSJulian Elischer	nullstop,
805e176f9aSJulian Elischer	nullreset,
815e176f9aSJulian Elischer	nodevtotty, 
825e176f9aSJulian Elischer	${1}select,
835e176f9aSJulian Elischer	${1}mmap,
845e176f9aSJulian Elischer	NULL,
855e176f9aSJulian Elischer	"${1}",
865e176f9aSJulian Elischer	NULL,
875e176f9aSJulian Elischer	-1 };
885e176f9aSJulian Elischer 
895e176f9aSJulian Elischerstruct isa_driver ${1}driver = {
905e176f9aSJulian Elischer	${1}probe,
915e176f9aSJulian Elischer	${1}attach,
925e176f9aSJulian Elischer	"${1}" };
935e176f9aSJulian Elischer
945e176f9aSJulian Elischer/* 
955e176f9aSJulian Elischer * device  specific Misc defines 
965e176f9aSJulian Elischer */
975e176f9aSJulian Elischer#define BUFFERSIZE 1024
985e176f9aSJulian Elischer#define NUMPORTS 4
995e176f9aSJulian Elischer#define UNIT(dev) minor(dev)	/* assume one minor number per unit */
1005e176f9aSJulian Elischer
1015e176f9aSJulian Elischer/*
1025e176f9aSJulian Elischer * One of these per allocated device
1035e176f9aSJulian Elischer */
1045e176f9aSJulian Elischerstruct ${1}_softc {
1055e176f9aSJulian Elischer	struct isa_device *dev;
1065e176f9aSJulian Elischer	char	buffer[BUFFERSIZE];
1075e176f9aSJulian Elischer#ifdef DEVFS
1085e176f9aSJulian Elischer	static void *devfs_token;
1095e176f9aSJulian Elischer#endif
1105e176f9aSJulian Elischer} ;
1115e176f9aSJulian Elischer
1125e176f9aSJulian Elischertypedef	struct ${1}_softc *sc_p;
1135e176f9aSJulian Elischer
1145e176f9aSJulian Elischerstatic sc_p sca[N${UPPER}];
1155e176f9aSJulian Elischer
1165e176f9aSJulian Elischer/* add your own test to see if it exists */
1175e176f9aSJulian Elischer/* should return the number of ports needed */
1185e176f9aSJulian Elischerstatic int
1195e176f9aSJulian Elischer${1}probe (struct isa_device *dev)
1205e176f9aSJulian Elischer{
1215e176f9aSJulian Elischer	char val;
1225e176f9aSJulian Elischer	int unit = dev->id_unit;
1235e176f9aSJulian Elischer	sc_p scp  = sca[unit];
1245e176f9aSJulian Elischer
1255e176f9aSJulian Elischer	/*
1265e176f9aSJulian Elischer	 * Check the unit makes sense.
1275e176f9aSJulian Elischer	 */
1285e176f9aSJulian Elischer	if (unit > N${UPPER}) {
1295e176f9aSJulian Elischer		printf("bad unit (%d)\n", unit);
1305e176f9aSJulian Elischer		return (0);
1315e176f9aSJulian Elischer	}
1325e176f9aSJulian Elischer	if (scp) {
1335e176f9aSJulian Elischer		printf("unit $d already attached\n", unit);
1345e176f9aSJulian Elischer		return (0);
1355e176f9aSJulian Elischer	}
1365e176f9aSJulian Elischer
1375e176f9aSJulian Elischer	/*
1385e176f9aSJulian Elischer	 * try see if the device is there.
1395e176f9aSJulian Elischer	 */
1405e176f9aSJulian Elischer	val = inb (dev->id_iobase);
1415e176f9aSJulian Elischer	if ( val != 42 ) {
1425e176f9aSJulian Elischer		return (0);
1435e176f9aSJulian Elischer	}
1445e176f9aSJulian Elischer
1455e176f9aSJulian Elischer	/*
1465e176f9aSJulian Elischer	 * ok, we got one we think 
1475e176f9aSJulian Elischer	 * do some further (this time possibly destructive) tests.
1485e176f9aSJulian Elischer	 */
1495e176f9aSJulian Elischer	outb (dev->id_iobase, 0xff);
1505e176f9aSJulian Elischer	DELAY (10000); /*  10 ms delay */
1515e176f9aSJulian Elischer	val = inb (dev->id_iobase) & 0x0f;
1525e176f9aSJulian Elischer	return ((val & 0x0f) == 0x0f)? NUMPORTS : 0 ;
1535e176f9aSJulian Elischer}
1545e176f9aSJulian Elischer
1555e176f9aSJulian Elischer/*
1565e176f9aSJulian Elischer * Called if the probe succeeded.
1575e176f9aSJulian Elischer * We can be destructive here as we know we have the device.
1585e176f9aSJulian Elischer * we can also trust the unit number.
1595e176f9aSJulian Elischer */
1605e176f9aSJulian Elischerstatic int
1615e176f9aSJulian Elischer${1}attach (struct isa_device *dev)
1625e176f9aSJulian Elischer{
1635e176f9aSJulian Elischer	int unit = dev->id_unit;
1645e176f9aSJulian Elischer	sc_p scp  = sca[unit];
1655e176f9aSJulian Elischer	
1665e176f9aSJulian Elischer	/* 
1675e176f9aSJulian Elischer	 * Allocate storage for this instance .
1685e176f9aSJulian Elischer	 */
1695e176f9aSJulian Elischer	scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT);
1705e176f9aSJulian Elischer	if( scp == NULL) {
1715e176f9aSJulian Elischer		printf("${1}%d failed to allocage driver strorage\n", unit);
1725e176f9aSJulian Elischer		return (0);
1735e176f9aSJulian Elischer	}
1745e176f9aSJulian Elischer	bzero(scp, sizeof(*scp));
1755e176f9aSJulian Elischer	sca[unit] = scp;
1765e176f9aSJulian Elischer
1775e176f9aSJulian Elischer	/*
1785e176f9aSJulian Elischer	 * Store whatever seems wise.
1795e176f9aSJulian Elischer	 */
1805e176f9aSJulian Elischer	scp->dev = dev;
1815e176f9aSJulian Elischer#if DEVFS
1825e176f9aSJulian Elischer    	scp->devfs_token = devfs_add_devswf(&${1}_cdevsw, unit, DV_CHR,
1835e176f9aSJulian Elischer	    UID_ROOT, GID_KMEM, 0600, "${1}%d", unit);
1845e176f9aSJulian Elischer#endif
1855e176f9aSJulian Elischer	return 1;
1865e176f9aSJulian Elischer}
1875e176f9aSJulian Elischer
1885e176f9aSJulian Elischer/* 
1895e176f9aSJulian Elischer * Macro to check that the unit number is valid
1905e176f9aSJulian Elischer * Often this isn't needed as once the open() is performed,
1915e176f9aSJulian Elischer * the unit number is pretty much safe.. The exception would be if we
1925e176f9aSJulian Elischer * implemented devices that could "go away". in which case all these routines
1935e176f9aSJulian Elischer * would be wise to check the number, DIAGNOSTIC or not.
1945e176f9aSJulian Elischer */
1955e176f9aSJulian Elischer#define CHECKUNIT(RETVAL)					\
1965e176f9aSJulian Elischerdo { /* the do-while is a safe way to do this grouping */	\
1975e176f9aSJulian Elischer	if (unit > N${UPPER}) {					\
1985e176f9aSJulian Elischer		printf(__FUNCTION__ ":bad unit $d\n", unit);	\
1995e176f9aSJulian Elischer		return (RETVAL);				\
2005e176f9aSJulian Elischer	}							\
2015e176f9aSJulian Elischer	if (scp == NULL) { 					\
2025e176f9aSJulian Elischer		printf( __FUNCTION__ ": unit $d not attached\n", unit);\
2035e176f9aSJulian Elischer		return (RETVAL);				\
2045e176f9aSJulian Elischer	}							\
2055e176f9aSJulian Elischer} while (0)						
2065e176f9aSJulian Elischer#ifdef	DIAGNOSTIC
2075e176f9aSJulian Elischer#define	CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL)
2085e176f9aSJulian Elischer#else	/* DIAGNOSTIC */
2095e176f9aSJulian Elischer#define	CHECKUNIT_DIAG(RETVAL)
2105e176f9aSJulian Elischer#endif 	/* DIAGNOSTIC */
2115e176f9aSJulian Elischer
2125e176f9aSJulian Elischervoid
2135e176f9aSJulian Elischer${1}intr(int unit)
2145e176f9aSJulian Elischer{
2155e176f9aSJulian Elischer	sc_p scp  = sca[unit];
2165e176f9aSJulian Elischer	
2175e176f9aSJulian Elischer	/* 
2185e176f9aSJulian Elischer	 * well we got an interupt, now what?
2195e176f9aSJulian Elischer	 * Theoretically we don't need to check the unit.
2205e176f9aSJulian Elischer	 */
2215e176f9aSJulian Elischer	return;
2225e176f9aSJulian Elischer}
2235e176f9aSJulian Elischer
2245e176f9aSJulian Elischerint ${1}ioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
2255e176f9aSJulian Elischer{
2265e176f9aSJulian Elischer	int unit = UNIT (dev);
2275e176f9aSJulian Elischer	sc_p scp  = sca[unit];
2285e176f9aSJulian Elischer	
2295e176f9aSJulian Elischer	CHECKUNIT_DIAG(ENXIO);
2305e176f9aSJulian Elischer    
2315e176f9aSJulian Elischer	switch (cmd) {
2325e176f9aSJulian Elischer	    case DHIOCRESET:
2335e176f9aSJulian Elischer		/*  whatever resets it */
2345e176f9aSJulian Elischer		outb(scp->dev->id_iobase, 0xff);
2355e176f9aSJulian Elischer		break;
2365e176f9aSJulian Elischer	    default:
2375e176f9aSJulian Elischer		return ENXIO;
2385e176f9aSJulian Elischer	}
2395e176f9aSJulian Elischer	return (0);
2405e176f9aSJulian Elischer}   
2415e176f9aSJulian Elischer/*
2425e176f9aSJulian Elischer * You also need read, write, open, close routines.
2435e176f9aSJulian Elischer * This should get you started
2445e176f9aSJulian Elischer */
2455e176f9aSJulian Elischerstatic  int
2465e176f9aSJulian Elischer${1}open(dev_t dev, int oflags, int devtype, struct proc *p)
2475e176f9aSJulian Elischer{
2485e176f9aSJulian Elischer	int unit = UNIT (dev);
2495e176f9aSJulian Elischer	sc_p scp  = sca[unit];
2505e176f9aSJulian Elischer	
2515e176f9aSJulian Elischer	CHECKUNIT(ENXIO);
2525e176f9aSJulian Elischer
2535e176f9aSJulian Elischer	/* 
2545e176f9aSJulian Elischer	 * Do processing
2555e176f9aSJulian Elischer	 */
2565e176f9aSJulian Elischer	return (0);
2575e176f9aSJulian Elischer}
2585e176f9aSJulian Elischer
2595e176f9aSJulian Elischerstatic  int
2605e176f9aSJulian Elischer${1}close(dev_t dev, int fflag, int devtype, struct proc *p)
2615e176f9aSJulian Elischer{
2625e176f9aSJulian Elischer	int unit = UNIT (dev);
2635e176f9aSJulian Elischer	sc_p scp  = sca[unit];
2645e176f9aSJulian Elischer	
2655e176f9aSJulian Elischer	CHECKUNIT_DIAG(ENXIO);
2665e176f9aSJulian Elischer
2675e176f9aSJulian Elischer	/* 
2685e176f9aSJulian Elischer	 * Do processing
2695e176f9aSJulian Elischer	 */
2705e176f9aSJulian Elischer	return (0);
2715e176f9aSJulian Elischer}
2725e176f9aSJulian Elischer
2735e176f9aSJulian Elischerstatic  int
2745e176f9aSJulian Elischer${1}read(dev_t dev, struct uio *uio, int ioflag)
2755e176f9aSJulian Elischer{
2765e176f9aSJulian Elischer	int unit = UNIT (dev);
2775e176f9aSJulian Elischer	sc_p scp  = sca[unit];
2785e176f9aSJulian Elischer	int     toread;
2795e176f9aSJulian Elischer	
2805e176f9aSJulian Elischer	
2815e176f9aSJulian Elischer	CHECKUNIT_DIAG(ENXIO);
2825e176f9aSJulian Elischer
2835e176f9aSJulian Elischer	/* 
2845e176f9aSJulian Elischer	 * Do processing
2855e176f9aSJulian Elischer	 * read from buffer
2865e176f9aSJulian Elischer	 */
2875e176f9aSJulian Elischer	toread = (min(uio->uio_resid, sizeof(scp->buffer)));
2885e176f9aSJulian Elischer	return(uiomove(scp->buffer, toread, uio));
2895e176f9aSJulian Elischer}
2905e176f9aSJulian Elischer
2915e176f9aSJulian Elischerstatic  int
2925e176f9aSJulian Elischer${1}write(dev_t dev, struct uio *uio, int ioflag)
2935e176f9aSJulian Elischer{
2945e176f9aSJulian Elischer	int unit = UNIT (dev);
2955e176f9aSJulian Elischer	sc_p scp  = sca[unit];
2965e176f9aSJulian Elischer	int	towrite;
2975e176f9aSJulian Elischer	
2985e176f9aSJulian Elischer	CHECKUNIT_DIAG(ENXIO);
2995e176f9aSJulian Elischer
3005e176f9aSJulian Elischer	/* 
3015e176f9aSJulian Elischer	 * Do processing
3025e176f9aSJulian Elischer	 * write to buffer
3035e176f9aSJulian Elischer	 */
3045e176f9aSJulian Elischer	towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
3055e176f9aSJulian Elischer	return(uiomove(scp->buffer, towrite, uio));
3065e176f9aSJulian Elischer}
3075e176f9aSJulian Elischer
3085e176f9aSJulian Elischerstatic  int
3095e176f9aSJulian Elischer${1}mmap(dev_t dev, int offset, int nprot)
3105e176f9aSJulian Elischer{
3115e176f9aSJulian Elischer	int unit = UNIT (dev);
3125e176f9aSJulian Elischer	sc_p scp  = sca[unit];
3135e176f9aSJulian Elischer	
3145e176f9aSJulian Elischer	CHECKUNIT_DIAG(-1);
3155e176f9aSJulian Elischer
3165e176f9aSJulian Elischer	/* 
3175e176f9aSJulian Elischer	 * Do processing
3185e176f9aSJulian Elischer	 */
3195e176f9aSJulian Elischer#if 0	/* if we had a frame buffer or whatever.. do this */
3205e176f9aSJulian Elischer	if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) {
3215e176f9aSJulian Elischer		return (-1);
3225e176f9aSJulian Elischer	}
3235e176f9aSJulian Elischer	return i386_btop((FRAMEBASE + offset));
3245e176f9aSJulian Elischer#else
3255e176f9aSJulian Elischer	return (-1);
3265e176f9aSJulian Elischer#endif
3275e176f9aSJulian Elischer}
3285e176f9aSJulian Elischer
3295e176f9aSJulian Elischerstatic  int
3305e176f9aSJulian Elischer${1}select(dev_t dev, int which, struct proc *p)
3315e176f9aSJulian Elischer{
3325e176f9aSJulian Elischer	int unit = UNIT (dev);
3335e176f9aSJulian Elischer	sc_p scp  = sca[unit];
3345e176f9aSJulian Elischer	
3355e176f9aSJulian Elischer	CHECKUNIT_DIAG(ENXIO);
3365e176f9aSJulian Elischer
3375e176f9aSJulian Elischer	/* 
3385e176f9aSJulian Elischer	 * Do processing
3395e176f9aSJulian Elischer	 */
3405e176f9aSJulian Elischer	return (0); /* this is the wrong value I'm sure */
3415e176f9aSJulian Elischer}
3425e176f9aSJulian Elischer
3435e176f9aSJulian Elischer/*
3445e176f9aSJulian Elischer * Now  for some driver initialisation.
3455e176f9aSJulian Elischer * Occurs ONCE during boot (very early).
3465e176f9aSJulian Elischer */
3475e176f9aSJulian Elischerstatic void             
3485e176f9aSJulian Elischer${1}_drvinit(void *unused)
3495e176f9aSJulian Elischer{
3505e176f9aSJulian Elischer        dev_t dev;
3515e176f9aSJulian Elischer
3525e176f9aSJulian Elischer	dev = makedev(CDEV_MAJOR, 0);
3535e176f9aSJulian Elischer	cdevsw_add(&dev, &${1}_cdevsw, NULL);
3545e176f9aSJulian Elischer}
3555e176f9aSJulian Elischer
3565e176f9aSJulian ElischerSYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
3575e176f9aSJulian Elischer		${1}_drvinit, NULL)
3585e176f9aSJulian Elischer
3595e176f9aSJulian Elischer
3605e176f9aSJulian ElischerDONE
3615e176f9aSJulian Elischer
3625e176f9aSJulian Elischercat >../../sys/${1}io.h <<DONE
3635e176f9aSJulian Elischer/*
3645e176f9aSJulian Elischer * Definitions needed to access the ${1} device (ioctls etc)
3655e176f9aSJulian Elischer * see mtio.h , ioctl.h as examples
3665e176f9aSJulian Elischer */
3675e176f9aSJulian Elischer#ifndef SYS_DHIO_H
3685e176f9aSJulian Elischer#define SYS_DHIO_H
3695e176f9aSJulian Elischer
3705e176f9aSJulian Elischer#ifndef KERNEL
3715e176f9aSJulian Elischer#include <sys/types.h>
3725e176f9aSJulian Elischer#endif
3735e176f9aSJulian Elischer#include <sys/ioccom.h>
3745e176f9aSJulian Elischer
3755e176f9aSJulian Elischer/*
3765e176f9aSJulian Elischer * define an ioctl here
3775e176f9aSJulian Elischer */
3785e176f9aSJulian Elischer#define DHIOCRESET _IO('D', 0)   /* reset the ${1} device */
3795e176f9aSJulian Elischer#endif
3805e176f9aSJulian ElischerDONE
3815e176f9aSJulian Elischer
3825e176f9aSJulian Elischerconfig ${UPPER}
3835e176f9aSJulian Elischercd ../../compile/${UPPER}
3845e176f9aSJulian Elischermake depend
3855e176f9aSJulian Elischermake ${1}.o
3865e176f9aSJulian Elischermake
3875e176f9aSJulian Elischerexit
3885e176f9aSJulian Elischer
3895e176f9aSJulian Elischer#--------------end of script---------------
3905e176f9aSJulian Elischer#
3915e176f9aSJulian Elischer#you also need to add an entry into the cdevsw[]
3925e176f9aSJulian Elischer#array in conf.c, but it's too hard to do in a script..
3935e176f9aSJulian Elischer#
3945e176f9aSJulian Elischer#edit to your taste..
3955e176f9aSJulian Elischer#
3965e176f9aSJulian Elischer#
3975e176f9aSJulian Elischer
3985e176f9aSJulian Elischer
3995e176f9aSJulian Elischer
4005e176f9aSJulian Elischer
401