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# $FreeBSD$" 10# 11#-------cut here------------------ 12if [ "${1}X" = "X" ] 13then 14 echo "Hey , how about some help here.. give me a device name!" 15 exit 1 16fi 17UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"` 18 19HERE=`pwd` 20cd /sys 21TOP=`pwd` 22 23RCS_KEYWORD=FreeBSD 24 25echo ${TOP}/modules/${1} 26echo ${TOP}/i386/conf/files.${UPPER} 27echo ${TOP}/i386/conf/${UPPER} 28echo ${TOP}/dev/${1} 29echo ${TOP}/dev/${1}/${1}.c 30echo ${TOP}/sys/${1}io.h 31echo ${TOP}/modules/${1} 32echo ${TOP}/modules/${1}/Makefile 33 34rm -rf ${TOP}/dev/${1} 35rm -rf ${TOP}/modules/${1} 36rm ${TOP}/i386/conf/files.${UPPER} 37rm ${TOP}/i386/conf/${UPPER} 38rm ${TOP}/sys/${1}io.h 39 40if [ -d ${TOP}/modules/${1} ] 41then 42 echo "There appears to already be a module called ${1}" 43 exit 1 44else 45 mkdir ${TOP}/modules/${1} 46fi 47 48####################################################################### 49####################################################################### 50# 51# Create configuration information needed to create a kernel 52# containing this driver. 53# 54# Not really needed if we are going to do this as a module. 55####################################################################### 56# First add the file to a local file list. 57####################################################################### 58 59cat >${TOP}/i386/conf/files.${UPPER} <<DONE 60dev/${1}/${1}.c optional ${1} 61DONE 62 63####################################################################### 64# Then create a configuration file for a kernel that contains this driver. 65####################################################################### 66cat >${TOP}/i386/conf/${UPPER} <<DONE 67# Configuration file for kernel type: ${UPPER} 68ident ${UPPER} 69# \$${RCS_KEYWORD}: $ 70DONE 71 72grep -v GENERIC < /sys/i386/conf/GENERIC >>${TOP}/i386/conf/${UPPER} 73 74cat >>${TOP}/i386/conf/${UPPER} <<DONE 75options DDB # trust me, you'll need this 76device ${1} 77DONE 78 79if [ ! -d ${TOP}/dev/${1} ] 80then 81 mkdir -p ${TOP}/dev/${1} 82fi 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99cat >${TOP}/dev/${1}/${1}.c <<DONE 100/* 101 * Copyright (c) [year] [your name] 102 * All rights reserved. 103 * 104 * Redistribution and use in source and binary forms, with or without 105 * modification, are permitted provided that the following conditions 106 * are met: 107 * 1. Redistributions of source code must retain the above copyright 108 * notice, this list of conditions and the following disclaimer. 109 * 2. Redistributions in binary form must reproduce the above copyright 110 * notice, this list of conditions and the following disclaimer in the 111 * documentation and/or other materials provided with the distribution. 112 * 113 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 114 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 115 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 116 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 117 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 118 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 119 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 120 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 121 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 122 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 123 * SUCH DAMAGE. 124 * 125 * 126 * ${1} driver 127 * \$${RCS_KEYWORD}: $ 128 */ 129 130 131#include <sys/param.h> 132#include <sys/systm.h> 133#include <sys/conf.h> /* cdevsw stuff */ 134#include <sys/kernel.h> /* SYSINIT stuff */ 135#include <sys/uio.h> /* SYSINIT stuff */ 136#include <sys/malloc.h> /* malloc region definitions */ 137#include <sys/module.h> 138#include <sys/bus.h> 139#include <machine/bus.h> 140#include <machine/resource.h> 141#include <sys/rman.h> 142#include <sys/time.h> 143 144#include <isa/isavar.h> 145#include "isa_if.h" 146#include <sys/${1}io.h> /* ${1} IOCTL definitions */ 147 148#define ${UPPER}DEV2SOFTC(dev) ((dev)->si_drv1) 149#define ${UPPER}_INB(port) bus_space_read_1( bt, bh, (port)) 150#define ${UPPER}_OUTB(port, val) bus_space_write_1( bt, bh, (port), (val)) 151#define SOME_PORT 123 152#define EXPECTED_VALUE 0x42 153 154 155/* Function prototypes (these should all be static) */ 156static int ${1}_isa_probe (device_t); 157static int ${1}_isa_attach (device_t); 158static int ${1}_isa_detach (device_t); 159static int ${1}_deallocate_resources(device_t device); 160static int ${1}_allocate_resources(device_t device); 161 162static d_open_t ${1}open; 163static d_close_t ${1}close; 164static d_read_t ${1}read; 165static d_write_t ${1}write; 166static d_ioctl_t ${1}ioctl; 167static d_mmap_t ${1}mmap; 168static d_poll_t ${1}poll; 169static void ${1}intr(void *arg); 170 171#define CDEV_MAJOR 20 172static struct cdevsw ${1}_cdevsw = { 173 /* open */ ${1}open, 174 /* close */ ${1}close, 175 /* read */ ${1}read, 176 /* write */ ${1}write, 177 /* ioctl */ ${1}ioctl, 178 /* poll */ ${1}poll, 179 /* mmap */ ${1}mmap, 180 /* strategy */ nostrategy, /* not a block type device */ 181 /* name */ "${1}", 182 /* maj */ CDEV_MAJOR, 183 /* dump */ nodump, /* not a block type device */ 184 /* psize */ nopsize, /* not a block type device */ 185 /* flags */ 0, 186 /* bmaj */ -1 187}; 188 189/* 190 * device specific Misc defines 191 */ 192#define BUFFERSIZE 1024 193#define NUMPORTS 4 194#define MEMSIZE 1024*1024 /* imaginable h/w buffer size */ 195 196/* 197 * One of these per allocated device 198 */ 199struct ${1}_softc { 200 bus_space_tag_t bt; 201 bus_space_handle_t bh; 202 int rid_ioport; 203 int rid_memory; 204 int rid_irq; 205 int rid_drq; 206 struct resource* res_ioport; /* resource for port range */ 207 struct resource* res_memory; /* resource for mem range */ 208 struct resource* res_irq; /* resource for irq range */ 209 struct resource* res_drq; /* resource for dma channel */ 210 device_t device; 211 dev_t dev; 212 void *intr_cookie; 213 char buffer[BUFFERSIZE]; 214} ; 215 216typedef struct ${1}_softc *sc_p; 217 218static devclass_t ${1}_devclass; 219 220static struct isa_pnp_id ${1}_ids[] = { 221 {0x12345678, "ABCco Widget"}, 222 {0xfedcba98, "shining moon Widget ripoff"}, 223 {0} 224}; 225 226static device_method_t ${1}_methods[] = { 227 DEVMETHOD(device_probe, ${1}_isa_probe), 228 DEVMETHOD(device_attach, ${1}_isa_attach), 229 DEVMETHOD(device_detach, ${1}_isa_detach), 230 { 0, 0 } 231}; 232 233static driver_t ${1}_isa_driver = { 234 "${1}", 235 ${1}_methods, 236 sizeof (struct ${1}_softc) 237}; 238 239DRIVER_MODULE(${1}, isa, ${1}_isa_driver, ${1}_devclass, 0, 0); 240 241 242/* 243 * The ISA code calls this for each device it knows about, 244 * whether via the PNP code or via the hints etc. 245 */ 246static int 247${1}_isa_probe (device_t device) 248{ 249 int error; 250 sc_p scp = device_get_softc(device); 251 252 bzero(scp, sizeof(*scp)); 253 scp->device = device; 254 255 /* 256 * Check for a PNP match.. 257 * There are several possible outcomes. 258 * error == 0 We match a PNP device (possibly several?). 259 * error == ENXIO, It is a PNP device but not ours. 260 * error == ENOENT, I is not a PNP device.. try heuristic probes. 261 * -- logic from if_ed_isa.c, added info from isa/isa_if.m: 262 */ 263 error = ISA_PNP_PROBE(device_get_parent(device), device, ${1}_ids); 264 switch (error) { 265 case 0: 266 /* 267 * We found a PNP device. 268 * Do nothing, as it's all done in attach() 269 */ 270 break; 271 case ENOENT: 272 /* 273 * Well it didn't show up in the PNP tables 274 * so look directly at known ports (if we have any) 275 * in case we are looking for an old pre-PNP card. 276 * 277 * I think the ports etc should come from a 'hints' section 278 * buried somewhere. XXX - still not figured out. 279 * which is read in by code in isa/isahint.c 280 */ 281#if 0 /* till I work out how to find ht eport from the hints */ 282 if ( ${UPPER}_INB(SOME_PORT) != EXPECTED_VALUE) { 283 /* 284 * It isn't what we expected, so quit looking for it. 285 */ 286 error = ENXIO; 287 } else { 288 /* 289 * We found one.. 290 */ 291 error = 0; 292 } 293#endif 294 break; 295 case ENXIO: 296 /* not ours, leave imediatly */ 297 default: 298 error = ENXIO; 299 } 300 return (error); 301} 302 303/* 304 * Called if the probe succeeded. 305 * We can be destructive here as we know we have the device. 306 */ 307static int 308${1}_isa_attach (device_t device) 309{ 310 int unit = device_get_unit(device); 311 sc_p scp = device_get_softc(device); 312 device_t parent = device_get_parent(device); 313 bus_space_handle_t bh; 314 bus_space_tag_t bt; 315 316 scp->dev->si_drv1 = scp; 317 scp->dev = make_dev(&${1}_cdevsw, 0, 318 UID_ROOT, GID_OPERATOR, 0600, "${1}%d", unit); 319 320 if (${1}_allocate_resources(device)) { 321 goto errexit; 322 } 323 324 scp->bt = bt = rman_get_bustag(scp->res_ioport); 325 scp->bh = bh = rman_get_bushandle(scp->res_ioport); 326 327 /* register the interrupt handler */ 328 if (scp->res_irq) { 329 /* default to the tty mask for registration */ /* XXX */ 330 if (BUS_SETUP_INTR(parent, device, scp->res_irq, INTR_TYPE_TTY, 331 ${1}intr, scp, &scp->intr_cookie) == 0) { 332 /* do something if successfull */ 333 } 334 } 335 return 0; 336 337errexit: 338 /* 339 * Undo anything we may have done 340 */ 341 ${1}_isa_detach(device); 342 return (ENXIO); 343} 344 345static int 346${1}_isa_detach (device_t device) 347{ 348 sc_p scp = device_get_softc(device); 349 device_t parent = device_get_parent(device); 350 351 /* 352 * At this point stick a strong piece of wood into the device 353 * to make sure it is stopped safely. The alternative is to 354 * simply REFUSE to detach if it's busy. What you do depends on 355 * your specific situation. 356 */ 357 /* ZAP some register */ 358 359 /* 360 * Take our interrupt handler out of the list of handlers 361 * that can handle this irq. 362 */ 363 if (scp->intr_cookie != NULL) { 364 if (BUS_TEARDOWN_INTR(parent, device, 365 scp->res_irq, scp->intr_cookie) != 0) { 366 printf("intr teardown failed.. continuing\n"); 367 } 368 scp->intr_cookie = NULL; 369 } 370 371 /* 372 * deallocate any system resources we may have 373 * allocated on behalf of this driver. 374 */ 375 return ${1}_deallocate_resources(device); 376} 377 378static int 379${1}_allocate_resources(device_t device) 380{ 381 int error; 382 sc_p scp = device_get_softc(device); 383 int size = 16; /* SIZE of port range used */ 384 385 scp->res_ioport = bus_alloc_resource(device, SYS_RES_IOPORT, 386 &scp->rid_ioport, 0ul, ~0ul, size, RF_ACTIVE); 387 if (scp->res_ioport == NULL) { 388 goto errexit; 389 } 390 391 scp->res_irq = bus_alloc_resource(device, SYS_RES_IRQ, 392 &scp->rid_irq, 0ul, ~0ul, 1, RF_SHAREABLE); 393 if (scp->res_irq == NULL) { 394 goto errexit; 395 } 396 397 scp->res_drq = bus_alloc_resource(device, SYS_RES_DRQ, 398 &scp->rid_drq, 0ul, ~0ul, 1, RF_ACTIVE); 399 if (scp->res_drq == NULL) { 400 goto errexit; 401 } 402 403 scp->res_memory = bus_alloc_resource(device, SYS_RES_IOPORT, 404 &scp->rid_memory, 0ul, ~0ul, MSIZE, RF_ACTIVE); 405 if (scp->res_memory == NULL) { 406 goto errexit; 407 } 408 409 return (0); 410 411errexit: 412 error = ENXIO; 413 /* cleanup anything we may have assigned. */ 414 ${1}_deallocate_resources(device); 415 return (ENXIO); /* for want of a better idea */ 416} 417 418static int 419${1}_deallocate_resources(device_t device) 420{ 421 sc_p scp = device_get_softc(device); 422 423 if (scp->res_irq != 0) { 424 bus_deactivate_resource(device, SYS_RES_IRQ, 425 scp->rid_irq, scp->res_irq); 426 bus_release_resource(device, SYS_RES_IRQ, 427 scp->rid_irq, scp->res_irq); 428 scp->res_irq = 0; 429 } 430 if (scp->res_ioport != 0) { 431 bus_deactivate_resource(device, SYS_RES_IOPORT, 432 scp->rid_ioport, scp->res_ioport); 433 bus_release_resource(device, SYS_RES_IOPORT, 434 scp->rid_ioport, scp->res_ioport); 435 scp->res_ioport = 0; 436 } 437 if (scp->res_ioport != 0) { 438 bus_deactivate_resource(device, SYS_RES_MEMORY, 439 scp->rid_memory, scp->res_memory); 440 bus_release_resource(device, SYS_RES_MEMORY, 441 scp->rid_memory, scp->res_memory); 442 scp->res_ioport = 0; 443 } 444 if (scp->res_drq != 0) { 445 bus_deactivate_resource(device, SYS_RES_DRQ, 446 scp->rid_drq, scp->res_drq); 447 bus_release_resource(device, SYS_RES_DRQ, 448 scp->rid_drq, scp->res_drq); 449 scp->res_drq = 0; 450 } 451 if (scp->dev) { 452 destroy_dev(scp->dev); 453 } 454 return (0); 455} 456 457static void 458${1}intr(void *arg) 459{ 460 sc_p scp = arg; 461 462 /* 463 * well we got an interupt, now what? 464 */ 465 return; 466} 467 468static int 469${1}ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 470{ 471 sc_p scp = ${UPPER}DEV2SOFTC(dev); 472 bus_space_handle_t bh = scp->bh; 473 bus_space_tag_t bt = scp->bt; 474 475 switch (cmd) { 476 case DHIOCRESET: 477 /* whatever resets it */ 478 ${UPPER}_OUTB(SOME_PORT, 0xff) ; 479 break; 480 default: 481 return ENXIO; 482 } 483 return (0); 484} 485/* 486 * You also need read, write, open, close routines. 487 * This should get you started 488 */ 489static int 490${1}open(dev_t dev, int oflags, int devtype, struct proc *p) 491{ 492 sc_p scp = ${UPPER}DEV2SOFTC(dev); 493 494 /* 495 * Do processing 496 */ 497 return (0); 498} 499 500static int 501${1}close(dev_t dev, int fflag, int devtype, struct proc *p) 502{ 503 sc_p scp = ${UPPER}DEV2SOFTC(dev); 504 505 /* 506 * Do processing 507 */ 508 return (0); 509} 510 511static int 512${1}read(dev_t dev, struct uio *uio, int ioflag) 513{ 514 sc_p scp = ${UPPER}DEV2SOFTC(dev); 515 int toread; 516 517 518 /* 519 * Do processing 520 * read from buffer 521 */ 522 toread = (min(uio->uio_resid, sizeof(scp->buffer))); 523 return(uiomove(scp->buffer, toread, uio)); 524} 525 526static int 527${1}write(dev_t dev, struct uio *uio, int ioflag) 528{ 529 sc_p scp = ${UPPER}DEV2SOFTC(dev); 530 int towrite; 531 532 /* 533 * Do processing 534 * write to buffer 535 */ 536 towrite = (min(uio->uio_resid, sizeof(scp->buffer))); 537 return(uiomove(scp->buffer, towrite, uio)); 538} 539 540static int 541${1}mmap(dev_t dev, vm_offset_t offset, int nprot) 542{ 543 sc_p scp = ${UPPER}DEV2SOFTC(dev); 544 545 /* 546 * Do processing 547 */ 548#if 0 /* if we had a frame buffer or whatever.. do this */ 549 if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) { 550 return (-1); 551 } 552 return i386_btop((FRAMEBASE + offset)); 553#else 554 return (-1); 555#endif 556} 557 558static int 559${1}poll(dev_t dev, int which, struct proc *p) 560{ 561 sc_p scp = ${UPPER}DEV2SOFTC(dev); 562 563 /* 564 * Do processing 565 */ 566 return (0); /* this is the wrong value I'm sure */ 567} 568 569DONE 570 571cat >${TOP}/sys/${1}io.h <<DONE 572/* 573 * Definitions needed to access the ${1} device (ioctls etc) 574 * see mtio.h , ioctl.h as examples 575 */ 576#ifndef SYS_DHIO_H 577#define SYS_DHIO_H 578 579#ifndef KERNEL 580#include <sys/types.h> 581#endif 582#include <sys/ioccom.h> 583 584/* 585 * define an ioctl here 586 */ 587#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */ 588#endif 589DONE 590 591if [ ! -d ${TOP}/modules/${1} ] 592then 593 mkdir -p ${TOP}/modules/${1} 594fi 595 596cat >${TOP}/modules/${1}/Makefile <<DONE 597# ${UPPER} Loadable Kernel Module 598# 599# \$${RCS_KEYWORD}: $ 600 601.PATH: \${.CURDIR}/../../dev/${1} 602KMOD = ${1} 603SRCS = ${1}.c 604SRCS += opt_inet.h device_if.h bus_if.h pci_if.h isa_if.h 605 606# you may need to do this is your device is an if_xxx driver 607opt_inet.h: 608 echo "#define INET 1" > opt_inet.h 609 610.include <bsd.kmod.mk> 611DONE 612 613(cd ${TOP}/modules/${1}; make depend; make ) 614exit 615 616config ${UPPER} 617cd ../../compile/${UPPER} 618make depend 619make ${1}.o 620make 621exit 622 623#--------------end of script--------------- 624# 625#edit to your taste.. 626# 627# 628 629 630 631 632