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