File:  [NetBSD Developer Wiki] / wikisrc / tutorials / bus_space_tutorial.mdwn
Revision 1.1: download - view: text, annotated - select for diffs
Sun Jun 23 13:59:13 2013 UTC (8 years, 5 months ago) by mspo
Branches: MAIN
CVS tags: HEAD
add bus space tutorial from rkujawa

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

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