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