Annotation of wikisrc/tutorials/bus_space_tutorial.mdwn, revision 1.1

1.1     ! mspo        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$");
        !           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