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