xref: /freebsd/share/examples/drivers/make_device_driver.sh (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1#!/bin/sh
2# This writes a skeleton driver and puts it into the kernel tree for you
3#arg1 is lowercase "foo"
4#
5# It also creates a directory under /usr/src/lkm to help you create
6#loadable kernel modules, though without much use except for development.
7#
8# Trust me, RUN THIS SCRIPT :)
9#
10#-------cut here------------------
11cd /sys/i386/conf
12
13if [ "${1}X" = "X" ]
14then
15	echo "Hey , how about some help here.. give me a device name!"
16	exit 1
17fi
18
19if [ -d /usr/src/lkm ]
20then
21	mkdir /usr/src/lkm/${1}
22fi
23
24UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"`
25cat >files.${UPPER} <<DONE
26i386/isa/${1}.c      optional ${1} device-driver
27DONE
28
29cat >${UPPER} <<DONE
30# Configuration file for kernel type: ${UPPER}
31ident	${UPPER}
32# \$FreeBSD$"
33DONE
34
35grep -v GENERIC < GENERIC >>${UPPER}
36
37cat >>${UPPER} <<DONE
38# trust me, you'll need this
39options	DDB		
40device ${1}0 at isa? port 0x234 bio irq 5
41DONE
42
43cat >../isa/${1}.c <<DONE
44/*
45 * Copyright ME
46 *
47 * ${1} driver
48 * \$FreeBSD$
49 */
50
51
52#include "${1}.h"		/* generated file.. defines N${UPPER} */
53#include <sys/param.h>
54#include <sys/systm.h>
55#include <sys/kernel.h>		/* SYSINIT stuff */
56#include <sys/conf.h>		/* cdevsw stuff */
57#include <sys/malloc.h>		/* malloc region definitions */
58#include <machine/clock.h>	/* DELAY() */
59#include <i386/isa/isa.h>	/* ISA bus port definitions etc. */
60#include <i386/isa/isa_device.h>/* ISA bus configuration structures */
61#include <sys/${1}io.h>		/* ${1} IOCTL definitions */
62#ifdef DEVFS
63#include <sys/devfsext.h>	/* DEVFS defintitions */
64#endif /* DEVFS */
65
66
67
68/* Function prototypes (these should all be static) */
69static  d_open_t	${1}open;
70static  d_close_t	${1}close;
71static  d_read_t	${1}read;
72static  d_write_t	${1}write;
73static  d_ioctl_t	${1}ioctl;
74static  d_mmap_t	${1}mmap;
75static  d_poll_t	${1}poll;
76static	int		${1}probe (struct isa_device *);
77static	int		${1}attach (struct isa_device *);
78#ifdef ${UPPER}_MODULE
79static	ointhand2_t	${1}intr; /* should actually have type inthand2_t */
80#endif
81 
82#define CDEV_MAJOR 20
83static struct cdevsw ${1}_cdevsw = {
84	${1}open,
85	${1}close,
86	${1}read,
87	${1}write,        
88	${1}ioctl,
89	nullstop,
90	nullreset,
91	nodevtotty, 
92	${1}poll,
93	${1}mmap,
94	NULL,
95	"${1}",
96	NULL,
97	-1 };
98 
99struct isa_driver ${1}driver = {
100	${1}probe,
101	${1}attach,
102	"${1}" };
103
104/* 
105 * device  specific Misc defines 
106 */
107#define BUFFERSIZE 1024
108#define NUMPORTS 4
109#define UNIT(dev) minor(dev)	/* assume one minor number per unit */
110
111/*
112 * One of these per allocated device
113 */
114struct ${1}_softc {
115	struct isa_device *dev;
116	char	buffer[BUFFERSIZE];
117#ifdef DEVFS
118	static void *devfs_token;
119#endif
120} ;
121
122typedef	struct ${1}_softc *sc_p;
123
124static sc_p sca[N${UPPER}];
125
126/* add your own test to see if it exists */
127/* should return the number of ports needed */
128static int
129${1}probe (struct isa_device *dev)
130{
131	char val;
132	int unit = dev->id_unit;
133	sc_p scp  = sca[unit];
134
135	/*
136	 * Check the unit makes sense.
137	 */
138	if (unit > N${UPPER}) {
139		printf("bad unit (%d)\n", unit);
140		return (0);
141	}
142	if (scp) {
143		printf("unit %d already attached\n", unit);
144		return (0);
145	}
146
147	/*
148	 * try see if the device is there.
149	 */
150	val = inb (dev->id_iobase);
151	if ( val != 42 ) {
152		return (0);
153	}
154
155	/*
156	 * ok, we got one we think 
157	 * do some further (this time possibly destructive) tests.
158	 */
159	outb (dev->id_iobase, 0xff);
160	DELAY (10000); /*  10 ms delay */
161	val = inb (dev->id_iobase) & 0x0f;
162	return ((val & 0x0f) == 0x0f)? NUMPORTS : 0 ;
163}
164
165/*
166 * Called if the probe succeeded.
167 * We can be destructive here as we know we have the device.
168 * we can also trust the unit number.
169 */
170static int
171${1}attach (struct isa_device *dev)
172{
173	int unit = dev->id_unit;
174	sc_p scp  = sca[unit];
175
176	/*
177	 * Attach our interrupt handler to the device struct.  Our caller
178	 * will attach it to the hardware soon after we return.
179	 */
180	dev->id_ointr = ${1}intr;
181
182	/* 
183	 * Allocate storage for this instance .
184	 */
185	scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT);
186	if( scp == NULL) {
187		printf("${1}%d failed to allocage driver strorage\n", unit);
188		return (0);
189	}
190	bzero(scp, sizeof(*scp));
191	sca[unit] = scp;
192
193	/*
194	 * Store whatever seems wise.
195	 */
196	scp->dev = dev;
197#if DEVFS
198    	scp->devfs_token = devfs_add_devswf(&${1}_cdevsw, unit, DV_CHR,
199	    UID_ROOT, GID_KMEM, 0600, "${1}%d", unit);
200#endif
201	return 1;
202}
203
204/* 
205 * Macro to check that the unit number is valid
206 * Often this isn't needed as once the open() is performed,
207 * the unit number is pretty much safe.. The exception would be if we
208 * implemented devices that could "go away". in which case all these routines
209 * would be wise to check the number, DIAGNOSTIC or not.
210 */
211#define CHECKUNIT(RETVAL)					\
212do { /* the do-while is a safe way to do this grouping */	\
213	if (unit > N${UPPER}) {					\
214		printf(__FUNCTION__ ":bad unit %d\n", unit);	\
215		return (RETVAL);				\
216	}							\
217	if (scp == NULL) { 					\
218		printf( __FUNCTION__ ": unit %d not attached\n", unit);\
219		return (RETVAL);				\
220	}							\
221} while (0)						
222#ifdef	DIAGNOSTIC
223#define	CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL)
224#else	/* DIAGNOSTIC */
225#define	CHECKUNIT_DIAG(RETVAL)
226#endif 	/* DIAGNOSTIC */
227
228static void
229${1}intr(int unit)
230{
231	sc_p scp  = sca[unit];
232	
233	/* 
234	 * well we got an interupt, now what?
235	 * Theoretically we don't need to check the unit.
236	 */
237	return;
238}
239
240int ${1}ioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
241{
242	int unit = UNIT (dev);
243	sc_p scp  = sca[unit];
244	
245	CHECKUNIT_DIAG(ENXIO);
246    
247	switch (cmd) {
248	    case DHIOCRESET:
249		/*  whatever resets it */
250		outb(scp->dev->id_iobase, 0xff);
251		break;
252	    default:
253		return ENXIO;
254	}
255	return (0);
256}   
257/*
258 * You also need read, write, open, close routines.
259 * This should get you started
260 */
261static  int
262${1}open(dev_t dev, int oflags, int devtype, struct proc *p)
263{
264	int unit = UNIT (dev);
265	sc_p scp  = sca[unit];
266	
267	CHECKUNIT(ENXIO);
268
269	/* 
270	 * Do processing
271	 */
272	return (0);
273}
274
275static  int
276${1}close(dev_t dev, int fflag, int devtype, struct proc *p)
277{
278	int unit = UNIT (dev);
279	sc_p scp  = sca[unit];
280	
281	CHECKUNIT_DIAG(ENXIO);
282
283	/* 
284	 * Do processing
285	 */
286	return (0);
287}
288
289static  int
290${1}read(dev_t dev, struct uio *uio, int ioflag)
291{
292	int unit = UNIT (dev);
293	sc_p scp  = sca[unit];
294	int     toread;
295	
296	
297	CHECKUNIT_DIAG(ENXIO);
298
299	/* 
300	 * Do processing
301	 * read from buffer
302	 */
303	toread = (min(uio->uio_resid, sizeof(scp->buffer)));
304	return(uiomove(scp->buffer, toread, uio));
305}
306
307static  int
308${1}write(dev_t dev, struct uio *uio, int ioflag)
309{
310	int unit = UNIT (dev);
311	sc_p scp  = sca[unit];
312	int	towrite;
313	
314	CHECKUNIT_DIAG(ENXIO);
315
316	/* 
317	 * Do processing
318	 * write to buffer
319	 */
320	towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
321	return(uiomove(scp->buffer, towrite, uio));
322}
323
324static  int
325${1}mmap(dev_t dev, int offset, int nprot)
326{
327	int unit = UNIT (dev);
328	sc_p scp  = sca[unit];
329	
330	CHECKUNIT_DIAG(-1);
331
332	/* 
333	 * Do processing
334	 */
335#if 0	/* if we had a frame buffer or whatever.. do this */
336	if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) {
337		return (-1);
338	}
339	return i386_btop((FRAMEBASE + offset));
340#else
341	return (-1);
342#endif
343}
344
345static  int
346${1}poll(dev_t dev, int which, struct proc *p)
347{
348	int unit = UNIT (dev);
349	sc_p scp  = sca[unit];
350	
351	CHECKUNIT_DIAG(ENXIO);
352
353	/* 
354	 * Do processing
355	 */
356	return (0); /* this is the wrong value I'm sure */
357}
358
359#ifndef ${UPPER}_MODULE
360
361/*
362 * Now  for some driver initialisation.
363 * Occurs ONCE during boot (very early).
364 * This is if we are NOT a loadable module.
365 */
366static void             
367${1}_drvinit(void *unused)
368{
369        dev_t dev;
370
371	dev = makedev(CDEV_MAJOR, 0);
372	cdevsw_add(&dev, &${1}_cdevsw, NULL);
373}
374
375SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
376		${1}_drvinit, NULL)
377
378#else  /* ${UPPER}_MODULE */
379/* Here is the support for if we ARE a loadable kernel module */
380
381#include <sys/exec.h>
382#include <sys/sysent.h>
383#include <sys/lkm.h>
384
385MOD_DEV (${1}, LM_DT_CHAR, CDEV_MAJOR, &${1}_cdevsw);
386
387static 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};
388
389static int
390${1}_load (struct lkm_table *lkmtp, int cmd)
391{
392	if (${1}probe (&dev)) {
393		${1}attach (&dev);
394		uprintf ("${1} driver loaded\n");
395		uprintf ("${1}: interrupts not hooked\n");
396		return 0;
397	} else {
398		uprintf ("${1} driver: probe failed\n");
399		return 1;
400	}
401}
402
403static int
404${1}_unload (struct lkm_table *lkmtp, int cmd)
405{
406	uprintf ("${1} driver unloaded\n");
407	return 0;
408}
409
410static int
411${1}_stat (struct lkm_table *lkmtp, int cmd)
412{
413	return 0;
414}
415
416int
417${1}_mod (struct lkm_table *lkmtp, int cmd, int ver)
418{
419	MOD_DISPATCH(${1}, lkmtp, cmd, ver,
420		${1}_load, ${1}_unload, ${1}_stat);
421}
422
423#endif /* ${UPPER}_MODULE */
424
425DONE
426
427cat >../../sys/${1}io.h <<DONE
428/*
429 * Definitions needed to access the ${1} device (ioctls etc)
430 * see mtio.h , ioctl.h as examples
431 */
432#ifndef SYS_DHIO_H
433#define SYS_DHIO_H
434
435#ifndef KERNEL
436#include <sys/types.h>
437#endif
438#include <sys/ioccom.h>
439
440/*
441 * define an ioctl here
442 */
443#define DHIOCRESET _IO('D', 0)   /* reset the ${1} device */
444#endif
445DONE
446
447if [ -d /usr/src/lkm/${1} ]
448then
449	cat >/usr/src/lkm/${1}/Makefile <<DONE
450#	${UPPER} Loadable Kernel Module
451#
452#	This happens not to work, actually. It's written for
453#	a character ISA device driver, but they cannot be
454#	be made into lkm's, because you have to hard code
455#	everything you'll otherwise enter into the kernel
456#	configuration file.
457
458.PATH:	\${.CURDIR}/../../sys/i386/isa
459KMOD	= ${1}_mod
460SRCS	= ${1}.c ${1}.h
461
462CFLAGS		+= -I. -D${UPPER}_MODULE
463CLEANFILES	+= ${1}.h
464
465BASE_IO=0		# Base IO address
466IRQ=0			# IRQ number
467DMA=-1			# DMA channel
468PHYS_IO=0		# Physical IO Memory base address
469PHYS_IO_SIZE=0		# Physical IO Memory size
470INT_INT=0		# Interrupt interface
471FLAGS=0			# Flags
472
473CFLAGS+= -DBASE_IO=\${BASE_IO} -DIRQ=\${IRQ} -DDMA=\${DMA} -DPHYS_IO=\${PHYS_IO} -DPHYS_IO_SIZE=\${PHYS_IO_SIZE} -DINT_INT=\${INT_INT} -DFLAGS=\${FLAGS}
474
475${1}.h:
476	echo "#define N${UPPER} 1" > ${1}.h
477
478afterinstall:
479	\${INSTALL} -c -o \${BINOWN} -g \${BINGRP} -m \${BINMODE} \
480	\${.CURDIR}/${1} \${DESTDIR}/usr/bin
481
482.include <bsd.kmod.mk>
483DONE
484fi
485
486config ${UPPER}
487cd ../../compile/${UPPER}
488make depend
489make ${1}.o
490make
491exit
492
493#--------------end of script---------------
494#
495#edit to your taste..
496#
497#
498
499
500
501
502