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