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