xref: /freebsd/share/examples/drivers/make_device_driver.sh (revision 33b77e2decd50e53798014b70bf7ca3bdc4c0c7e)
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#
10#-------cut here------------------
11cd /sys/i386/conf
12
13if [ "${1}X" = "X" ]
14then
15	echo "Hey , how about some help here.. give me a device name!"
16	exit 1
17fi
18
19if [ -d /usr/src/lkm ]
20then
21	mkdir /usr/src/lkm/${1}
22fi
23
24UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"`
25cat >files.${UPPER} <<DONE
26i386/isa/${1}.c      optional ${1} device-driver
27DONE
28
29cat >${UPPER} <<DONE
30# Configuration file for kernel type: ${UPPER}
31ident	${UPPER}
32# \$Id: make_device_driver.sh,v 1.2 1997/12/30 03:23:12 julian Exp $"
33DONE
34
35grep -v GENERIC < GENERIC >>${UPPER}
36
37cat >>${UPPER} <<DONE
38# trust me, you'll need this
39options	DDB		
40device ${1}0 at isa? port 0x234 bio irq 5 vector ${1}intr
41DONE
42
43cat >../isa/${1}.c <<DONE
44/*
45 * Copyright ME
46 *
47 * ${1} driver
48 * \$Id: make_device_driver.sh,v 1.2 1997/12/30 03:23:12 julian Exp $
49 */
50
51
52#include "${1}.h"		/* generated file.. defines N${UPPER} */
53#include <sys/param.h>
54#include <sys/systm.h>
55#include <sys/kernel.h>		/* SYSINIT stuff */
56#include <sys/conf.h>		/* cdevsw stuff */
57#include <sys/malloc.h>		/* malloc region definitions */
58#include <machine/clock.h>	/* DELAY() */
59#include <i386/isa/isa.h>	/* ISA bus port definitions etc. */
60#include <i386/isa/isa_device.h>/* ISA bus configuration structures */
61#include <sys/${1}io.h>		/* ${1} IOCTL definitions */
62#ifdef DEVFS
63#include <sys/devfsext.h>	/* DEVFS defintitions */
64#endif /* DEVFS */
65
66
67
68/* Function prototypes (these should all be static  except for ${1}intr()) */
69static  d_open_t	${1}open;
70static  d_close_t	${1}close;
71static  d_read_t	${1}read;
72static  d_write_t	${1}write;
73static  d_ioctl_t	${1}ioctl;
74static  d_mmap_t	${1}mmap;
75static  d_poll_t	${1}poll;
76static	int		${1}probe (struct isa_device *);
77static	int		${1}attach (struct isa_device *);
78#ifdef ${UPPER}_MODULE
79void ${1}intr(int unit); /* actually defined in ioconf.h (generated file) */
80#endif
81 
82#define CDEV_MAJOR 20
83static struct cdevsw ${1}_cdevsw = {
84	${1}open,
85	${1}close,
86	${1}read,
87	${1}write,        
88	${1}ioctl,
89	nullstop,
90	nullreset,
91	nodevtotty, 
92	${1}poll,
93	${1}mmap,
94	NULL,
95	"${1}",
96	NULL,
97	-1 };
98 
99struct isa_driver ${1}driver = {
100	${1}probe,
101	${1}attach,
102	"${1}" };
103
104/* 
105 * device  specific Misc defines 
106 */
107#define BUFFERSIZE 1024
108#define NUMPORTS 4
109#define UNIT(dev) minor(dev)	/* assume one minor number per unit */
110
111/*
112 * One of these per allocated device
113 */
114struct ${1}_softc {
115	struct isa_device *dev;
116	char	buffer[BUFFERSIZE];
117#ifdef DEVFS
118	static void *devfs_token;
119#endif
120} ;
121
122typedef	struct ${1}_softc *sc_p;
123
124static sc_p sca[N${UPPER}];
125
126/* add your own test to see if it exists */
127/* should return the number of ports needed */
128static int
129${1}probe (struct isa_device *dev)
130{
131	char val;
132	int unit = dev->id_unit;
133	sc_p scp  = sca[unit];
134
135	/*
136	 * Check the unit makes sense.
137	 */
138	if (unit > N${UPPER}) {
139		printf("bad unit (%d)\n", unit);
140		return (0);
141	}
142	if (scp) {
143		printf("unit $d already attached\n", unit);
144		return (0);
145	}
146
147	/*
148	 * try see if the device is there.
149	 */
150	val = inb (dev->id_iobase);
151	if ( val != 42 ) {
152		return (0);
153	}
154
155	/*
156	 * ok, we got one we think 
157	 * do some further (this time possibly destructive) tests.
158	 */
159	outb (dev->id_iobase, 0xff);
160	DELAY (10000); /*  10 ms delay */
161	val = inb (dev->id_iobase) & 0x0f;
162	return ((val & 0x0f) == 0x0f)? NUMPORTS : 0 ;
163}
164
165/*
166 * Called if the probe succeeded.
167 * We can be destructive here as we know we have the device.
168 * we can also trust the unit number.
169 */
170static int
171${1}attach (struct isa_device *dev)
172{
173	int unit = dev->id_unit;
174	sc_p scp  = sca[unit];
175	
176	/* 
177	 * Allocate storage for this instance .
178	 */
179	scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT);
180	if( scp == NULL) {
181		printf("${1}%d failed to allocage driver strorage\n", unit);
182		return (0);
183	}
184	bzero(scp, sizeof(*scp));
185	sca[unit] = scp;
186
187	/*
188	 * Store whatever seems wise.
189	 */
190	scp->dev = dev;
191#if DEVFS
192    	scp->devfs_token = devfs_add_devswf(&${1}_cdevsw, unit, DV_CHR,
193	    UID_ROOT, GID_KMEM, 0600, "${1}%d", unit);
194#endif
195	return 1;
196}
197
198/* 
199 * Macro to check that the unit number is valid
200 * Often this isn't needed as once the open() is performed,
201 * the unit number is pretty much safe.. The exception would be if we
202 * implemented devices that could "go away". in which case all these routines
203 * would be wise to check the number, DIAGNOSTIC or not.
204 */
205#define CHECKUNIT(RETVAL)					\
206do { /* the do-while is a safe way to do this grouping */	\
207	if (unit > N${UPPER}) {					\
208		printf(__FUNCTION__ ":bad unit $d\n", unit);	\
209		return (RETVAL);				\
210	}							\
211	if (scp == NULL) { 					\
212		printf( __FUNCTION__ ": unit $d not attached\n", unit);\
213		return (RETVAL);				\
214	}							\
215} while (0)						
216#ifdef	DIAGNOSTIC
217#define	CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL)
218#else	/* DIAGNOSTIC */
219#define	CHECKUNIT_DIAG(RETVAL)
220#endif 	/* DIAGNOSTIC */
221
222void
223${1}intr(int unit)
224{
225	sc_p scp  = sca[unit];
226	
227	/* 
228	 * well we got an interupt, now what?
229	 * Theoretically we don't need to check the unit.
230	 */
231	return;
232}
233
234int ${1}ioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
235{
236	int unit = UNIT (dev);
237	sc_p scp  = sca[unit];
238	
239	CHECKUNIT_DIAG(ENXIO);
240    
241	switch (cmd) {
242	    case DHIOCRESET:
243		/*  whatever resets it */
244		outb(scp->dev->id_iobase, 0xff);
245		break;
246	    default:
247		return ENXIO;
248	}
249	return (0);
250}   
251/*
252 * You also need read, write, open, close routines.
253 * This should get you started
254 */
255static  int
256${1}open(dev_t dev, int oflags, int devtype, struct proc *p)
257{
258	int unit = UNIT (dev);
259	sc_p scp  = sca[unit];
260	
261	CHECKUNIT(ENXIO);
262
263	/* 
264	 * Do processing
265	 */
266	return (0);
267}
268
269static  int
270${1}close(dev_t dev, int fflag, int devtype, struct proc *p)
271{
272	int unit = UNIT (dev);
273	sc_p scp  = sca[unit];
274	
275	CHECKUNIT_DIAG(ENXIO);
276
277	/* 
278	 * Do processing
279	 */
280	return (0);
281}
282
283static  int
284${1}read(dev_t dev, struct uio *uio, int ioflag)
285{
286	int unit = UNIT (dev);
287	sc_p scp  = sca[unit];
288	int     toread;
289	
290	
291	CHECKUNIT_DIAG(ENXIO);
292
293	/* 
294	 * Do processing
295	 * read from buffer
296	 */
297	toread = (min(uio->uio_resid, sizeof(scp->buffer)));
298	return(uiomove(scp->buffer, toread, uio));
299}
300
301static  int
302${1}write(dev_t dev, struct uio *uio, int ioflag)
303{
304	int unit = UNIT (dev);
305	sc_p scp  = sca[unit];
306	int	towrite;
307	
308	CHECKUNIT_DIAG(ENXIO);
309
310	/* 
311	 * Do processing
312	 * write to buffer
313	 */
314	towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
315	return(uiomove(scp->buffer, towrite, uio));
316}
317
318static  int
319${1}mmap(dev_t dev, int offset, int nprot)
320{
321	int unit = UNIT (dev);
322	sc_p scp  = sca[unit];
323	
324	CHECKUNIT_DIAG(-1);
325
326	/* 
327	 * Do processing
328	 */
329#if 0	/* if we had a frame buffer or whatever.. do this */
330	if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) {
331		return (-1);
332	}
333	return i386_btop((FRAMEBASE + offset));
334#else
335	return (-1);
336#endif
337}
338
339static  int
340${1}poll(dev_t dev, int which, struct proc *p)
341{
342	int unit = UNIT (dev);
343	sc_p scp  = sca[unit];
344	
345	CHECKUNIT_DIAG(ENXIO);
346
347	/* 
348	 * Do processing
349	 */
350	return (0); /* this is the wrong value I'm sure */
351}
352
353#ifndef ${UPPER}_MODULE
354
355/*
356 * Now  for some driver initialisation.
357 * Occurs ONCE during boot (very early).
358 * This is if we are NOT a loadable module.
359 */
360static void             
361${1}_drvinit(void *unused)
362{
363        dev_t dev;
364
365	dev = makedev(CDEV_MAJOR, 0);
366	cdevsw_add(&dev, &${1}_cdevsw, NULL);
367}
368
369SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
370		${1}_drvinit, NULL)
371
372#else  /* ${UPPER}_MODULE */
373/* Here is the support for if we ARE a loadable kernel module */
374
375#include <sys/exec.h>
376#include <sys/sysent.h>
377#include <sys/lkm.h>
378
379MOD_DEV (${1}, LM_DT_CHAR, CDEV_MAJOR, &${1}_cdevsw);
380
381static struct isa_device dev = {0, &${1}driver, BASE_IO, IRQ, DMA, (caddr_t) PHYS_IO, PHYS_IO_SIZE, INT_INT, 0, FLAGS, 0, 0, 0, 0, 1, 0, 0};
382
383static int
384${1}_load (struct lkm_table *lkmtp, int cmd)
385{
386	if (${1}probe (&dev)) {
387		${1}attach (&dev);
388		uprintf ("${1} driver loaded\n");
389		uprintf ("${1}: interrupts not hooked\n");
390		return 0;
391	} else {
392		uprintf ("${1} driver: probe failed\n");
393		return 1;
394	}
395}
396
397static int
398${1}_unload (struct lkm_table *lkmtp, int cmd)
399{
400	uprintf ("${1} driver unloaded\n");
401	return 0;
402}
403
404static int
405${1}_stat (struct lkm_table *lkmtp, int cmd)
406{
407	return 0;
408}
409
410int
411${1}_mod (struct lkm_table *lkmtp, int cmd, int ver)
412{
413	MOD_DISPATCH(${1}, lkmtp, cmd, ver,
414		${1}_load, ${1}_unload, ${1}_stat);
415}
416
417#endif /* ${UPPER}_MODULE */
418
419DONE
420
421cat >../../sys/${1}io.h <<DONE
422/*
423 * Definitions needed to access the ${1} device (ioctls etc)
424 * see mtio.h , ioctl.h as examples
425 */
426#ifndef SYS_DHIO_H
427#define SYS_DHIO_H
428
429#ifndef KERNEL
430#include <sys/types.h>
431#endif
432#include <sys/ioccom.h>
433
434/*
435 * define an ioctl here
436 */
437#define DHIOCRESET _IO('D', 0)   /* reset the ${1} device */
438#endif
439DONE
440
441if [ -d /usr/src/lkm/${1} ]
442then
443	cat >/usr/src/lkm/${1}/Makefile <<DONE
444#	${UPPER} Loadable Kernel Module
445#
446#	This happens not to work, actually. It's written for
447#	a character ISA device driver, but they cannot be
448#	be made into lkm's, because you have to hard code
449#	everything you'll otherwise enter into the kernel
450#	configuration file.
451
452.PATH:	\${.CURDIR}/../../sys/i386/isa
453KMOD	= ${1}_mod
454SRCS	= ${1}.c ${1}.h
455
456CFLAGS		+= -I. -D${UPPER}_MODULE
457CLEANFILES	+= ${1}.h
458
459BASE_IO=0		# Base IO address
460IRQ=0			# IRQ number
461DMA=-1			# DMA channel
462PHYS_IO=0		# Physical IO Memory base address
463PHYS_IO_SIZE=0		# Physical IO Memory size
464INT_INT=0		# Interrupt interface
465FLAGS=0			# Flags
466
467CFLAGS+= -DBASE_IO=\${BASE_IO} -DIRQ=\${IRQ} -DDMA=\${DMA} -DPHYS_IO=\${PHYS_IO} -DPHYS_IO_SIZE=\${PHYS_IO_SIZE} -DINT_INT=\${INT_INT} -DFLAGS=\${FLAGS}
468
469${1}.h:
470	echo "#define N${UPPER} 1" > ${1}.h
471
472afterinstall:
473	\${INSTALL} -c -o \${BINOWN} -g \${BINGRP} -m \${BINMODE} \
474	\${.CURDIR}/${1} \${DESTDIR}/usr/bin
475
476.include <bsd.kmod.mk>
477DONE
478fi
479
480config ${UPPER}
481cd ../../compile/${UPPER}
482make depend
483make ${1}.o
484make
485exit
486
487#--------------end of script---------------
488#
489#edit to your taste..
490#
491#
492
493
494
495
496