File:  [NetBSD Developer Wiki] / wikisrc / tutorials / bus_space_tutorial.mdwn
Revision 1.4: download - view: text, annotated - select for diffs
Sun Jun 23 14:34:32 2013 UTC (8 years, 5 months ago) by mspo
Branches: MAIN
CVS tags: HEAD
clean up whitespace and try converting tables to tables

    1: [[!toc ]]
    2: 
    3: ## Introduction
    4: 
    5: ### Why was this tutorial created?
    6: 
    7: -   Introductory-level documentation is scarce
    8: -   Writing device drivers is often considered black magic
    9: -   Reading the man pages won’t give you the big picture
   10: -   BSD systems are always in need of new drivers
   11: -   Device drivers are fun
   12: 
   13: ### What won’t be covered here?
   14: 
   15: We don’t have much time, so several ~~advanced~~ topics were omitted:
   16: 
   17: -   Interrupt handling
   18: -   Direct Memory Access and the bus\_dma framework
   19: -   Power management
   20: -   Driver detachment
   21: -   Drivers as kernel modules
   22: -   Examples for buses other than PCI
   23: -   Pretty much everything else...
   24: 
   25: However, once you finish this tutorial, you should be able to pursue
   26: this knowledge yourself.
   27: 
   28: ### What is a driver anyway?
   29: 
   30: -   The interface between user space and hardware, implemented as a part
   31:     of the kernel
   32: -   The NetBSD drivers are written mostly in C
   33: -   Sometimes they have machine dependent assembler parts, but this is a
   34:     rare case
   35: 
   36: ### What do you need to write a driver?
   37: 
   38: -   C programming skills
   39: -   Hardware documentation (or the ability to reverse engineer the
   40:     hardware)
   41: -   A reference driver implementation will help but is not essential
   42: -   A NetBSD installation and kernel source, or a cross-build
   43:     environment (the latter is usually preferred for development of
   44:     drivers)
   45: -   A lot of time, coffee and patience
   46: 
   47: ### Why is writing the device drivers considered difficult?
   48: 
   49: -   It’s not as difficult as you may expect, in fact during this
   50:     tutorial we’ll prove that it’s quite easy
   51: -   You need to think on a very low level
   52:     -   Good understanding of computer architecture is a must
   53: -   Often documentation is the main problem – writing the driver is not
   54:     possible if you don’t understand how the device works
   55:     -   No access to documentation (uncooperative hardware vendors,
   56:         vendors out of business)
   57:     -   Documentation is incomplete or plain wrong
   58:     -   Reverse engineering can solve these problems but it’s a very
   59:         time consuming process
   60: 
   61: ## The NetBSD driver model
   62: 
   63: ### The NetBSD kernel basics
   64: 
   65: -   NetBSD has a classic monolithic UNIX-like kernel - all drivers are
   66:     running in the same address space
   67: -   Thanks to the above, communication between drivers and other kernel
   68:     layers is simple
   69: -   However, it also means that one badly written driver can affect the
   70:     whole kernel
   71: -   Numerous in-kernel frameworks standardise the way drivers are
   72:     written (bus\_space, autoconf, etc.)
   73: 
   74: ### The NetBSD source directory structure
   75: 
   76: -   We’ll only cover parts interesting for a device driver programmer
   77: -   src/sys/
   78:     - kernel source directory
   79: -   src/sys/dev/
   80:     - machine-independent device drivers
   81: -   src/sys/arch/
   82:     - port-specific or architecture-specific parts (such as the
   83:     low-level system initialisation procedures or machine-dependent
   84:     drivers)
   85: -   src/sys/arch/\$PORTNAME/conf/
   86:     - kernel configuration files for a given port
   87: 
   88: ### Kernel autoconfiguration framework - autoconf(9)
   89: 
   90: -   Autoconfiguration is the process of matching hardware devices with
   91:     an appropriate device driver
   92: -   The kernel message buffer (dmesg) contains information about
   93:     autoconfiguration of devices
   94: -   driver0 at bus0: Foo hardware
   95:     -   Instance 0 of the driver has attached to instance 0 of the
   96:         particular bus
   97:     -   Such messages often carry additional bus-specific information
   98:         about the exact location of the device (like the device and
   99:         function number on the PCI bus)
  100: -   driver0: some message
  101:     -   Additional information about the driver state or device
  102:         configuration
  103: 
  104: ### Autoconfiguration as seen in the dmesg
  105: 
  106:     NetBSD 6.99.12 (GENERIC) #7: Fri Oct  5 18:43:21 CEST 2012
  107:             rkujawa@saiko.local:/Users/rkujawa/netbsd-eurobsdcon2012/src/sys/arch/cobalt/compile/obj/GENERIC
  108:     Cobalt Qube 2
  109:     total memory = 32768 KB
  110:     avail memory = 27380 KB
  111:     mainbus0 (root)
  112:     com0 at mainbus0 addr 0x1c800000 level 3: ns16550a, working fifo
  113:     com0: console
  114:     cpu0 at mainbus0: QED RM5200 CPU (0x28a0) Rev. 10.0 with built-in FPU Rev. 1.0
  115:     cpu0: 48 TLB entries, 256MB max page size
  116:     cpu0: 32KB/32B 2-way set-associative L1 instruction cache
  117:     cpu0: 32KB/32B 2-way set-associative write-back L1 data cache
  118:     mcclock0 at mainbus0 addr 0x10000070: mc146818 compatible time-of-day clock
  119:     panel0 at mainbus0 addr 0x1f000000
  120:     gt0 at mainbus0 addr 0x14000000
  121:     pci0 at gt0
  122:     pchb0 at pci0 dev 0 function 0: Galileo GT-64011 System Controller, rev 1
  123:     pcib0 at pci0 dev 9 function 0
  124:     pcib0: VIA Technologies VT82C586 PCI-ISA Bridge, rev 57
  125:     viaide0 at pci0 dev 9 function 1
  126:     viaide0: VIA Technologies VT82C586 (Apollo VP) ATA33 controller
  127:     viaide0: primary channel interrupting at irq 14
  128:     atabus0 at viaide0 channel 0
  129:     viaide0: secondary channel interrupting at irq 15
  130:     atabus1 at viaide0 channel 1
  131:     wd0 at atabus0 drive 0
  132:     wd0: <netbsd-cobalt.img>
  133:     wd0: 750 MB, 1524 cyl, 16 head, 63 sec, 512 bytes/sect x 1536192 sectors
  134: 
  135: ### Autoconfiguration as seen in the dmesg
  136: 
  137: ![image](img_cobaltdevices.png)
  138: 
  139: ### The bus\_space(9) framework
  140: 
  141: -   “The goal of the bus\_space functions is to allow a single driver
  142:     source file to manipulate a set of devices on different system
  143:     architectures, and to allow a single driver object file to
  144:     manipulate a set of devices on multiple bus types on a single
  145:     architecture.”
  146: -   Provides a set of functions implementing common operations on the
  147:     bus like mapping, reading, writing, copying, etc.
  148: -   The bus\_space(9) is implemented at the machine-dependent level
  149:     (typically it’s a part of architecture-specific code), but all
  150:     implementations present the same interface[^1]
  151: 
  152: ### Machine independent drivers
  153: 
  154: -   If possible drivers should work on any hardware platform
  155: -   High quality, machine-independent (MI) drivers are an important
  156:     factor that adds to NetBSD portability
  157: -   Some drivers are completely MI, some have MD or bus dependent
  158:     attachments and some are completely MD
  159:     -   A driver for a typical PCI card will be completely MI
  160:     -   A driver for the components of a SoC will usually be completely
  161:         MD
  162: -   The bus\_space abstraction helps to achieve portability,
  163:     transparently handling endianness issues and hiding bus
  164:     implementation details from the device driver
  165: -   Even if we have MI drivers, writing the drivers is always
  166:     significant part of effort needed to port NetBSD to new hardware
  167: 
  168: ## Example driver from scratch
  169: 
  170: ### Development environment
  171: 
  172: -   Out of scope of this course, but very well documented
  173: -   Cross compiling is an easy task with the build.sh script
  174: -   Described in [Part V of the NetBSD
  175:     Guide](http://www.netbsd.org/docs/guide/en/part-compile.html)
  176: -   Check out the NetBSD sources
  177: -   \$ build.sh -m cobalt tools
  178:     will build compiler, assembler, linker, etc. for cobalt port
  179: -   \$ build.sh -m cobalt kernel=GENERIC
  180:     will build the GENERIC kernel for cobalt
  181: -   Call build.sh with a -u parameter to update (won’t rebuilding
  182:     everything)
  183: -   build.sh
  184:     is calling nbconfig and nbmake tools, no magic involved
  185: 
  186: ### Quick introduction to GXemul
  187: 
  188: -   A framework for full-system computer architecture emulation,
  189:     excellent for educational purposes
  190: -   Capable of emulating several real machines supported by NetBSD
  191: -   We’ll emulate a [Cobalt](http://en.wikipedia.org/wiki/Cobalt_Qube),
  192:     MIPS-based micro server with PCI bus
  193: -   I’ve modified GXemul and implemented an emulation of an additional
  194:     PCI device
  195: -   It will be used to show (almost) a real-life example of the driver
  196:     development process
  197: 
  198: ### Our hardware - functional description
  199: 
  200: -   Business applications often use arithmetic operations like addition
  201: -   Fake Cards Inc. responded to market needs and created a new product,
  202:     Advanced Addition Accelerator
  203: -   Pointy Haired Bosses will certainly buy it to accelerate their
  204:     business applications, so let’s create a driver for NetBSD!
  205: 
  206: ### Our hardware - technical details
  207: 
  208: -   Overview
  209:     -   Implemented as a PCI device
  210:     -   Arithmetic unit capable of addition of two numbers
  211:     -   Four[^2] registers in the PCI memory space
  212: -   PCI configuration space
  213:     -   Identified by the PCI vendor ID 0xfabc and product ID 0x0001
  214:     -   Base Address Register 0x10 used to configure the engine address
  215:     -   4 x 32-bit registers = 16 bytes
  216:     -   Other configuration registers irrelevant
  217: 
  218: ### Our hardware - technical details (memory mapped register set)
  219: 
  220: -   Advanced Addition Acceleration registers
  221: 
  222: <table>
  223: <tr><th>Register Name</th><th>Offset</th><th>Description</th></tr>
  224: <tr><td>COMMAND</td><td>0x4</td><td>Register used to issue commands to the engine</td></tr>
  225: <tr><td>DATA</td><td>0x8</td><td>Register used to load data to internal engine registers</td></tr>
  226: <tr><td>RESULT</td><td>0xC</td><td>Register used to store the result of arithmetic operation</td></tr>
  227: </table>
  228: 
  229: -   COMMAND register
  230: 
  231: <table>
  232: <tr><th>Bit</th><th>R/W</th><th>Description</th></tr>
  233: <tr><td>0</td><td>W</td><td>Execute ADD operation on values loaded into internal register A and B</td></tr>
  234: <tr><td>1</td><td>R/W</td><td>Select internal register A for access through DATA register</td></tr>
  235: <tr><td>2</td><td>R/W</td><td>Select internal register B for access through DATA register</td></tr>
  236: </table>
  237: 
  238: -   Selecting internal register A and B at the same time will lead to
  239:     undefined behaviour
  240: 
  241: ### Our hardware - technical details (memory mapped register set)
  242: 
  243: -   DATA register
  244: 
  245: <table>
  246: <tr><th>Bit</th><th>R/W</th><th>Description</th></tr>
  247: <tr><td>0:31</td><td>R/W</td><td>Read/write the value in internal engine register</td></tr>
  248: </table>
  249: 
  250: -   RESULT register
  251: 
  252: <table>
  253: <tr><th>Bit</th><th>R/W</th><th>Description</th></tr>
  254: <tr><td>0:31</td><td>R</td><td>Holds the result of last ADD operation</td></tr>
  255: </table>
  256: 
  257: ### Our hardware - technical details (operation algorithm)
  258: 
  259: -   Select the internal register A for access (write 0x2 into COMMAND
  260:     register)
  261: -   Write the first number into DATA register
  262: -   Select the internal register B for access (write 0x4 into COMMAND
  263:     register)
  264: -   Write the second number into DATA register
  265: -   Issue the ADD operation (write 0x1 into COMMAND register)
  266: -   Read the result from RESULT register
  267: 
  268: ### Adding a new driver to the NetBSD kernel
  269: 
  270: -   We’ll discuss the steps needed to add a new MI PCI device driver to
  271:     the NetBSD kernel
  272:     -   Add the vendor and device ID to the database of PCI IDs
  273:     -   Create a set of the driver source files in
  274:         src/sys/dev/\$BUSNAME/
  275:     -   Add the new driver to src/sys/dev/\$BUSNAME/\$BUSNAME.files file
  276:     -   Add the new driver to DEVNAMES[^3] file
  277: 
  278: ### Modifying the PCI device database
  279: 
  280:     unmatched vendor 0xfabc product 0x0001 (Co-processor 
  281:     processor, revision 0x01) at pci0 dev 12 function 0 
  282:     not configured
  283: 
  284: -   The kernel does not know anything about this vendor and device
  285: -   Add it to the PCI device database - src/sys/dev/pci/pcidevs
  286: -   vendor VENDORNAME 0xVENDORID Long Vendor Name
  287: -   product VENDORNAME PRODUCTNAME 0xPRODUCTID Long Product Name
  288: -   To regenerate pcidevs\*.h run awk -f devlist2h.awk pcidevs or
  289:     Makefile.pcidevs if you’re on NetBSD
  290: 
  291: ### Modifying the PCI device database - example
  292: 
  293:     --- pcidevs 29 Sep 2012 10:26:14 -0000  1.1139
  294:     +++ pcidevs 5 Oct 2012 08:52:59 -0000
  295:     @@ -669,6 +669,7 @@
  296:      vendor CHRYSALIS   0xcafe  Chrysalis-ITS
  297:      vendor MIDDLE_DIGITAL  0xdeaf  Middle Digital
  298:      vendor ARC     0xedd8  ARC Logic
  299:     +vendor FAKECARDS   0xfabc  Fake Cards
  300:      vendor INVALID     0xffff  INVALID VENDOR ID
  301:      
  302:      /*
  303:     @@ -2120,6 +2121,9 @@
  304:      /* Eumitcom products */
  305:      product EUMITCOM WL11000P  0x1100  WL11000P PCI WaveLAN/IEEE 802.11
  306:      
  307:     +/* FakeCards products */
  308:     +product FAKECARDS AAA      0x0001  Advanced Addition Accelerator
  309:     +
  310:      /* O2 Micro */
  311:      product O2MICRO 00F7       0x00f7  Integrated OHCI IEEE 1394 Host Controller
  312:      product O2MICRO OZ6729     0x6729  OZ6729 PCI-PCMCIA Bridge
  313: 
  314: ### Modifying the PCI device database - example
  315: 
  316:     Fake Cards Advanced Addition Accelerator (Co-processor 
  317:     processor, revision 0x01) at pci0 dev 12 function 0 
  318:     not configured
  319: 
  320: -   Now the kernel knows the vendor and product ID
  321: -   But there’s still no driver for this device
  322: 
  323: ### Adding the new PCI driver
  324: 
  325: -   Choose a name - short, easy to remember, avoid numbers
  326:     -   faa
  327:         looks like a good name, but you can choose any name you like
  328: -   Create a set of new files in src/sys/dev/pci
  329:     -   faa.c
  330:         - main driver code
  331:     -   faareg.h
  332:         - register definitions[^4]
  333:     -   faavar.h
  334:         - driver structures and functions used in other parts of the
  335:         kernel[^5]
  336: -   Modify driver definitions
  337:     -   src/sys/dev/pci/files.pci
  338:     -   src/sys/dev/DEVNAMES
  339: -   Configure the kernel to use the newly added driver -
  340:     src/sys/arch/\$PORTNAME/conf/GENERIC
  341: 
  342: ### Adding the new PCI driver - main driver
  343: 
  344: -   Kernel includes are at the beginning, followed by machine-specific
  345:     and bus-specific includes
  346: -   Should also include faareg.h and faavar.h files
  347: -   A minimal driver needs just two functions
  348:     -   faa\_match
  349:         (or faa\_probe for some buses)
  350:     -   faa\_attach
  351: -   The CFATTACH\_DECL\_NEW macro plugs the above functions into
  352:     autoconf(9) mechanism
  353: 
  354: ### Adding the new PCI driver - main driver
  355: 
  356: -   static int faa\_match(device\_t parent, cfdata\_t match, void
  357:     \*aux);
  358:     -   Check if the driver should attach to a given device (for example
  359:         in case of PCI bus, it will be used to check vendor and product
  360:         ID)
  361:     -   parent
  362:         - pointer to parent’s driver device structure
  363:     -   match
  364:         - pointer to autoconf(9) details structure
  365:     -   aux
  366:         - despite the name the most important argument, usually contains
  367:         bus-specific structure describing device details
  368: 
  369: -   static void faa\_attach(device\_t parent, device\_t self, void
  370:     \*aux);
  371:     -   Attach the driver to a given device
  372:     -   parent
  373:         - same as with match function
  374:     -   self
  375:         - pointer to driver’s device structure
  376:     -   aux
  377:         - same as with match function
  378: -   See definitions of these functions in the
  379:     [driver(9)](http://netbsd.gw.com/cgi-bin/man-cgi?driver+9+NetBSD-current)
  380:     man page.
  381: 
  382: ### Adding the new PCI driver - main driver cont’d
  383: 
  384: -   CFATTACH\_DECL\_NEW(faa, sizeof(struct faa\_softc), faa\_match,
  385:     faa\_attach, NULL, NULL);
  386:     -   driver name
  387:     -   size of softc structure containing state of driver’s instance
  388:     -   match/probe function
  389:     -   attach function
  390:     -   detach function
  391:     -   activate function
  392: -   The “\_NEW” name is unfortunate
  393: -   Pass NULL for unimplemented functions
  394: -   We won’t cover detach and activate now, as they are not needed for a
  395:     simple driver
  396: 
  397: ### Adding the new PCI driver - main driver example
  398: 
  399: -   src/sys/dev/pci/faa.c
  400: 
  401: <!-- -->
  402: 
  403:     #include <sys/cdefs.h>
  404:     __KERNEL_RCSID(0, "$NetBSD: bus_space_tutorial.mdwn,v 1.4 2013/06/23 14:34:32 mspo Exp $");
  405:     #include <sys/param.h>
  406:     #include <sys/device.h>
  407:     #include <dev/pci/pcivar.h>
  408:     #include <dev/pci/pcidevs.h>
  409:     #include <dev/pci/faareg.h>
  410:     #include <dev/pci/faavar.h>
  411: 
  412:     static int      faa_match(device_t, cfdata_t, void *);
  413:     static void     faa_attach(device_t, device_t, void *);
  414: 
  415:     CFATTACH_DECL_NEW(faa, sizeof(struct faa_softc),
  416:         faa_match, faa_attach, NULL, NULL);
  417: 
  418:     static int
  419:     faa_match(device_t parent, cfdata_t match, void *aux)
  420:     {
  421:             return 0;
  422:     }
  423: 
  424:     static void
  425:     faa_attach(device_t parent, device_t self, void *aux)
  426:     { 
  427:     }
  428: 
  429: ### Adding the new PCI driver - auxiliary includes
  430: 
  431: -   src/sys/dev/pci/faareg.h
  432: 
  433: <!-- -->
  434: 
  435:     #ifndef FAAREG_H
  436:     #define FAAREG_H
  437:     /* 
  438:      * Registers are defined using preprocessor:
  439:      * #define FAA_REGNAME  0x0
  440:      * We'll add them later, let's leave it empty for now.
  441:      */
  442:     #endif /* FAAREG_H */
  443: 
  444: -   src/sys/dev/pci/faavar.h
  445: 
  446: <!-- -->
  447: 
  448:     #ifndef FAAVAR_H
  449:     #define FAAVAR_H
  450: 
  451:     /* sc_dev is an absolute minimum, we'll add more later */
  452:     struct faa_softc {
  453:             device_t sc_dev;
  454:     };
  455:     #endif /* FAAVAR_H */
  456: 
  457: ### Adding the new PCI driver - registering the driver (courtesy)
  458: 
  459: -   src/sys/dev/DEVNAMES
  460: 
  461: <!-- -->
  462: 
  463:     --- DEVNAMES    1 Sep 2012 11:19:58 -0000   1.279
  464:     +++ DEVNAMES    6 Oct 2012 19:59:06 -0000
  465:     @@ -436,6 +436,7 @@
  466:      ex         MI
  467:      exphy          MI
  468:      ezload         MI      Attribute
  469:     +faa            MI
  470:      fb         luna68k
  471:      fb         news68k
  472:      fb         newsmips
  473: 
  474: ### Adding the new PCI driver - registering the driver
  475: 
  476: -   See config(5)
  477: -   src/sys/dev/pci/files.pci
  478: 
  479: <!-- -->
  480: 
  481:     --- pci/files.pci   2 Aug 2012 00:17:44 -0000   1.360
  482:     +++ pci/files.pci   6 Oct 2012 19:59:10 -0000
  483:     @@ -1122,3 +1122,9 @@
  484:      device tdvfb: wsemuldisplaydev, rasops8, vcons, videomode
  485:      attach tdvfb at pci
  486:      file   dev/pci/tdvfb.c     tdvfb   
  487:     +
  488:     +# FakeCards Advanced Addition Accelerator
  489:     +device faa
  490:     +attach faa at pci
  491:     +file   dev/pci/faa.c       faa 
  492:     +
  493: 
  494: ### Adding the new PCI driver to the kernel configuration
  495: 
  496: -   src/sys/arch/cobalt/conf/GENERIC
  497: 
  498: <!-- -->
  499: 
  500:     --- GENERIC 10 Mar 2012 21:51:50 -0000  1.134
  501:     +++ GENERIC 6 Oct 2012 20:12:37 -0000
  502:     @@ -302,6 +302,9 @@
  503:      #fms*      at pci? dev ? function ?    # Forte Media FM801
  504:      #sv*       at pci? dev ? function ?    # S3 SonicVibes
  505:      
  506:     +# Fake Cards Advanced Addition Accelerator
  507:     +faa*       at pci? dev ? function ?
  508:     +
  509:      # Audio support
  510:      #audio*        at audiobus?
  511: 
  512: -   The above definition means that an instance of faa may be attached
  513:     to any PCI bus, any device, any function
  514: -   The exact position of the rule in the configuration file is not
  515:     important in this case
  516: -   See
  517:     [config(5)](http://netbsd.gw.com/cgi-bin/man-cgi?config+5+NetBSD-current)
  518:     for a description of the device definition language
  519: 
  520: ### Adding the new PCI driver - example
  521: 
  522: -   The driver should compile now
  523: -   The driver’s match function will check if the driver is able to work
  524:     with a given device
  525: -   Since it is not implemented, the kernel will not attach the driver
  526: 
  527: ### Matching the PCI device
  528: 
  529: -   Modify the faa\_match function to match the specified PCI device
  530: -   Use PCI\_VENDOR and PCI\_PRODUCT macros to obtain the IDs
  531: 
  532: <!-- -->
  533: 
  534:     static int
  535:     faa_match(device_t parent, cfdata_t match, void *aux)
  536:     {
  537:             const struct pci_attach_args *pa = (const struct pci_attach_args *)aux;
  538: 
  539:             if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FAKECARDS) 
  540:                 && (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FAKECARDS_AAA))
  541:                     return 1;
  542: 
  543:             return 0;
  544:     }
  545: 
  546: ### Attaching to the PCI device
  547: 
  548:     faa0 at pci0 dev 12 function 0
  549: 
  550: -   The driver has successfully matched and attached to the PCI device
  551:     but still is not doing anything useful
  552: -   Let’s fill the attach function and actually program the hardware
  553: 
  554: ### Variable types used with bus\_space
  555: 
  556: -   bus\_space\_tag\_t
  557: 
  558:     – type used to describe a particular bus, usually passed to the
  559:     driver from MI bus structures
  560: 
  561: -   bus\_space\_handle\_t
  562: 
  563:     – used to describe a mapped range of bus space, usually created with
  564:     the bus\_space\_map() function
  565: 
  566: -   bus\_addr\_t
  567: 
  568:     – address on the bus
  569: 
  570: -   bus\_size\_t
  571: 
  572:     – an amount of space on the bus
  573: 
  574: -   Contents of these types are MD, so avoid modifying from within the
  575:     driver[^6]
  576: 
  577: ### Why do we need to “map” the resources?
  578: 
  579: -   “The bus space must be mapped before it can be used, and should be
  580:     unmapped when it is no longer needed”
  581: -   It’s a machine-dependent process but it’s also conveniently hidden
  582:     from the programmer by the bus\_space framework
  583: 
  584: ### Mapping the hardware resources
  585: 
  586: -   The generic bus\_space(9) way to map space
  587: 
  588: <!-- -->
  589: 
  590:     bus_space_map(bus_space_tag_t space, bus_addr_t address, 
  591:     bus_size_t size, int flags, bus_space_handle_t  *handlep);
  592: 
  593: -   bus\_space\_map
  594: 
  595:     creates a mapping from the physical address to a kernel virtual
  596:     address
  597: 
  598: -   space
  599: 
  600:     – represents the bus on which the mapping will be created
  601: 
  602: -   address
  603: 
  604:     – typically represents the physical address for which a mapping will
  605:     be created
  606: 
  607: -   size
  608: 
  609:     – describes the amount of bus space to be mapped
  610: 
  611: -   handlep
  612: 
  613:     – pointer to mapped space (filled after successful mapping)
  614: 
  615: -   Separate space and address
  616: 
  617: ### Mapping the hardware resources
  618: 
  619: -   The PCI-specific way to map space
  620: 
  621: <!-- -->
  622: 
  623:     pci_mapreg_map(const struct pci_attach_args *pa, int reg, pcireg_t type, 
  624:     int busflags, bus_space_tag_t *tagp, bus_space_handle_t *handlep, 
  625:     bus_addr_t *basep, bus_size_t *sizep);
  626: 
  627: -   pci\_mapreg\_map
  628: 
  629:     creates mapping from physical address present in specified BAR
  630:     register to kernel virtual address
  631: 
  632: -   pa
  633: 
  634:     – struct describing PCI attachment details (passed through aux)
  635: 
  636: -   reg
  637: 
  638:     – BAR register number
  639: 
  640: -   type
  641: 
  642:     – Select mapping type (I/O, memory)
  643: 
  644: -   busflags
  645: 
  646:     – Passed to bus\_space\_map flags argument
  647: 
  648: -   tagp
  649: 
  650:     – pointer to bus\_space\_tag
  651: 
  652: -   handlep
  653: 
  654:     – pointer to a mapped space
  655: 
  656: -   basep
  657: 
  658:     – address of a mapped space
  659: 
  660: -   sizep
  661: 
  662:     – size of mapped space (equivalent to BAR size)
  663: 
  664: -   The last four parameters are filled after successful mapping
  665: 
  666: ### Mapping the registers using BAR - adding auxiliary includes
  667: 
  668: -   src/sys/dev/pci/faareg.h
  669: 
  670: <!-- -->
  671: 
  672:     #define FAA_MMREG_BAR   0x10
  673: 
  674: -   src/sys/dev/pci/faavar.h
  675: 
  676: <!-- -->
  677: 
  678:     struct faa_softc {
  679:             device_t sc_dev;
  680: 
  681:             bus_space_tag_t sc_regt;
  682:             bus_space_handle_t sc_regh;
  683:             bus_addr_t sc_reg_pa;
  684: 
  685:     };
  686: 
  687: ### Mapping the registers using BAR - main driver code
  688: 
  689: -   src/sys/dev/pci/faa.c
  690: 
  691: <!-- -->
  692: 
  693:     static void
  694:     faa_attach(device_t parent, device_t self, void *aux)
  695:     {
  696:             struct faa_softc *sc = device_private(self);
  697:             const struct pci_attach_args *pa = aux;
  698: 
  699:             sc->sc_dev = self;
  700: 
  701:             pci_aprint_devinfo(pa, NULL);
  702: 
  703:             if (pci_mapreg_map(pa, FAA_MMREG_BAR, PCI_MAPREG_TYPE_MEM, 0, 
  704:                 &sc->sc_regt, &sc->sc_regh, &sc->sc_reg_pa, 0) != 0 ) {
  705:                 aprint_error_dev(sc->sc_dev, "can't map the BAR\n");
  706:                 return;
  707:             }
  708: 
  709:             aprint_normal_dev(sc->sc_dev, "regs at 0x%08x\n", (uint32_t) sc->sc_reg_pa);
  710:     }
  711: 
  712: ### Accessing the hardware registers
  713: 
  714: -   The bus\_space\_read\_ and bus\_space\_write\_ functions are basic
  715:     methods of reading and writing the hardware registers
  716: 
  717: -   uintX\_t bus\_space\_read\_X(bus\_space\_tag\_t space,
  718:     bus\_space\_handle\_t handle, bus\_size\_t offset);
  719: 
  720: -   void bus\_space\_write\_X(bus\_space\_tag\_t space,
  721:     bus\_space\_handle\_t handle, bus\_size\_t offset, uintX\_t value);
  722: 
  723:     -   space
  724: 
  725:         - tag describing the bus
  726: 
  727:     -   handle
  728: 
  729:         - describes the exact location on the bus where read/write
  730:         should occur, this handle is obtained by bus\_space\_map
  731: 
  732:     -   offset
  733: 
  734:         - offset from handle location
  735: 
  736:     -   The read function returns the data read from the specified
  737:         location, while write has an argument value which should be
  738:         filled with data to be written
  739: 
  740: ### Variants of bus\_space\_read and bus\_space\_write
  741: 
  742:     Data       Read function         Write function
  743:   -------- --------------------- ----------------------
  744:    8-bit    bus\_space\_read\_1   bus\_space\_write\_1
  745:    16-bit   bus\_space\_read\_2   bus\_space\_write\_2
  746:    32-bit   bus\_space\_read\_4   bus\_space\_write\_4
  747:    64-bit   bus\_space\_read\_8   bus\_space\_write\_8
  748: 
  749: -   There are many more variants of read and write functions and they
  750:     are useful in certain situations, see the
  751:     [bus\_space(9)](http://netbsd.gw.com/cgi-bin/man-cgi?bus_space++NetBSD-current)
  752:     man page
  753: 
  754: ### Accessing the hardware registers - example
  755: 
  756: -   Create a function that will write a value into the DATA register of
  757:     our device, then read it back and check if the value is the same as
  758:     written
  759: 
  760: -   Define the DATA register in the driver
  761: 
  762: -   src/sys/dev/pci/faareg.h
  763: 
  764: <!-- -->
  765: 
  766:     #define FAA_DATA                0x8
  767:     #define FAA_COMMAND             0x4
  768:     #define FAA_COMMAND_STORE_A         __BIT(1)
  769: 
  770: -   Define the new function in main driver code
  771: 
  772: -   static bool faa\_check(struct faa\_softc \*sc);
  773: 
  774: ### Accessing the hardware registers - example
  775: 
  776: -   src/sys/dev/pci/faa.c
  777: 
  778: <!-- -->
  779: 
  780:     static void
  781:     faa_attach(device_t parent, device_t self, void *aux)
  782:     {
  783:        /* ... */
  784:        if (!faa_check(sc)) {
  785:             aprint_error_dev(sc->sc_dev, "hardware not responding\n");
  786:             return;
  787:        }
  788:     }
  789: 
  790:     static bool
  791:     faa_check(struct faa_softc *sc)
  792:     {
  793:             uint32_t testval = 0xff11ee22; 
  794:             bus_space_write_4(sc->sc_regt, sc->sc_regh, FAA_COMMAND, FAA_COMMAND_STORE_A);
  795:             bus_space_write_4(sc->sc_regt, sc->sc_regh, FAA_DATA, testval);
  796:             if (bus_space_read_4(sc->sc_regt, sc->sc_regh, FAA_DATA) == testval)
  797:                     return true;
  798: 
  799:             return false;
  800:     }
  801: 
  802: ### Accessing the hardware registers - running the example
  803: 
  804: -   Update the kernel binary and run it again
  805: 
  806: -   Check the GXemul log
  807: 
  808: <!-- -->
  809: 
  810:     [ faa: COMMAND register (0x4) WRITE value 0x2 ]
  811:     [ faa: DATA register (0x8) WRITE value 0xff11ee22 ]
  812:     [ faa: DATA register (0x8) READ value 0xff11ee22 ]
  813: 
  814: -   GXemul will conveniently display all accesses to our device
  815: 
  816: -   The faa driver still does attach without error, which means that the
  817:     check function is working properly
  818: 
  819: <!-- -->
  820: 
  821:     faa0 at pci0 dev 12 function 0: Fake Cards Advanced Addition Accelerator (rev. 0x01)
  822:     faa0: registers at 0x10110000
  823: 
  824: ### Implementing addition using the hardware
  825: 
  826: -   The basic principle of device operation should be laid out in the
  827:     data sheet
  828: 
  829: -   We need to implement an algorithm based on this description
  830: 
  831: -   Writing such an algorithm is often not needed, since the NetBSD
  832:     kernel already has frameworks for common device types (such as
  833:     atabus/wd for IDE and SATA hard disk controllers, wsdisplay/wscons
  834:     for frame buffers, etc.)
  835: 
  836: ### Implementing addition using the hardware
  837: 
  838: -   Define all registers
  839: 
  840: -   src/sys/dev/pci/faareg.h
  841: 
  842: <!-- -->
  843: 
  844:     #define FAA_STATUS              0x0
  845:     #define FAA_COMMAND             0x4
  846:     #define FAA_COMMAND_ADD             __BIT(0)        
  847:     #define FAA_COMMAND_STORE_A         __BIT(1)
  848:     #define FAA_COMMAND_STORE_B         __BIT(2)
  849:     #define FAA_DATA                0x8
  850:     #define FAA_RESULT              0xC
  851: 
  852: ### Implementing addition using the hardware
  853: 
  854: -   Add a new function to the main driver code
  855: 
  856: -   src/sys/dev/pci/faa.c
  857: 
  858: <!-- -->
  859: 
  860:     static void
  861:     faa_attach(device_t parent, device_t self, void *aux)
  862:     {
  863:             /* ... */
  864:             aprint_normal_dev(sc->sc_dev, "just checking: 1 + 2 = %d\n", faa_add(sc, 1, 2));
  865:     }
  866: 
  867:     static uint32_t
  868:     faa_add(struct faa_softc *sc, uint32_t a, uint32_t b)
  869:     {
  870:             bus_space_write_4(sc->sc_regt, sc->sc_regh, FAA_COMMAND, FAA_COMMAND_STORE_A);
  871:             bus_space_write_4(sc->sc_regt, sc->sc_regh, FAA_DATA, a);
  872:             bus_space_write_4(sc->sc_regt, sc->sc_regh, FAA_COMMAND, FAA_COMMAND_STORE_B);
  873:             bus_space_write_4(sc->sc_regt, sc->sc_regh, FAA_DATA, b);
  874:             bus_space_write_4(sc->sc_regt, sc->sc_regh, FAA_COMMAND, FAA_COMMAND_ADD);
  875:             return bus_space_read_4(sc->sc_regt, sc->sc_regh, FAA_RESULT);
  876:     }
  877: 
  878: ### Implementing addition using the hardware - running the example
  879: 
  880: -   Update the kernel binary and run it again
  881: 
  882: -   Check GXemul log
  883: 
  884: <!-- -->
  885: 
  886:     [ faa: COMMAND register (0x4) WRITE value 0x2 ]
  887:     [ faa: DATA register (0x8) WRITE value 0x1 ]
  888:     [ faa: COMMAND register (0x4) WRITE value 0x4 ]
  889:     [ faa: DATA register (0x8) WRITE value 0x2 ]
  890:     [ faa: COMMAND register (0x4) WRITE value 0x1 ]
  891:     [ faa: RESULT register (0xC) READ value 0x3 ]
  892: 
  893: -   Looks like it worked!
  894: 
  895: <!-- -->
  896: 
  897:     faa0 at pci0 dev 12 function 0: Fake Cards Advanced Addition Accelerator (rev. 0x01)
  898:     faa0: registers at 0x10110000
  899:     faa0: just checking: 1 + 2 = 3
  900: 
  901: ## Interacting with userspace
  902: 
  903: ### The kernel-user space interface
  904: 
  905: -   Now that the core functionality of the kernel driver is working, it
  906:     should be exposed to user space
  907: -   The interface between kernel driver and userspace can be designed in
  908:     many different ways
  909: -   The classic UNIX way of interfacing between the kernel and user
  910:     space is a device file
  911: -   Even when using device files there is no single interfacing method
  912:     that fits all use cases
  913: -   It’s up to the programmer to define the communication protocol
  914: 
  915: ### Device files
  916: 
  917: -   crw-r—– 1 root wheel 101, 1 Aug 12 21:53 /dev/file
  918: -   The kernel identifies which driver should service the request to
  919:     this file by using major and minor numbers (101 and 1 in the example
  920:     above)
  921: -   The major number identifies the driver
  922: -   The minor number usually identifies the driver instance, although
  923:     the driver is free to use it in any other way
  924: -   In NetBSD device files are created statically
  925:     -   By the MAKEDEV script during installation or boot
  926:     -   Manually by using the mknod utility
  927: 
  928: ### Operations on device files
  929: 
  930: -   [open(2)](http://netbsd.gw.com/cgi-bin/man-cgi?read++NetBSD-current)
  931:     and
  932:     [close(2)](http://netbsd.gw.com/cgi-bin/man-cgi?read++NetBSD-current)
  933: -   [read(2)](http://netbsd.gw.com/cgi-bin/man-cgi?read++NetBSD-current)
  934:     and
  935:     [write(2)](http://netbsd.gw.com/cgi-bin/man-cgi?write++NetBSD-current)
  936: -   [ioctl(2)](http://netbsd.gw.com/cgi-bin/man-cgi?write++NetBSD-current)
  937: -   [poll(2)](http://netbsd.gw.com/cgi-bin/man-cgi?poll++NetBSD-current)
  938: -   [mmap(2)](http://netbsd.gw.com/cgi-bin/man-cgi?write++NetBSD-current)
  939: -   and more…
  940: -   Any mix of the above system calls might be used to interface between
  941:     the kernel and user space
  942: -   We’ll implement an ioctl(2)-based communication mechanism
  943: 
  944: ### Adding cdevsw
  945: 
  946: -   cdevsw
  947: 
  948:     is used to decide which operation on the character device file calls
  949:     which driver function
  950: 
  951: -   Not all calls have to be implemented, although some device layers
  952:     define a set of calls that a driver must implement
  953: 
  954: -   For example disk drivers must implement open, close, read, write and
  955:     ioctl
  956: 
  957: -   src/sys/dev/pci/faa.c
  958: 
  959: <!-- -->
  960: 
  961:     dev_type_open(faaopen);
  962:     dev_type_close(faaclose);
  963:     dev_type_ioctl(faaioctl);
  964: 
  965:     const struct cdevsw faa_cdevsw = {
  966:             faaopen, faaclose, noread, nowrite, faaioctl,
  967:             nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
  968:     };
  969: 
  970: ### Prototyping the cdevsw operations
  971: 
  972: -   The dev\_type\* macros are used to prototype the functions passed to
  973:     cdevsw
  974: -   Pass no followed by a function name to the appropriate cdevsw field
  975:     if it is not implemented
  976: -   There’s also bdevsw for block devices, but we won’t use it in this
  977:     example
  978: -   The last member of the cdevsw structure defines the device flags,
  979:     originally it was used to define the device type (still used for
  980:     disks, tape drives and ttys, for other devices pass D\_OTHER)
  981: 
  982: ### Implemeting the cdevsw operations - open / close
  983: 
  984: -   src/sys/dev/pci/faa.c
  985: 
  986: <!-- -->
  987: 
  988:     int
  989:     faaopen(dev_t dev, int flags, int mode, struct lwp *l)
  990:     {
  991:             struct faa_softc *sc;
  992:             sc = device_lookup_private(&faa_cd, minor(dev));
  993: 
  994:             if (sc == NULL)
  995:                     return ENXIO;
  996:             if (sc->sc_flags & FAA_OPEN)
  997:                     return EBUSY;
  998: 
  999:             sc->sc_flags |= FAA_OPEN;
 1000:             return 0;
 1001:     }
 1002:     int
 1003:     faaclose(dev_t dev, int flag, int mode, struct lwp *l)
 1004:     {
 1005:             struct faa_softc *sc;
 1006:             sc = device_lookup_private(&faa_cd, minor(dev));
 1007: 
 1008:             if (sc->sc_flags & FAA_OPEN)
 1009:                     sc->sc_flags =~ FAA_OPEN;
 1010: 
 1011:             return 0;
 1012:     }
 1013: 
 1014: ### Defining the ioctls
 1015: 
 1016: -   ioctl(2)
 1017: 
 1018:     can be used to call kernel-level functions and exchange data between
 1019:     the kernel and user space
 1020: 
 1021: -   The classic way of passing data is by using structures, their
 1022:     definitions are shared between the kernel and user space code
 1023: -   The driver might support more than one ioctl, the \_IO\* macros are
 1024:     used to define the operation and associated structure used to
 1025:     exchange data
 1026: 
 1027:     -   \_IO
 1028: 
 1029:         - just a kernel function call, no data exchange
 1030: 
 1031:     -   \_IOR
 1032: 
 1033:         - kernel function call and data pass from kernel to user space
 1034: 
 1035:     -   \_IOW
 1036: 
 1037:         - kernel function call and data pass from user space to kernel
 1038: 
 1039:     -   \_IOWR
 1040: 
 1041:         - kernel function call and data exchange in both directions
 1042: 
 1043:     -   \#define DRIVERIO\_IOCTLNAME \_IOXXX(group, ioctl\_number, data
 1044:         structure)
 1045: 
 1046: ## Using ioctls
 1047: 
 1048: ### Defining the ioctls
 1049: 
 1050: -   src/sys/dev/pci/faaio.h
 1051: 
 1052: <!-- -->
 1053: 
 1054:     #include <sys/ioccom.h>
 1055:                          
 1056:     #define FAAIO_ADD   _IOWR(0, 1, struct faaio_add)
 1057: 
 1058:     struct faaio_add {
 1059:         uint32_t a;
 1060:         uint32_t b;
 1061:         uint32_t *result;
 1062:     };
 1063: 
 1064: -   In the above example the ioctl group is not defined (0), but a
 1065:     single letter identifier could appear as first argument to \_IOWR
 1066: 
 1067: ### Implemeting the cdevsw operations - ioctl
 1068: 
 1069: -   src/sys/dev/pci/faa.c
 1070: 
 1071: <!-- -->
 1072: 
 1073:     int
 1074:     faaioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
 1075:     {
 1076:             struct faa_softc *sc = device_lookup_private(&faa_cd, minor(dev));
 1077:             int err;
 1078: 
 1079:             switch (cmd) {
 1080:             case FAAIO_ADD:
 1081:                     err = faaioctl_add(sc, (struct faaio_add *) data);
 1082:                     break;
 1083:             default:
 1084:                     err = EINVAL;
 1085:                     break;
 1086:             }
 1087:             return(err);
 1088:     }
 1089:     static int
 1090:     faaioctl_add(struct faa_softc *sc, struct faaio_add *data)
 1091:     {
 1092:             uint32_t result; int err;
 1093: 
 1094:             aprint_normal_dev(sc->sc_dev, "got ioctl with a %d, b %d\n",
 1095:                 data->a, data->b);
 1096: 
 1097:             result = faa_add(sc, data->a, data->b);
 1098:             err = copyout(&result, data->result, sizeof(uint32_t));
 1099:             return err;
 1100:     }
 1101: 
 1102: ### Using copyout to pass data to userspace
 1103: 
 1104: -   The copy(9) functions are used to copy kernel space data from/to
 1105:     user space
 1106: -   copyout(kernel\_address, user space\_address, size);
 1107: -   Actually on Cobalt we could just do data-\>result = faa\_add();
 1108:     instead of calling the copyout function, but that is a bad idea
 1109: -   Some architectures (such as sparc64) have totally separate kernel
 1110:     and user address spaces $ \implies $ user space addresses are
 1111:     meaningless in the kernel
 1112: 
 1113: ### Defining device major number
 1114: 
 1115: -   Device major numbers for hardware drivers are usually defined in a
 1116:     per-port manner[^7]
 1117: -   src/sys/arch/\$PORTNAME/conf/majors.\$PORTNAME
 1118: -   src/sys/arch/cobalt/conf/majors.cobalt
 1119: -   The following defines a new character device file called /dev/faa\*
 1120:     with major number 101, but only if the faa driver is included in the
 1121:     kernel (last argument)
 1122: -   device-major faa char 101 faa
 1123: 
 1124: ### Creating the device node
 1125: 
 1126: -   The mknod utility can be used to create the device file manually
 1127: -   The driver name can be specified instead of the major number - it
 1128:     will be automatically resolved into the correct major number
 1129: -   mknod name [b | c] [major | driver] minor
 1130: -   mknod /dev/faa0 c faa 0
 1131: -   Created successfully
 1132: -   crw-r–r– 1 root wheel 101, 0 Oct 8 2012 /dev/faa0
 1133: 
 1134: ### An example user space program
 1135: 
 1136: -   The example program will open the device file and call ioctl(2) on
 1137:     it
 1138: -   As simple as possible, just to show how communication is done
 1139: -   Using ioctls from the user space
 1140:     -   Open the device file with O\_RDWR
 1141:     -   Call ioctl(2) with the operation number and structure as
 1142:         parameters
 1143: 
 1144: ### An example user space program - source
 1145: 
 1146:     void add(int, uint32_t, uint32_t);
 1147: 
 1148:     static const char* faa_device = "/dev/faa0";
 1149: 
 1150:     int
 1151:     main(int argc, char *argv[])
 1152:     {
 1153:             int devfd;
 1154: 
 1155:             if (argc != 3) {
 1156:                     printf("usage: %s a b\n", argv[0]);
 1157:                     return 1;
 1158:             }
 1159:             if ( (devfd = open(faa_device, O_RDWR)) == -1) {
 1160:                     perror("can't open device file");
 1161:                     return 1;
 1162:             }
 1163: 
 1164:             add(devfd, atoi(argv[1]), atoi(argv[2]));
 1165: 
 1166:             close(devfd);
 1167:             return 0;
 1168:     }
 1169: 
 1170: ### An example user space program - source
 1171: 
 1172:     void
 1173:     add(int devfd, uint32_t a, uint32_t b)
 1174:     {
 1175:             struct faaio_add faaio;
 1176:             uint32_t result = 0;
 1177: 
 1178:             faaio.result = &result;
 1179:             faaio.a = a;
 1180:             faaio.b = b;
 1181: 
 1182:             if (ioctl(devfd, FAAIO_ADD, &faaio) == -1) {
 1183:                     perror("ioctl failed");
 1184:             }
 1185:             printf("%d\n", result);
 1186:     }
 1187: 
 1188: ### An example user space program - running it
 1189: 
 1190:     # make
 1191:     cc -o aaa_add aaa_add.c
 1192:     # ./aaa_add 3 7
 1193:     faa0: got ioctl with a 3, b 7
 1194:     10
 1195: 
 1196: -   The program is successfully accessing the faa driver through the
 1197:     ioctl
 1198: -   The faa0:... line is a kernel message, normally only seen on the
 1199:     console terminal
 1200: 
 1201: ## A few tips
 1202: 
 1203: ### Avoiding common pitfalls
 1204: 
 1205: -   Always free resources allocated in the match or probe functions
 1206: -   Always use bus\_space methods, don’t access the hardware using a
 1207:     pointer dereference
 1208: -   If possible test on more than one hardware architecture, some bugs
 1209:     may surface
 1210: -   Don’t reinvent the wheel, try to use existing kernel frameworks as
 1211:     much as possible
 1212: -   Use copy(9) (or uiomove(9) or store(9)/fetch(9)) to move data
 1213:     between the kernel and user space
 1214: 
 1215: ### Basic driver debugging
 1216: 
 1217: -   Use aprint\_debug to print debug-level messages on console and log
 1218:     them (enabled by passing AB\_DEBUG from the boot loader)
 1219: -   Use the built-in DDB debugger
 1220:     -   Enabled by the kernel option DDB
 1221:     -   A kernel panic will start DDB if the DDB\_ONPANIC=1 kernel
 1222:         option is specified or the ddb.onpanic sysctl is set to 1.
 1223:     -   Run \# sysctl -w kern.panic\_now=1 to trigger a panic manually
 1224:         (DIAGNOSTIC option)
 1225: -   Remote debugging is possible on some ports
 1226:     -   With KGDB through the serial port
 1227:     -   With IPKDB through the network
 1228: 
 1229: ## Summary
 1230: 
 1231: ### Further reading
 1232: 
 1233: -   Documentation, articles:
 1234:     -   [A Machine-Independent DMA Framework for NetBSD, Jason R.
 1235:         Thorpe](http://www.netbsd.org/docs/kernel/bus_dma.pdf)
 1236:     -   [Writing Drivers for NetBSD, Jochen
 1237:         Kunz](ftp://ftp.netbsd.org/pub/NetBSD/misc/ddwg/NetBSD-driver_writing-1.0.1e.pdf)
 1238:     -   [NetBSD Documentation: Writing a pseudo
 1239:         device](http://www.netbsd.org/docs/kernel/pseudo/)
 1240:     -   [autoconf(9)](http://netbsd.gw.com/cgi-bin/man-cgi?autoconf+9+NetBSD-current),
 1241:         [bus\_space(9)](http://netbsd.gw.com/cgi-bin/man-cgi?bus_space+9+NetBSD-current)
 1242:         [bus\_dma(9)](http://netbsd.gw.com/cgi-bin/man-cgi?bus_dma+9+NetBSD-current)
 1243:         [driver(9)](http://netbsd.gw.com/cgi-bin/man-cgi?driver+9+NetBSD-current),
 1244:         [pci(9)](http://netbsd.gw.com/cgi-bin/man-cgi?pci+9+NetBSD-current)
 1245:         man pages, etc.
 1246: 
 1247: -   Example source code of drivers:
 1248:     -   tdvfb
 1249: 
 1250:         voodoofb are fairly good frame buffer driver examples with
 1251:         documentation publicly available.
 1252: 
 1253:     -   etsec
 1254: 
 1255:         is a nice example of a more complicated network interface driver
 1256: 
 1257: ### Get the source code
 1258: 
 1259: -   Download the source code and materials for this tutorial
 1260: -   <https://github.com/rkujawa/busspace-tutorial>
 1261: -   <https://github.com/rkujawa/gxemul-tutorial>
 1262: 
 1263: ### Questions?
 1264: 
 1265: -   Do you have any questions?
 1266: 
 1267: ### The End…
 1268: 
 1269: ![image](NetBSD.png)
 1270: 
 1271: Thank you!
 1272: 
 1273: [^1]: At least they should, some functions are missing on less popular
 1274:     ports
 1275: 
 1276: [^2]: Only three of these registers are of any importance for us at this
 1277:     moment
 1278: 
 1279: [^3]: Required if you are NetBSD developer, optional otherwise.
 1280: 
 1281: [^4]: Might not exist if the driver is only a simple passthrough from a
 1282:     specific bus to another MI driver.
 1283: 
 1284: [^5]: Omitted if not needed.
 1285: 
 1286: [^6]: although you’ll often have to use bus\_size\_t
 1287: 
 1288: [^7]: It’s also possible to define a major in a machine-independent way
 1289:     in src/sys/conf/majors

CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb