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