make_device_driver.sh revision 67653
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# $FreeBSD: head/share/examples/drivers/make_device_driver.sh 67653 2000-10-26 21:37:38Z julian $"
10#
11#-------cut here------------------
12if [ "${1}X" = "X" ] 
13then
14	echo "Hey , how about some help here.. give me a device name!"
15	exit 1
16fi
17UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"` 
18
19HERE=`pwd`
20cd /sys
21TOP=`pwd`
22
23echo ${TOP}/modules/${1}
24echo ${TOP}/i386/conf/files.${UPPER}
25echo ${TOP}/i386/conf/${UPPER}
26echo ${TOP}/dev/${1}
27echo ${TOP}/dev/${1}/${1}.c
28echo ${TOP}/sys/${1}io.h
29echo ${TOP}/modules/${1}
30echo ${TOP}/modules/${1}/Makefile
31
32rm -rf ${TOP}/dev/${1}
33rm -rf ${TOP}/modules/${1}
34rm ${TOP}/i386/conf/files.${UPPER}
35rm ${TOP}/i386/conf/${UPPER}
36rm ${TOP}/sys/${1}io.h
37
38if [ -d ${TOP}/modules/${1} ]
39then
40	echo "There appears to already be a module called ${1}"
41	exit 1
42else
43	mkdir ${TOP}/modules/${1}
44fi
45
46#######################################################################
47#######################################################################
48#
49# Create configuration information needed to create a kernel
50# containing this driver.
51#
52# Not really needed if we are going to do this as a module.
53#######################################################################
54# First add the file to a local file list.
55#######################################################################
56
57cat >${TOP}/i386/conf/files.${UPPER} <<DONE
58dev/${1}/${1}.c	 optional ${1}
59DONE
60
61#######################################################################
62# Then create a configuration file for a kernel that contains this driver.
63#######################################################################
64cat >${TOP}/i386/conf/${UPPER} <<DONE
65# Configuration file for kernel type: ${UPPER}
66ident	${UPPER}
67# \$Free\0x42SD: src/share/examples/drivers/make_device_driver.sh,v 1.8 2000/10/25 15:08:11 julian Exp $"
68DONE
69
70grep -v GENERIC < /sys/i386/conf/GENERIC >>${TOP}/i386/conf/${UPPER}
71
72cat >>${TOP}/i386/conf/${UPPER} <<DONE
73options		DDB		# trust me, you'll need this
74device		${1}
75DONE
76
77if [ ! -d ${TOP}/dev/${1} ]
78then
79	mkdir -p ${TOP}/dev/${1}
80fi
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99cat >${TOP}/dev/${1}/${1}.c <<DONE
100/*
101 * Copyright ME
102 *
103 * ${1} driver
104 * \$FreeBSD: head/share/examples/drivers/make_device_driver.sh 67653 2000-10-26 21:37:38Z julian $
105 */
106
107
108#include <sys/param.h>
109#include <sys/systm.h>
110#include <sys/conf.h>		/* cdevsw stuff */
111#include <sys/kernel.h>		/* SYSINIT stuff */
112#include <sys/uio.h>		/* SYSINIT stuff */
113#include <sys/malloc.h>		/* malloc region definitions */
114#include <sys/module.h>
115#include <sys/bus.h>
116#include <machine/bus.h>
117#include <machine/resource.h>
118#include <sys/rman.h>
119#include <sys/time.h>
120
121#include <isa/isavar.h>
122#include "isa_if.h"
123#include <sys/${1}io.h>		/* ${1} IOCTL definitions */
124
125#define ${UPPER}DEV2SOFTC(dev) ((dev)->si_drv1)
126#define ${UPPER}_INB(port) bus_space_read_1( bt, bh, (port))
127#define ${UPPER}_OUTB(port, val) bus_space_write_1( bt, bh, (port), (val))
128#define SOME_PORT 123
129#define EXPECTED_VALUE 0x42
130
131
132/* Function prototypes (these should all be static) */
133static int ${1}_isa_probe (device_t);
134static int ${1}_isa_attach (device_t);
135static int ${1}_isa_detach (device_t);
136static int ${1}_deallocate_resources(device_t device);
137static int ${1}_allocate_resources(device_t device);
138
139static d_open_t		${1}open;
140static d_close_t	${1}close;
141static d_read_t		${1}read;
142static d_write_t	${1}write;
143static d_ioctl_t	${1}ioctl;
144static d_mmap_t		${1}mmap;
145static d_poll_t		${1}poll;
146static	void		${1}intr(void *arg);
147 
148#define CDEV_MAJOR 20
149static struct cdevsw ${1}_cdevsw = {
150	/* open */	${1}open,
151	/* close */	${1}close,
152	/* read */	${1}read,
153	/* write */	${1}write,
154	/* ioctl */	${1}ioctl,
155	/* poll */	${1}poll,
156	/* mmap */	${1}mmap,
157	/* strategy */	nostrategy,	/* not a block type device */
158	/* name */	"${1}",
159	/* maj */	CDEV_MAJOR,
160	/* dump */	nodump,		/* not a block type device */
161	/* psize */	nopsize,	/* not a block type device */
162	/* flags */	0,
163	/* bmaj */	-1
164};
165 
166/* 
167 * device specific Misc defines 
168 */
169#define BUFFERSIZE 1024
170#define NUMPORTS 4
171#define MEMSIZE	1024*1024 /* imaginable h/w buffer size */
172
173/*
174 * One of these per allocated device
175 */
176struct ${1}_softc {
177	bus_space_tag_t bt;
178	bus_space_handle_t bh;
179	int rid_ioport;
180	int rid_memory;
181	int rid_irq;
182	int rid_drq;
183	struct resource* res_ioport;	/* resource for port range */
184	struct resource* res_memory;	/* resource for mem range */
185	struct resource* res_irq;	/* resource for irq range */
186	struct resource* res_drq;	/* resource for dma channel */
187	device_t device;
188	dev_t dev;
189	void	*intr_cookie;
190	char	buffer[BUFFERSIZE];
191} ;
192
193typedef	struct ${1}_softc *sc_p;
194
195static devclass_t ${1}_devclass;
196
197static struct isa_pnp_id ${1}_ids[] = {
198	{0x12345678, "ABCco Widget"},
199	{0xfedcba98, "shining moon Widget ripoff"},
200	{0}
201};
202
203static device_method_t ${1}_methods[] = {
204	DEVMETHOD(device_probe,		${1}_isa_probe),
205	DEVMETHOD(device_attach,	${1}_isa_attach),
206	DEVMETHOD(device_detach,	${1}_isa_detach),
207	{ 0, 0 }
208};
209
210static driver_t ${1}_isa_driver = {
211	"${1}",
212	${1}_methods,
213	sizeof (struct ${1}_softc)
214};
215
216DRIVER_MODULE(${1}, isa, ${1}_isa_driver, ${1}_devclass, 0, 0);
217
218
219/*
220 * The ISA code calls this for each device it knows about,
221 * whether via the PNP code or via the hints etc.
222 */
223static int
224${1}_isa_probe (device_t device)
225{
226	int error;
227	sc_p scp = device_get_softc(device);
228
229	bzero(scp, sizeof(*scp));
230	scp->device = device;
231
232	/*
233	 * Check for a PNP match..
234	 * There are several possible outcomes.
235	 * error == 0		We match a PNP device (possibly several?).
236	 * error == ENXIO,	It is a PNP device but not ours.
237	 * error == ENOENT,	I is not a PNP device.. try heuristic probes.
238	 *    -- logic from if_ed_isa.c, added info from isa/isa_if.m:
239	 */
240	error = ISA_PNP_PROBE(device_get_parent(device), device, ${1}_ids);
241	switch (error) {
242	case 0:
243		/*
244		 * We found a PNP device.
245		 * Do nothing, as it's all done in attach()
246		 */
247		break;
248	case ENOENT:
249		/*
250		 * Well it didn't show up in the PNP tables
251		 * so look directly at known ports (if we have any)
252		 * in case we are looking for an old pre-PNP card.
253		 *
254		 * I think the ports etc should come from a 'hints' section
255		 * buried somewhere. XXX - still not figured out.
256		 * which is read in by code in isa/isahint.c
257		 */
258#if 0 /* till I work out how to find ht eport from the hints */
259		if ( ${UPPER}_INB(SOME_PORT) != EXPECTED_VALUE) {
260			/* 
261			 * It isn't what we expected, so quit looking for it.
262			 */
263			error = ENXIO;
264		} else {
265			/*
266			 * We found one..
267			 */
268			error = 0;
269		}
270#endif
271		break;
272	case  ENXIO:
273		/* not ours, leave imediatly */
274	default:
275		error = ENXIO;
276	}
277	return (error);
278}
279
280/*
281 * Called if the probe succeeded.
282 * We can be destructive here as we know we have the device.
283 */
284static int
285${1}_isa_attach (device_t device)
286{
287	int	unit	= device_get_unit(device);
288	sc_p	scp	= device_get_softc(device);
289	device_t parent	= device_get_parent(device);
290	bus_space_handle_t  bh;
291	bus_space_tag_t bt;
292
293	scp->dev->si_drv1 = scp;
294	scp->dev = make_dev(&${1}_cdevsw, 0,
295			UID_ROOT, GID_OPERATOR, 0600, "${1}%d", unit);
296
297	if (${1}_allocate_resources(device)) {
298		goto errexit;
299	}
300
301	scp->bt = bt = rman_get_bustag(scp->res_ioport);
302	scp->bh = bh = rman_get_bushandle(scp->res_ioport);
303
304	/* register the interrupt handler */
305	if (scp->res_irq) {
306		/* default to the tty mask for registration */  /* XXX */
307		if (BUS_SETUP_INTR(parent, device, scp->res_irq, INTR_TYPE_TTY,
308				${1}intr, scp, &scp->intr_cookie) == 0) {
309			/* do something if successfull */
310		}
311	}
312	return 0;
313
314errexit:
315	/*
316	 * Undo anything we may have done
317	 */
318	${1}_isa_detach(device);
319	return (ENXIO);
320}
321
322static int
323${1}_isa_detach (device_t device)
324{
325	sc_p scp = device_get_softc(device);
326	device_t parent = device_get_parent(device);
327
328	/*
329	 * At this point stick a strong piece of wood into the device
330	 * to make sure it is stopped safely. The alternative is to 
331	 * simply REFUSE to detach if it's busy. What you do depends on 
332	 * your specific situation.
333	 */
334	/* ZAP some register */
335
336	/*
337	 * Take our interrupt handler out of the list of handlers
338	 * that can handle this irq.
339	 */
340	if (scp->intr_cookie != NULL) {
341		if (BUS_TEARDOWN_INTR(parent, device,
342			scp->res_irq, scp->intr_cookie) != 0) {
343				printf("intr teardown failed.. continuing\n");
344		}
345		scp->intr_cookie = NULL;
346	}
347
348	/*
349	 * deallocate any system resources we may have
350	 * allocated on behalf of this driver.
351	 */
352	return ${1}_deallocate_resources(device);
353}
354
355static int
356${1}_allocate_resources(device_t device)
357{
358	int error;
359	sc_p scp = device_get_softc(device);
360	int	size = 16; /* SIZE of port range used */
361
362	scp->res_ioport = bus_alloc_resource(device, SYS_RES_IOPORT,
363			&scp->rid_ioport, 0ul, ~0ul, size, RF_ACTIVE);
364	if (scp->res_ioport == NULL) {
365		goto errexit;
366	}
367
368	scp->res_irq = bus_alloc_resource(device, SYS_RES_IRQ,
369			&scp->rid_irq, 0ul, ~0ul, 1, RF_SHAREABLE);
370	if (scp->res_irq == NULL) {
371		goto errexit;
372	}
373
374	scp->res_drq = bus_alloc_resource(device, SYS_RES_DRQ,
375			&scp->rid_drq, 0ul, ~0ul, 1, RF_ACTIVE);
376	if (scp->res_drq == NULL) {
377		goto errexit;
378	}
379
380	scp->res_memory = bus_alloc_resource(device, SYS_RES_IOPORT,
381			&scp->rid_memory, 0ul, ~0ul, MSIZE, RF_ACTIVE);
382	if (scp->res_memory == NULL) {
383		goto errexit;
384	}
385
386	return (0);
387
388errexit:
389	error = ENXIO;
390	/* cleanup anything we may have assigned. */
391	${1}_deallocate_resources(device);
392	return (ENXIO); /* for want of a better idea */
393}
394
395static int
396${1}_deallocate_resources(device_t device)
397{
398	sc_p scp = device_get_softc(device);
399
400	if (scp->res_irq != 0) {
401		bus_deactivate_resource(device, SYS_RES_IRQ,
402			scp->rid_irq, scp->res_irq);
403		bus_release_resource(device, SYS_RES_IRQ,
404			scp->rid_irq, scp->res_irq);
405		scp->res_irq = 0;
406	}
407	if (scp->res_ioport != 0) {
408		bus_deactivate_resource(device, SYS_RES_IOPORT,
409			scp->rid_ioport, scp->res_ioport);
410		bus_release_resource(device, SYS_RES_IOPORT,
411			scp->rid_ioport, scp->res_ioport);
412		scp->res_ioport = 0;
413	}
414	if (scp->res_ioport != 0) {
415		bus_deactivate_resource(device, SYS_RES_MEMORY,
416			scp->rid_memory, scp->res_memory);
417		bus_release_resource(device, SYS_RES_MEMORY,
418			scp->rid_memory, scp->res_memory);
419		scp->res_ioport = 0;
420	}
421	if (scp->res_drq != 0) {
422		bus_deactivate_resource(device, SYS_RES_DRQ,
423			scp->rid_drq, scp->res_drq);
424		bus_release_resource(device, SYS_RES_DRQ,
425			scp->rid_drq, scp->res_drq);
426		scp->res_drq = 0;
427	}
428	if (scp->dev) {
429		destroy_dev(scp->dev);
430	}
431	return (0);
432}
433
434static void
435${1}intr(void *arg)
436{
437	sc_p scp	= arg;
438
439	/* 
440	 * well we got an interupt, now what?
441	 */
442	return;
443}
444
445static int
446${1}ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
447{
448	sc_p scp	= ${UPPER}DEV2SOFTC(dev);
449	bus_space_handle_t  bh = scp->bh;
450	bus_space_tag_t bt = scp->bt;
451
452	switch (cmd) {
453	case DHIOCRESET:
454		/* whatever resets it */
455		${UPPER}_OUTB(SOME_PORT, 0xff) ;
456		break;
457	default:
458		return ENXIO;
459	}
460	return (0);
461}
462/*
463 * You also need read, write, open, close routines.
464 * This should get you started
465 */
466static int
467${1}open(dev_t dev, int oflags, int devtype, struct proc *p)
468{
469	sc_p scp	= ${UPPER}DEV2SOFTC(dev);
470
471	/* 
472	 * Do processing
473	 */
474	return (0);
475}
476
477static int
478${1}close(dev_t dev, int fflag, int devtype, struct proc *p)
479{
480	sc_p scp	= ${UPPER}DEV2SOFTC(dev);
481
482	/* 
483	 * Do processing
484	 */
485	return (0);
486}
487
488static int
489${1}read(dev_t dev, struct uio *uio, int ioflag)
490{
491	sc_p scp	= ${UPPER}DEV2SOFTC(dev);
492	int	 toread;
493
494
495	/* 
496	 * Do processing
497	 * read from buffer
498	 */
499	toread = (min(uio->uio_resid, sizeof(scp->buffer)));
500	return(uiomove(scp->buffer, toread, uio));
501}
502
503static int
504${1}write(dev_t dev, struct uio *uio, int ioflag)
505{
506	sc_p scp	= ${UPPER}DEV2SOFTC(dev);
507	int	towrite;
508
509	/* 
510	 * Do processing
511	 * write to buffer
512	 */
513	towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
514	return(uiomove(scp->buffer, towrite, uio));
515}
516
517static int
518${1}mmap(dev_t dev, vm_offset_t offset, int nprot)
519{
520	sc_p scp	= ${UPPER}DEV2SOFTC(dev);
521
522	/* 
523	 * Do processing
524	 */
525#if 0	/* if we had a frame buffer or whatever.. do this */
526	if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) {
527		return (-1);
528	}
529	return i386_btop((FRAMEBASE + offset));
530#else
531	return (-1);
532#endif
533}
534
535static int
536${1}poll(dev_t dev, int which, struct proc *p)
537{
538	sc_p scp	= ${UPPER}DEV2SOFTC(dev);
539
540	/* 
541	 * Do processing
542	 */
543	return (0); /* this is the wrong value I'm sure */
544}
545
546DONE
547
548cat >${TOP}/sys/${1}io.h <<DONE
549/*
550 * Definitions needed to access the ${1} device (ioctls etc)
551 * see mtio.h , ioctl.h as examples
552 */
553#ifndef SYS_DHIO_H
554#define SYS_DHIO_H
555
556#ifndef KERNEL
557#include <sys/types.h>
558#endif
559#include <sys/ioccom.h>
560
561/*
562 * define an ioctl here
563 */
564#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */
565#endif
566DONE
567
568if [ ! -d ${TOP}/modules/${1} ]
569then
570	mkdir -p ${TOP}/modules/${1}
571fi
572
573cat >${TOP}/modules/${1}/Makefile <<DONE
574#	${UPPER} Loadable Kernel Module
575#
576# $FreeBSD: head/share/examples/drivers/make_device_driver.sh 67653 2000-10-26 21:37:38Z julian $
577 
578.PATH:  \${.CURDIR}/../../dev/${1}
579KMOD    = ${1}
580SRCS    = ${1}.c
581SRCS    += opt_inet.h device_if.h bus_if.h pci_if.h isa_if.h
582  
583# you may need to do this is your device is an if_xxx driver
584opt_inet.h:
585	echo "#define INET 1" > opt_inet.h
586	   
587.include <bsd.kmod.mk>
588DONE
589
590(cd ${TOP}/modules/${1}; make depend; make )
591exit
592
593config ${UPPER}
594cd ../../compile/${UPPER}
595make depend
596make ${1}.o
597make
598exit
599
600#--------------end of script---------------
601#
602#edit to your taste..
603#
604# 
605
606
607
608
609