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