Autoconfiguration is a process that determines what hardware actually exists during the current instance of the running kernel at static configuration time. The autoconfiguration software creates a configuration tree that represents the current system configuration. In creating this configuration tree, the autoconfiguration software uses the following data structures:
The following sections describe each of these data structures except the driver structure. Section 5.3 describes the driver structure.
The bus structure represents an instance of a bus entity. A bus is a real or imagined entity to which other buses or controllers are logically attached. All systems have at least one bus, the system bus, even though the bus may not actually exist physically. The term controller here refers both to devices that control slave devices (for example, disk or tape controllers) and to devices that stand alone (for example, terminal or network controllers). Bus adapter driver writers create bus structures by calling the create_bus_struct interface and passing to it a filled-in bus_config structure. The discussion of how to use the create_bus_struct interface and how to fill in the bus_config structure is beyond the scope of this book. However, the descriptions of the bus structure are presented here.
Table 17-1 lists the members of the bus structure along with their associated data types.
Member Name | Data Type |
bus_mbox | u_long * |
bus_hd | struct bus * |
nxt_bus | struct bus * |
ctlr_list | struct controller * |
bus_list | struct bus * |
bus_type | int |
bus_name | char * |
bus_num | int |
slot | int |
connect_bus | char * |
connect_num | int |
confl1 | int (*confl1)() |
confl2 | int (*confl2)() |
pname | char * |
port | struct port * |
intr | int (**intr)() |
alive | int |
framework | struct bus_framework * |
driver_name | char * |
bus_bridge_dma | void * |
private | void * [8] |
conn_priv | void * [8] |
rsvd | void * [7] |
The following sections discuss all of these members.
The bus_mbox member specifies a pointer to the mailbox data structure for hardware platforms that access I/O space through hardware mailboxes. The bus adapter code sets this member. As the adapter code probes the buses, the first bus that has a mailbox allocates the initial software mailbox data structure and sets its bus_mbox pointer to that data structure. As the adapter code continues to probe for buses and controllers, the MBOX_GET macro allocates the ctlr_mbox members for devices accessed by mailboxes. Typically, this macro is called in the controller configuration interface after the controller data structure has been found, but before probing the controller. The following code fragment gives an idea of the tasks that occur prior to calling the MBOX_GET macro:
config_con(name, node, bus) { register struct controller *ctlr; if((ctlr = get_ctlr(name, node, bus->bus_name, bus->bus_num)) || /* other wildcards here */ (ctlr = get_ctlr(name, -1, "*", -99))) {
.
.
.
} /*************************************************** * Found the controller * ***************************************************/ int savebusnum; char *savebusname; int saveslot; if(ctlr->alive & ALV_ALIVE) { printf("config_con: %s%d alive\n", ctlr->ctlr_name, ctlr->ctlr_num); return(stat); } savebusnum = ctlr->bus_num; savebusname = ctlr->bus_name; saveslot = ctlr->slot; ctlr->bus_name = bus->bus_name; ctlr->bus_num = bus->bus_num; ctlr->slot = node; /*************************************************** * Allocate and initialize a software * * mailbox data structure for the * * controller if it is attached to a * * bus that is accessed by mailboxes * ***************************************************/ MBOX_GET(bus, ctlr); /*************************************************** * Now get the controller's driver structure * * and probe * ***************************************************/
.
.
.
}
The bus_hd member specifies a pointer to the bus structure that this bus is connected to. The nxt_bus member specifies a pointer to the next bus at this level.
The ctlr_list member specifies a linked list of controllers connected to this bus. The bus_list member specifies a linked list of buses connected to this bus.
The bus_type member specifies the type of bus. The devdriver.h file defines constants that represent a variety of bus type constants. For example, BUS_PCI represents a PCI bus, BUS_EISA represents an EISA bus, BUS_ISA represents an ISA bus, and so forth.
Device driver writers seldom need to reference this member. However, bus adapter driver writers might reference this member in their bus adapter code.
The bus_name member specifies the bus name. The bus_num member specifies the bus number of this bus.
The bus name consists of a character string, for example, pci (for PCI bus). The bus number is a number such as 0 (zero), 1, 2, and so forth.
Device driver writers seldom need to reference the bus_name and bus_num members in their device drivers. Instead, driver writers often pass a pointer to a bus structure to the handler interfaces, and the interrupt handlers use the information contained in these members.
The slot member specifies the bus slot or node number. The connect_bus member specifies the name of the bus that this bus is connected to. The connect_num member specifies the number of the bus that this bus is connected to.
The bus name consists of a character string, for example, pci (for PCI bus). The bus number consists of one of the following:
Thus, pci1 specifies a bus with a bus number of 1.
pci?
pci *
Device driver writers seldom need to reference these members in their device drivers. However, bus adapter driver writers might reference these members in their bus adapter code.
The confl1 member specifies a pointer to an entry point of the level 1 bus configuration interface. The confl2 member specifies a pointer to an entry point of the level 2 bus configuration interface. Device driver writers do not typically use these interfaces, but systems engineers who want to implement a configuration procedure for a specific bus probably would use them.
The pname member specifies a pointer to the port name for this bus, if applicable. The port member specifies a pointer to the port structure for this bus, if applicable.
Device driver writers do not reference these members in their device drivers. However, bus adapter writers use the port structure to implement the initialization for a class of devices or controllers that have common characteristics.
The intr member specifies an array that contains an entry point or points for the bus interrupt handlers.
A device driver knows the name of its bus interrupt interface. A device driver uses the handler_add and handler_enable interfaces to register its interrupt handlers.
Device driver writers seldom need to reference this member in their device drivers. However, bus adapter driver writers might use this member in their bus adapter code to reference the interrupt handlers that handle error interrupts related to the bus.
The alive member specifies a flag word to indicate the current status of the bus. The system sets this member to the bitwise inclusive OR of the valid alive bits defined in devdriver.h.
The ALV_ALIVE bit indicates that the device is present and configured on the system. The following list shows the valid alive bits that bus adapter drivers can use:
ALV_FREE | The bus is not yet processed. |
ALV_ALIVE | The bus is alive and configured. |
ALV_PRES | The bus is present but not yet configured. |
ALV_NOCNFG | The bus is not to be configured. |
ALV_LOADABLE | The bus is present and resolved as loadable. |
ALV_NOSIZER | The sizer program should ignore these bus structures. This bit is set for dynamically configured drivers. It indicates that this bus structure is not part of the static configuration. |
The framework member specifies a pointer to the bus_framework structure. This structure contains pointers to bus interfaces for dynamically configured device drivers. These interfaces provide dynamic extensions to bus functionality. They are used in the autoconfiguration of dynamically configured drivers to perform bus-specific tasks, such as the registration of interrupt handlers. The framework member is initialized by the bus adapter driver.
Device driver writers seldom need to reference this member in their device drivers. However, bus adapter driver writers might reference this member in their bus adapter code.
The driver_name member specifies the name of the controlling device driver.
The autoconfiguration software sets the driver_name members to xxdriver, where xx is the driver name as specified by the device driver entry in the sysconfigtab file fragment. The following example shows one such entry:
.
.
.
none:
.
.
.
Device driver writers seldom need to reference this member in their device drivers. However, bus adapter driver writers might reference this member in their bus adapter code.
The bus_bridge_dma member specifies that the bus adapter has direct memory access (DMA) mapping support. The bus_bridge_dma member is initialized by the bus adapter driver.
Device driver writers seldom need to reference this member in their device drivers. However, bus adapter driver writers might reference this member in their bus adapter code.
The private member specifies private storage for use by this bus or bus class. The conn_priv member specifies private storage for use by the bus that this bus is connected to. The rsvd member is reserved for future expansion of the data structure.
The controller structure represents an instance of a controller entity, one that connects logically to a bus. A controller can control devices that are directly connected or can perform some other controlling operation, such as a network interface or terminal controller operation.
Device driver writers create controller structures by calling the create_controller_struct interface and passing to it a filled-in controller_config structure. Section 6.6.4.1 discusses the controller_config structure and Section 6.6.4.3 discusses how to call the create_controller_struct interface.
Table 17-2 lists the members of the controller structure, along with their associated data types.
Member Name | Data Type |
ctlr_mbox | u_long * |
bus_hd | struct bus * |
nxt_ctlr | struct controller * |
dev_list | struct device * |
driver | struct driver * |
ctlr_type | int |
ctlr_name | char * |
ctlr_num | int |
bus_name | char * |
bus_num | int |
rctlr | int |
slot | int |
alive | int |
pname | char * |
port | struct port * |
intr | int (**intr)() |
addr | caddr_t |
addr2 | caddr_t |
flags | int |
bus_priority | int |
ivnum | int |
priority | int |
cmd | int |
physaddr | caddr_t |
physaddr2 | caddr_t |
private | void * [8] |
conn_priv | void * [8] |
rsvd | void * [8] |
The following sections discuss all of these members.
The ctlr_mbox member specifies a pointer to the mailbox data structure for hardware platforms that access I/O space through hardware mailboxes. The bus adapter code sets this member. As the adapter code probes the buses, the first bus that has a mailbox allocates the initial software mailbox data structure and sets its bus_mbox pointer to that data structure. As the adapter code continues to probe for buses and controllers, the MBOX_GET macro allocates the ctlr_mbox members for devices accessed by mailboxes. Typically, this macro is called in the controller configuration interface after the controller data structure has been found, but before probing the controller.
The following code fragment gives an idea of the tasks that occur prior
to calling the
MBOX_GET
macro:
config_con(name, node, bus) { register struct controller *ctlr; if((ctlr = get_ctlr(name, node, bus->bus_name, bus->bus_num)) || /* other wildcards here */ (ctlr = get_ctlr(name, -1, "*", -99))) {
.
.
.
} /*************************************************** * Found the controller * ***************************************************/ int savebusnum; char *savebusname; int saveslot; if(ctlr->alive & ALV_ALIVE) { printf("config_con: %s%d alive\n", ctlr->ctlr_name, ctlr->ctlr_num); return(stat); } savebusnum = ctlr->bus_num; savebusname = ctlr->bus_name; saveslot = ctlr->slot; ctlr->bus_name = bus->bus_name; ctlr->bus_num = bus->bus_num; ctlr->slot = node; /*************************************************** * Allocate and initialize a software * * mailbox data structure for the * * controller if it is attached to a * * bus that is accessed by mailboxes * ***************************************************/ MBOX_GET(bus, ctlr); /*************************************************** * Now get the controller's driver structure * * and probe * ***************************************************/
.
.
.
}
The bus_hd member specifies a pointer to the bus structure that this controller is connected to. The nxt_ctlr member specifies a pointer to the next controller at this level. The dev_list member specifies a linked list of devices connected to this controller.
The driver member specifies a pointer to the driver structure for this controller. The device driver writer initializes a driver structure, usually in the declarations section of the driver.
The ctlr_type member specifies the controller type. The ctlr_name member specifies the controller name. The ctlr_num member specifies the controller number.
The ctlr_type member is not currently used by the autoconfiguration software.
The controller name consists of a character string, for example, fb (for graphics frame buffer controller).
Driver writers are unlikely to use the ctlr_name member. Driver writers often use the ctlr_num member as an index to identify which instance of the controller the request is for. The /dev/none device driver illustrates the use of the ctlr_num member.
The bus_name member specifies the name of the bus to which this controller is connected. The bus_num member specifies the number of the bus to which the controller is connected.
The bus name consists of a character string, for example, pci (for PCI bus).
The bus number consists of one of the following:
Thus, pci1 specifies a bus with a bus number of 1.
pci?
pci *
Device driver writers seldom need to reference these members in their device drivers. However, bus adapter driver writers might reference these members in their bus adapter code.
The rctlr member specifies the remote controller number (for example, the SCSI ID).
The slot member specifies the bus slot or node number. The kernel can set this member to the value -1 if there are no slots.
The alive member specifies a flag word to indicate the current status of the controller. The autoconfiguration software sets the alive member to the ALV_ALIVE bit if the controller is present on the system. The autoconfiguration software obtains this and the other alive bits in the file devdriver.h. The following list shows the valid alive bits that bus adapter drivers can use:
ALV_FREE | The controller is not yet processed. |
ALV_ALIVE | The controller is alive and configured. |
ALV_PRES | The controller is present but not yet configured. |
ALV_NOCNFG | The controller is not to be configured. |
ALV_LOADABLE | The controller is present and resolved as dynamically configured. |
ALV_NOSIZER | The sizer program should ignore these controller structures. This bit is set for dynamically configured drivers. It indicates that this controller structure is not part of the static configuration. |
ALV_RONLY | The device is read only. This bit is set for statically configured drivers if the corresponding entry is specified in the sysconfigtab file fragment. This bit is not supported for dynamically configured drivers. |
ALV_WONLY | The device is write only. This bit is set for statically configured drivers if the corresponding entry is specified in the sysconfigtab file fragment. This bit is not supported for dynamically configured drivers. |
The pname member specifies a pointer to the port name for this controller, if applicable. The port member specifies a pointer to the port structure for this controller, if applicable.
Device driver writers do not reference these members in their device drivers. However, bus adapter writers use the port structure to implement the initialization for a class of devices or controllers that have common characteristics.
The intr member specifies an array that contains one or more entry points for the controller interrupt handlers.
For device drivers, the intr members of these data structures would be set up indirectly through calls to the handler_add interface.
The addr member specifies the address of the device registers or memory. This address is the first control status register (CSR) for the CPU.
The addr2 member specifies an optional second virtual address for this controller. This member is set if there are two CSR spaces.
The flags member specifies controller-specific flags.
The bus_priority member specifies the configured VMEbus priority level of the device. Only drivers operating on the VMEbus use this member. See Writing VMEbus Device Drivers for additional information on this member.
The ivnum member specifies an interrupt vector number. Only drivers operating on the VMEbus use this member. See Writing VMEbus Device Drivers for additional information on this member.
The priority member specifies the system priority level (spl) to block interrupts from this device. Only drivers operating on the VMEbus use this member. Thus, the autoconfiguration software initializes the priority member with an appropriate value based on the value stored in the bus_priority member (if specified) and the system implementation. You use this value as an argument to the splx interface to block interrupts for the device. See Writing VMEbus Device Drivers for additional information on this member.
The cmd member specifies a field that is not currently used.
The physaddr member specifies the physical address that corresponds to the virtual address set in the addr member.
The physaddr2 member specifies the physical address that corresponds to the virtual address set in the addr2 member.
The private member specifies private storage for use by this controller or controller type. The code controlling the controller can use these members for any storage purpose.
The conn_priv member specifies private storage for use by the bus that this controller is connected to.
The rsvd member is reserved for future expansion of the data structure.
The device structure represents an instance of a device entity. A device is an entity that connects to and is controlled by a controller. A device does not connect directly to a bus.
Device driver writers create device structures by calling the create_device_struct interface and passing to it a filled-in device_config structure. Section 6.6.4.2 discusses the device_config structure and Section 6.6.4.3 discusses how to call the create_device_struct interface.
Table 17-3 lists the members of the device structure along with their associated data types.
Member Name | Data Type |
nxt_dev | struct device * |
ctlr_hd | struct controller * |
dev_type | char * |
dev_name | char * |
logunit | int |
unit | int |
ctlr_name | char * |
ctlr_num | int |
alive | int |
private | void * [8] |
conn_priv | void * [8] |
rsvd | void * [8] |
The following sections discuss all of these members.
The nxt_dev member specifies a pointer to the next device at this level. The ctlr_hd member specifies a pointer to the controller structure that this device is connected to.
The dev_type member specifies the device type (for example, disk or tape). The dev_name member specifies the device name type.
The logunit member specifies the device logical unit number. The unit member specifies the device physical unit number.
The ctlr_name member specifies the name of the controller that this device is connected to. The ctlr_num member specifies the number of the controller that this device is connected to.
The alive member specifies a flag word to indicate the current status of the device. The autoconfiguration software obtains this and the other alive bits in the file /usr/sys/include/io/common/devdriver.h.
The private member specifies private storage for use by this device or device class. The conn_priv member specifies private storage for use by the controller that this device is connected to.
The rsvd member is reserved for future expansion of the data structure.
The port structure contains information about a port.
Table 17-4 lists the member of the port structure along with its associated data type.
Member Name | Data Type |
conf | int (*conf) () |
The conf member specifies a pointer to the configuration interface for this port.