From 30f7fc408b9320f9b5b25060abd546d15a80ae16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Axel=20D=C3=B6rfler?= This document tries to give you a short introduction into the new device
+manager, and how to write drivers for it. Haiku still supports the legacy
+device driver architecture introduced with BeOS. The new device driver architecture of Haiku is still a moving target,
+although most of its details are already specificed. The device manager functionality builds upon device_node objects.
+Every driver in the system publishes one or more of such nodes, building a
+tree of device nodes. This tree is in theory a dynamic representation of the
+current hardware devices in the system, but in practice will also contain
+implementation specific details; since every node comes with an API specific
+to that node, you'll find device nodes that only come with a number of support
+functions for a certain class of drivers. Structurally, a device_node is a set of a module, attributes,
+and resources, as well as a parent and children. At a minimum, a node must
+have a module, all other components are optional. When the system starts, there is only a root node registered. Only primary
+hardware busses register with the root node, such as PCI, and ISA on x86.
+Since the PCI bus is an intelligent bus, it knows what hardware is installed,
+and registers a child node for each device on the bus. Every driver can also publish a device in /dev for communication with
+userland applications. All drivers and devices are kernel modules. So how does it all work? When building the initial device tree, the system only
+explores a minimum of device drivers only, resulting in a tree that basically
+only shows the hardware found in the computer. Now, if the system requires disk access, it will scan the device file system
+for a driver that provides such functionality, in this case, it will look for
+drivers under "/dev/disk/". The device manager has a set of built-in rules for
+how to translate a device path into a device node, and vice versa: every node
+representing a device of an intelligent bus (such as PCI) will also contain
+device type information following the PCI definitions. In this case, the "disk"
+sub-path will translate into the PCI_mass_storage type, and hence, the
+device manager will then completely explore all device nodes of that type. It will also use that path information to only ask drivers that actually
+are in a matching module directory. In the above example of a disk driver, this
+would be either in "busses/scsi", "busses/ide", "drivers/disk", ... The device manager assumes the following API from a driver module: To ensure that a module exports this API, it must end its module name
+with "driver_v1" to denote the version of the API it supports. Note that
+suspend() and resume() are currently never called, as Haiku has
+no power management implemented yet. If your driver can give the device it is attached to a nice name that can be
+presented to the user, it should add the B_DEVICE_PRETTY_NAME attribute
+to the device node.
+ The B_DEVICE_UNIQUE_ID should be used in case the device has a unique
+ID that can be used to identify it, and also differentiate it from other devices
+of the same model and vendor. This information will be added to the file system
+attributes of all devices published by your driver, so that user applications
+can identify, say, a USB printer no matter what USB slot it is attached to, and
+assign it additional data, like paper configuration, or recognize it as the
+default printer. If your driver implements an API that is used by a support or bus module, you
+will usually use the B_DEVICE_FIXED_CHILD attribute to specify exactly
+which child device node you will be talking to. If you support several child
+nodes, you may want to have a closer look at the section explaining
+how to write a bus driver.Introduction to Haiku's Device Driver Architecture
+
+1. The Basics
+
+2. Exploring the Device Tree
+
+3. Writing a Driver
+
+
+
+
+ Determines wether or not the driver supports a given parent device node,
+ that is the hardware device it represents (if any), and the API the node
+ exports.
+ The driver should register its device node here. The parent driver is
+ always initialized at this point. When registering the node, the driver
+ can also attach certain I/O resources (like I/O ports, or memory ranges)
+ to the node -- the device manager will make sure that only one node can
+ claim these resources.
+ Any initialization necessary to get the driver going. For most drivers,
+ this will be reduced to the creation of a private data structure that is
+ going to be used for all of the following functions.
+ Uninitializes resources acquired by init_driver().
+ If the driver wants to register any child device nodes or to publish
+ any devices, it should do so here. This function is called only during
+ the initial registration process of the device node.
+ Is called whenever a manual rescan is triggered.
+ Enters different sleep modes.
+ Resumes a device from a previous sleep mode.4. Publishing a Device
+
+To publish a device entry in the device file system under /dev, all your
+driver has to do is to call the
+
+ publish_device(device_node *node, const char *path,
+ const char *deviceModuleName);
+
+function the device manager module exports. The path is the path
+component that follows "/dev", for example "net/ipro1000/0". The
+deviceModuleName is the module exporting the device functionality.
+It should end with "device_v1" to show the device manager which protocol it
+supports. If the device node your device belongs to is removed, your device
+is removed automatically with it. On the other hand, you are allowed to
+unpublish the device at any point using the unpublish_device() function
+the device manager delivers for this.
A device module must export the following API:
+A bus driver is a driver that represents a bus where one or more arbitrary +devices can be attached to.
+ +There are two basic types of busses: intelligent busses like PCI or USB that +know a lot about the devices attached to it, like a generic device type, as +well as device and vendor ID information, and simple untyped/generic busses that +either have not all the information (like device type) or don't even know what +and if any devices are attached. The device manager has been written in such a +way that device exploration makes use of additional information the bus can +provide in order to find a responsible device driver faster, and with less +overhead.
+ +If your bus knows what type of device is attached to, and also has vendor and +device ID information about that device, it is considered to be an intelligent +bus. The bus driver is supposed to have one parent node representing the bus, +and to create a child node for each device attached to the bus.
+ +The additional information you have about the devices are attached to the +device node in the following attributes:
+You can use the B_DEVICE_FLAGS attribute to define how the device +manager finds the children of the devices you exported. For this kind of bus +drivers, you will usually only want to specify B_FIND_CHILD_ON_DEMAND +here, which causes the driver only to be searched when the system asks for it. +
+ +The way the device manager works, it makes versioning of modules (which are +supposed to be one of the strong points of the module system) much harder or +even impossible. While the device manager could introduce a new API and could +translate between a "driver_v1", and a "driver_v2" API on the fly, it's not +yet possible for a PCI sub module to do the same thing.
+ +Proposed Solution: Add attribute B_DEVICE_ALTERNATE_VERSION +that specifies alternate versions of the module API this device node supports. +We would then need a request_version() or set_version() function +(to be called from supports_device()) that allows to specify the version +of the parent node this device node wants to talk to.
+ +