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