xref: /freebsd/share/examples/drivers/make_pseudo_driver.sh (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1#!/bin/sh
2# This writes a skeleton driver and puts it into the kernel tree for you
3#
4# arg1 is lowercase "foo"
5# arg2 path to the kernel sources, "/sys" if omitted
6#
7# Trust me, RUN THIS SCRIPT :)
8#
9#
10#-------cut here------------------
11
12if [ "${1}X" = "X" ]
13then
14	echo "Hey , how about some help here.. give me a device name!"
15	exit 1
16fi
17if [ "X${2}" = "X" ]; then
18	TOP=`cd /sys; pwd -P`
19	echo "Using ${TOP} as the path to the kernel sources!"
20else
21	TOP=${2}
22fi
23
24for i in "" "conf" "i386" "i386/conf" "dev" "sys" "modules"
25do
26	if [ -d ${TOP}/${i} ]
27	then
28		continue
29	fi
30	echo "${TOP}/${i}: no such directory."
31	echo "Please, correct the error and try again."
32	exit 1
33done
34
35UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"`
36
37if [ -d ${TOP}/modules/${1} ]; then
38	echo "There appears to already be a module called ${1}"
39	echo -n "Should it be overwritten? [Y]"
40	read VAL
41	if [ "-z" "$VAL" ]; then
42		VAL=YES
43	fi
44	case ${VAL} in
45	[yY]*)
46		echo "Cleaning up from prior runs"
47		rm -rf ${TOP}/dev/${1}
48		rm -rf ${TOP}/modules/${1}
49		rm ${TOP}/conf/files.${UPPER}
50		rm ${TOP}/i386/conf/${UPPER}
51		rm ${TOP}/sys/${1}io.h
52		;;
53	*)
54		exit 1
55		;;
56	esac
57fi
58
59echo "The following files will be created:"
60echo ${TOP}/modules/${1}
61echo ${TOP}/conf/files.${UPPER}
62echo ${TOP}/i386/conf/${UPPER}
63echo ${TOP}/dev/${1}
64echo ${TOP}/dev/${1}/${1}.c
65echo ${TOP}/sys/${1}io.h
66echo ${TOP}/modules/${1}
67echo ${TOP}/modules/${1}/Makefile
68
69mkdir ${TOP}/modules/${1}
70
71cat >${TOP}/conf/files.${UPPER} <<DONE
72dev/${1}/${1}.c      optional ${1}
73DONE
74
75cat >${TOP}/i386/conf/${UPPER} <<DONE
76# Configuration file for kernel type: ${UPPER}
77# \$FreeBSD\$
78
79files		"${TOP}/conf/files.${UPPER}"
80
81include		GENERIC
82
83ident		${UPPER}
84
85# trust me, you'll need this
86options		KDB
87options		DDB
88device		${1}
89DONE
90
91if [ ! -d ${TOP}/dev/${1} ]; then
92	mkdir -p ${TOP}/dev/${1}
93fi
94
95cat >${TOP}/dev/${1}/${1}.c <<DONE
96/*
97 * Copyright (c) [year] [your name]
98 *
99 * Redistribution and use in source and binary forms, with or without
100 * modification, are permitted provided that the following conditions
101 * are met:
102 * 1. Redistributions of source code must retain the above copyright
103 *    notice, this list of conditions and the following disclaimer.
104 * 2. Redistributions in binary form must reproduce the above copyright
105 *    notice, this list of conditions and the following disclaimer in the
106 *    documentation and/or other materials provided with the distribution.
107 *
108 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
109 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
110 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
111 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
112 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
113 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
114 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
115 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
116 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
117 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
118 * SUCH DAMAGE.
119 *
120 * ${1} driver
121 */
122
123#include <sys/cdefs.h>
124__FBSDID("\$FreeBSD\$");
125
126#include <sys/param.h>
127#include <sys/systm.h>
128#include <sys/kernel.h>		/* SYSINIT stuff */
129#include <sys/uio.h>		/* SYSINIT stuff */
130#include <sys/conf.h>		/* cdevsw stuff */
131#include <sys/malloc.h>		/* malloc region definitions */
132#include <sys/proc.h>
133#include <sys/${1}io.h>		/* ${1} IOCTL definitions */
134
135#include <machine/clock.h>	/* DELAY() */
136
137#define N${UPPER}	3	/* defines number of instances */
138
139/* XXX These should be defined in terms of bus-space ops. */
140#define ${UPPER}_INB(port) inb(port)
141#define ${UPPER}_OUTB(port, val) (port, (val))
142
143/* Function prototypes (these should all be static) */
144static  d_open_t	${1}open;
145static  d_close_t	${1}close;
146static  d_read_t	${1}read;
147static  d_write_t	${1}write;
148static  d_ioctl_t	${1}ioctl;
149static  d_mmap_t	${1}mmap;
150static  d_poll_t	${1}poll;
151
152#define CDEV_MAJOR 20
153static struct cdevsw ${1}_cdevsw = {
154	.d_version =	D_VERSION,
155	.d_open =	${1}open,
156	.d_close =	${1}close,
157	.d_read =	${1}read,
158	.d_write =	${1}write,
159	.d_ioctl =	${1}ioctl,
160	.d_poll =	${1}poll,
161	.d_mmap =	${1}mmap,
162	.d_name =	"${1}",
163};
164
165/*
166 * device  specific Misc defines
167 */
168#define BUFFERSIZE 1024
169#define UNIT(dev) dev2unit(dev)	/* assume one minor number per unit */
170
171/*
172 * One of these per allocated device
173 */
174struct ${1}_softc {
175	u_long	iobase;
176	char	buffer[BUFFERSIZE];
177  	struct cdev *dev;
178};
179
180typedef	struct ${1}_softc *sc_p;
181
182static sc_p sca[N${UPPER}];
183
184/*
185 * Macro to check that the unit number is valid
186 * Often this isn't needed as once the open() is performed,
187 * the unit number is pretty much safe.. The exception would be if we
188 * implemented devices that could "go away". in which case all these routines
189 * would be wise to check the number, DIAGNOSTIC or not.
190 */
191#define CHECKUNIT(RETVAL)						\
192do { /* the do-while is a safe way to do this grouping */		\
193	if (unit > N${UPPER}) {						\
194		printf("%s: bad unit %d\n", __func__, unit);		\
195		return (RETVAL);					\
196	}								\
197	if (scp == NULL) { 						\
198		printf("%s: unit %d not attached\n", __func__, unit);	\
199		return (RETVAL);					\
200	}								\
201} while (0)
202
203#ifdef	DIAGNOSTIC
204#define	CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL)
205#else	/* DIAGNOSTIC */
206#define	CHECKUNIT_DIAG(RETVAL)
207#endif 	/* DIAGNOSTIC */
208
209static int
210${1}ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
211{
212	int unit = UNIT(dev);
213	sc_p scp  = sca[unit];
214
215	CHECKUNIT_DIAG(ENXIO);
216
217	switch (cmd) {
218	    case DHIOCRESET:
219		/*  whatever resets it */
220		(void)scp; /* Delete this line after using scp. */
221#if 0
222		${UPPER}_OUTB(scp->iobase, 0xff);
223#endif
224		break;
225	    default:
226		return ENXIO;
227	}
228	return (0);
229}
230
231/*
232 * You also need read, write, open, close routines.
233 * This should get you started
234 */
235static int
236${1}open(struct cdev *dev, int oflags, int devtype, struct thread *td)
237{
238	int unit = UNIT(dev);
239	sc_p scp  = sca[unit];
240
241	CHECKUNIT(ENXIO);
242
243	(void)scp; /* Delete this line after using scp. */
244	/*
245	 * Do processing
246	 */
247	return (0);
248}
249
250static int
251${1}close(struct cdev *dev, int fflag, int devtype, struct thread *td)
252{
253	int unit = UNIT(dev);
254	sc_p scp  = sca[unit];
255
256	CHECKUNIT_DIAG(ENXIO);
257
258	(void)scp; /* Delete this line after using scp. */
259	/*
260	 * Do processing
261	 */
262	return (0);
263}
264
265static int
266${1}read(struct cdev *dev, struct uio *uio, int ioflag)
267{
268	int unit = UNIT(dev);
269	sc_p scp  = sca[unit];
270	int     toread;
271
272
273	CHECKUNIT_DIAG(ENXIO);
274
275	/*
276	 * Do processing
277	 * read from buffer
278	 */
279	toread = (min(uio->uio_resid, sizeof(scp->buffer)));
280	return(uiomove(scp->buffer, toread, uio));
281}
282
283static int
284${1}write(struct cdev *dev, struct uio *uio, int ioflag)
285{
286	int unit = UNIT(dev);
287	sc_p scp  = sca[unit];
288	int	towrite;
289
290	CHECKUNIT_DIAG(ENXIO);
291
292	/*
293	 * Do processing
294	 * write to buffer
295	 */
296	towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
297	return(uiomove(scp->buffer, towrite, uio));
298}
299
300static int
301${1}mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
302{
303	int unit = UNIT(dev);
304	sc_p scp  = sca[unit];
305
306	CHECKUNIT_DIAG(-1);
307
308	(void)scp; /* Delete this line after using scp. */
309	/*
310	 * Do processing
311	 */
312#if 0	/* if we had a frame buffer or whatever.. do this */
313	if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) {
314		return (-1);
315	}
316	return i386_btop((FRAMEBASE + offset));
317#else
318	return (-1);
319#endif
320}
321
322static int
323${1}poll(struct cdev *dev, int which, struct thread *td)
324{
325	int unit = UNIT(dev);
326	sc_p scp  = sca[unit];
327
328	CHECKUNIT_DIAG(ENXIO);
329
330	(void)scp; /* Delete this line after using scp. */
331	/*
332	 * Do processing
333	 */
334	return (0); /* this is the wrong value I'm sure */
335}
336
337/*
338 * Now  for some driver initialisation.
339 * Occurs ONCE during boot (very early).
340 */
341static void
342${1}_drvinit(void *unused)
343{
344	int	unit;
345	sc_p	scp;
346
347	for (unit = 0; unit < N${UPPER}; unit++) {
348		/*
349		 * Allocate storage for this instance .
350		 */
351		scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO);
352		if( scp == NULL) {
353			printf("${1}%d failed to allocate strorage\n", unit);
354			return;
355		}
356		sca[unit] = scp;
357    		scp->dev = make_dev(&${1}_cdevsw, unit,
358			UID_ROOT, GID_KMEM, 0640, "${1}%d", unit);
359	}
360}
361
362SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
363		${1}_drvinit, NULL);
364DONE
365
366cat >${TOP}/sys/${1}io.h <<DONE
367/*
368 * Definitions needed to access the ${1} device (ioctls etc)
369 * see mtio.h , ioctl.h as examples
370 */
371#ifndef SYS_DHIO_H
372#define SYS_DHIO_H
373
374#ifndef KERNEL
375#include <sys/types.h>
376#endif
377#include <sys/ioccom.h>
378
379/*
380 * define an ioctl here
381 */
382#define DHIOCRESET _IO('D', 0)   /* reset the ${1} device */
383#endif
384DONE
385
386if [ ! -d ${TOP}/modules/${1} ]; then
387	mkdir -p ${TOP}/modules/${1}
388fi
389
390cat >${TOP}/modules/${1}/Makefile <<DONE
391#	${UPPER} Loadable Kernel Module
392#
393# \$FreeBSD\$
394
395.PATH:  \${.CURDIR}/../../dev/${1}
396KMOD    = ${1}
397SRCS    = ${1}.c
398
399.include <bsd.kmod.mk>
400DONE
401
402echo -n "Do you want to build the '${1}' module? [Y]"
403read VAL
404if [ "-z" "$VAL" ]; then
405	VAL=YES
406fi
407case ${VAL} in
408[yY]*)
409	(cd ${TOP}/modules/${1}; make depend; make )
410	;;
411*)
412#	exit
413	;;
414esac
415
416echo ""
417echo -n "Do you want to build the '${UPPER}' kernel? [Y]"
418read VAL
419if [ "-z" "$VAL" ]; then
420	VAL=YES
421fi
422case ${VAL} in
423[yY]*)
424	(
425	 cd ${TOP}/i386/conf; \
426	 config ${UPPER}; \
427	 cd ${TOP}/i386/compile/${UPPER}; \
428	 make depend; \
429	 make; \
430	)
431	;;
432*)
433#	exit
434	;;
435esac
436
437#--------------end of script---------------
438#
439#edit to your taste..
440#
441#
442