This chapter describes:
The descriptions of the device driver interfaces are presented in alphabetical order and in reference (man) page style. The bus configuration interfaces are presented in a separate section and they, too, appear in reference (man) page style. The descriptions can include the following sections.
This section lists the name of the driver or bus configuration interface along with a summary description of its purpose. In general, there is one interface described for each reference page. However, in some cases it makes sense to describe more than one interface on the same page if the interfaces are related. When this occurs, this section lists the names of all the interfaces it describes.
This section lists the structure or file where the driver writer specifies the entry for the device driver interface. This section is not applicable to the bus configuration interfaces.
This section shows the device driver or bus configuration interface function definition. The style used is that of the function definition, not the function call. This book assumes that you understand how to interpret the function definition and how to write an appropriate call for a specific interface.
The presentation shown in the following example is of the function definitions for all the block and character driver interfaces and for the xxconfl1 and xxconfl2 bus configuration interfaces:
int xxopen
(dev,
flag,
format)
dev_t
dev;
int
flag;
int
format;
The presentation shown in the following example is of the function definitions for the bus configuration interfaces that obtain the interface name through the bus structure's framework member:
int (*bus->framework->adp_handler_disable)
(id)
ihandler_id_t
id;
The presentation shown in the following example is of the function definitions for the bus configuration interfaces that do not obtain the interface name through the bus structure's framework member:
void conn_dev
(ctlr,
device)
struct controller
*ctlr;
struct device
*device;
These interface function definitions give you the following information:
Gives the data type of the return value, if the interface returns data. If the interface does not return a value, uses the void data type.
Gives the driver or bus configuration interface name. In the first example, xxopen is the name of the block or character driver interface. The prefix xx indicates that this part of the name is variable. Replace it with the character prefix that represents the name of the device for which the driver is being written.
In the second example, the name of the bus configuration interface is obtained through the bus structure's framework member. This member is a pointer to a bus_framework structure, which contains a pointer to the actual interface. The example shows that the disable interrupt member contains a pointer to the actual adp_handler_disable interface.
In the third example, the name of the bus configuration interface is as specified, for example, conn_dev.
Gives the name of each driver or bus configuration interface argument. In the first example, the argument names are dev, flag, and format. In some cases, the driver interface function definition will have different arguments based on the bus on which the driver operates. For example, the xxprobe interface has different arguments for the TURBOchannel bus and the VMEbus.
Gives the types for each of the arguments. In the first example, these types are dev_t and int. Note that the term driver interface or bus configuration interface is used, instead of the term driver routine or bus configuration routine to establish consistent terminology with that used for the kernel interfaces.
This section provides descriptions for the arguments associated with a given driver or bus configuration interface. In most cases, argument descriptions begin with the word specifies to indicate that the driver writer passes the argument (with some specified value) to the driver or bus configuration interface.
This section contains explanations of the tasks performed by the driver or bus configuration interface.
This section contains information about the driver or bus configuration interface pertinent to the device driver writer. For example, this section could point out that the interface is specific to loadable device drivers.
This section describes the values that a given driver or bus configuration interface can return.
This section lists related kernel interfaces, structures, system calls, and so forth.
Table 4-1 summarizes the interfaces that device drivers use. The table has the following columns:
This column lists the driver interface name.
This column lists the structure (or file) where the driver writer defines the entry point for the device driver interface.
A Yes appears in this column if the interface is applicable to a character device. Otherwise, N/A (not applicable) appears.
A Yes appears in this column if the interface is applicable to a block device. Otherwise, N/A (not applicable) appears.
Interface | Entry Point | Character | Block |
callback | N/A | Yes | Yes |
cattach | driver | Yes | Yes |
close | dsent | Yes | Yes |
configure | N/A | Yes | Yes |
ctrl_unattach | driver | Yes | Yes |
dattach | driver | Yes | Yes |
dev_unattach | driver | Yes | Yes |
dump | dsent | N/A | Yes |
flush | N/A | Yes | Yes |
intr | Use the handler_add and handler_enable interfaces for registration of interrupt handlers | Yes | Yes |
ioctl | dsent | Yes | Yes |
mmap | dsent | Yes | N/A |
open | dsent | Yes | Yes |
probe | driver | Yes | Yes |
psize | dsent | N/A | Yes |
read | dsent | Yes | N/A |
reset | dsent | Yes | N/A |
select | dsent | Yes | N/A |
shutdown | N/A | Yes | Yes |
slave | driver | Yes | Yes |
stop | dsent | Yes | N/A |
strategy | dsent | N/A | Yes |
write | dsent | Yes | N/A |
Is the callback interface for device drivers
None
void xx_callback
(point,
order,
argument,
event_arg)
int
point;
int
order;
ulong
argument;
ulong
event_arg;
The xxcallback interface is a driver-implemented interface that performs tasks required at a specific dispatch point.
You must have previously registered the device driver's xxcallback interface by calling the register_callback interface. You implement xxcallback interfaces only for statically configured drivers.
None
register_callback, unregister_callback
Perform controller- or device-specific initialization
The driver structure
void xxcattach
(ctlr)
struct controller
*ctlr;
void xxdattach
(device)
struct device
*device;
The
xxcattach and
xxdattach interfaces
perform controller- or device- specific initialization.
These interfaces usually perform the tasks necessary to establish
communication with the actual device.
These tasks might include, for a device
attach
interface,
initializing a tape drive or putting a disk
drive on line.
In addition,
xxcattach and
xxdattach initialize any global data structures that the device driver uses.
At boot time, the autoconfiguration software calls these interfaces under the following conditions:
If you set the cattach or dattach member of the driver structure to NULL, no call is made to the xxcattach or xxdattach interface. The xxcattach interface is passed a controller structure and the xxdattach interface is passed a device structure for this device.
For loadable drivers, the xxcattach or xxdattach interface is called indirectly when the system manager issues a command to dynamically load the driver.
None
Closes a device
The dsent table
int xxclose
(dev,
flag,
format)
dev_t
dev;
int
flag;
int
format;
Device driver writers use the dev_t data type to represent a device's major and minor numbers. This data type is an abstraction of the internal representations of the major and minor numbers. Driver writers do not need to know how the system internally represents the major and minor numbers.
A device driver's xxclose interface is called when a process closes the special device file that corresponds to this driver. This action occurs when the last file descriptor that is open and associated with this device is closed by means of the close system call.
A block device driver's xxclose interface closes a device that was previously opened by the xxopen interface. The xxclose interface is called only after making the final open reference to the device.
A character and block device driver's xxclose interfaces perform similar tasks. If the character device provides raw access to a block device, the xxclose interface is usually the same. Almost all character device drivers provide an xxclose interface; however, some block devices do not require this interface.
The xxclose interface for a block or character device driver also performs the following tasks:
Upon successful completion of the close request, the xxclose interface returns ESUCCESS. Otherwise, xxclose can return error constants defined in /usr/sys/include/sys/errno.h. A typical return constant is:
dsent, fcntl.h, sysconfig.h, xxopen
Performs configuration-related tasks
None
int xx_configure
(optype,
indata,
indatalen,
outdata,
outdatalen)
cfg_op_t
optype;
cfg_attr_t
*indata;
size_t
indatalen;
cfg_attr_t
*outdata;
size_t
outdatalen;
Value | Meaning |
CFG_OP_CONFIGURE | Configures (loads) the device driver. |
CFG_OP_UNCONFIGURE | Unconfigures (unloads) the device driver. |
CFG_OP_QUERY | Queries the driver for configuration information. |
CFG_OP_RECONFIGURE | Reconfigures the device driver. |
The xxconfigure interface cooperates with the cfgmgr framework to handle user-level requests to the cfgmgr framework to dynamically load (configure), unload (unconfigure), query, reconfigure, and perform user-defined tasks for the driver's associated device. In addition, the xxconfigure interface cooperates with the cfgmgr framework to handle static configuration requests. The xxconfigure interface also cooperates with the cfgmgr framework to perform one-time initialization tasks such as allocating memory, initializing data structures and variables, adding the driver's I/O services interfaces and reserving a major number in the dsent table. A driver's xxconfigure interface should be implemented to handle static and dynamic configuration.
Your xxconfigure interface must use an underscore (_) in the name. For example, a fax device driver could have a configure interface called fax_configure.
The xxconfigure interface can return error values defined in the /usr/sys/include/sys/errno.h file. The following list describes some of these error values:
Removes the specified controller
The driver structure
int xxctrl_unattach
(bus_struct,
ctlr_struct)
struct bus
*bus_struct;
struct controller
*ctlr_struct;
A device driver's xxctrl_unattach interface removes the specified controller structure from the list of controllers it handles. This interface should clean up any in-memory data structures and remove any interrupt handlers the driver may have established.
Because this interface is called indirectly from the CFG_OP_UNCONFIGURE entry point of the driver's configure interface, the driver has already determined that the controller is in a quiescent state. Thus, xxctrl_unattach need not check this condition.
Because you cannot unconfigure device drivers that are statically configured into the kernel, the xxctrl_unattach interface is specific to device drivers that are dynamically configured into the kernel.
The unconfigure_driver interface calls the xxctrl_unattach interface if one is implemented. If your driver supports a single controller, you can perform all of the unattach controller tasks in the CFG_OP_UNCONFIGURE entry point of the driver's configure interface. However, if your driver supports more than a single controller, you should implement a xxctrl_unattach interface.
The xxctrl_unattach interface can return one of the following values defined in /usr/sys/include/sys/errno.h:
bus, controller, xxdev_unattach
Removes the specified device
The driver structure
int xxdev_unattach
(ctlr_struct,
dev_struct)
struct controller
*ctlr_struct;
struct device
*dev_struct;
A device driver's xxdev_unattach interface removes the specified device structure from the list of devices it handles. This interface should free any in-memory data structures that were dynamically allocated in the driver's attach interface. You can write this interface so that it removes a single device, or you can write the interface as part of a calling sequence to remove a controller structure.
Because you cannot unconfigure device drivers that are statically configured into the kernel, the xxdev_unattach interface is specific to device drivers that are dynamically configured into the kernel.
The
unconfigure_driver
interface calls the
xxdev_unattach interface if one is implemented.
If your driver supports a single device, you can perform all of the
unattach device tasks in the
CFG_OP_UNCONFIGURE
entry point of the driver's
configure
interface.
However, if your driver supports more than a single device, you should
implement a
xxdev_unattach interface.
The xxdev_unattach interface can return one of the following values defined in the /usr/sys/include/sys/errno.h file:
controller, device, ctrl_unattach
Copy system memory to the dump device
The dsent table
int xxdump
(dumpdev)
dev_t
dumpdev;
The xxdump interface copies the contents of system memory to the specified device. Usually, xxdump is called when a system panic occurs. By copying the contents of memory to the dump device, you can investigate what is called a ``core dump'' to determine the cause of the panic. After the system panic, the next time the system is booted, the system startup software looks on the swap device for the existence of a core dump. If the core dump exists, it will be formatted and copied to the specified location in the file system, thereby freeing up the dump device for subsequent dumps.
Because the xxdump interface is usually called only when a system panic occurs, the exact state and sanity of the operating system are compromised. It could be possible that the panic is the result of an error in the device driver that contains the xxdump interface. In an effort to have a known stable means of dumping system memory to the dump device, there are some hardware platforms that utilize console firmware callbacks to implement the actual dump functions.
A device driver is required to implement an xxdump interface only if the associated device is capable of accepting the contents of system memory. Typically, only disk device drivers, which are candidates for being dump devices, implement the xxdump interface. If the driver does not implement the xxdump interface, you specify the nodev interface in the dsent table.
The Digital UNIX operating system does not currently support a dump interface's ability to copy the contents of system memory to the specified device. Device driver writers should not provide a dump interface for this version of Digital UNIX.
Upon successful completion of the dump request, the xxdump interface returns ESUCCESS. Otherwise, xxdump returns one of the following error constants defined in /usr/sys/include/sys/errno.h:
Is the flush controller interface for device drivers
None
void xxflush
(parameter)
caddr_t
parameter;
The xxflush interface flushes the cache on the specified controller.
You must have previously registered the device driver's xxflush interface by calling the drvr_register_flush interface.
None
Handles hardware interrupts
The intr member of the handler_intr_info data structure
int xxintr
(parameter)
caddr_t
parameter;
Typically, you set this member to the logical controller number, which is used to specify the instance of the controller the interrupt corresponds to. One way to accomplish this is to set the param member of the handler_intr_info data structure to the value stored in the ctlr_num member of the controller structure pointer associated with the controller the interrupt corresponds to. This is typically done in the driver's probe interface.
The xxintr interface is called as a result of a hardware interrupt. The way in which interrupts are dispatched is bus specific. A device driver's xxintr interface is referred to as an interrupt handler.
A shared interrupt handler is a driver routine registered to take advantage of the shared interrupt framework that Digital UNIX provides for hardware devices that share an interrupt line. Currently, the AlphaStation 200, AlphaStation 400, and AlphaStation 600 series of computer systems support shared interrupts on the PCI bus. Binary compatibility is maintained with device drivers that do not implement the functionality to support shared interrupts.
To successfully implement an interrupt handler that takes advantage of the shared interrupt functionality requires cooperation between the interrupt handler and the interrupt dispatch code. The interrupt dispatch code sequentially calls interrupt handlers sharing a particular interrupt line to the system until one of the interrupt handlers returns status that indicates that it serviced the interrupt. Therefore, an interrupt handler must determine if the device is asserting an interrupt condition. This is typically done through a read of the device register. If the device is not asserting an interrupt condition, then the driver's interrupt handler must immediately return the constant INTR_NOT_SERVICED. The checking of the device register and the returning of INTR_NOT_SERVICED must be as fast as possible to maintain low interrupt latency. An interrupt handler must not do any other operations when called and the device is not asserting an interrupt condition.
The checking of a device's interrupt status must not cause any side effects. For example, the check cannot cause errors to occur or impact the device or any other device, or the system in any way. If it is not possible to quickly check the device's interrupt status without side effects, then the driver must not register its interrupt handler as sharable.
All other return points from an interrupt handler must return the constant INTR_SERVICED. The device driver must call the handler_add interface to register its interrupt handler and handler_enable to enable its interrupt handler. In addition, a driver can call handler_disable to disable its interrupt handler and handler_del to deregister its interrupt handler.
A device driver typically sets up the handler_intr_info data structure used in the call to handler_add in its probe interface. The config_type member specifies the driver type and whether the driver's interrupt handler can handle shared interrupts. If your device driver's interrupt handler cannot handle shared interrupts, you set this member to one of the following interrupt handler type bit values defined in handler.h: CONTROLLER_CONFIG_TYPE (the interrupt handler is for a controller) or ADAPTER_CONFIG_TYPE (the interrupt handler is for a bus adapter). If your device driver's interrupt handler can handle shared interrupts, you set this member to the bitwise inclusive OR of the interrupt handler type bit value and the shared interrupt bit value SHARED_INTR_CAPABLE.
If the device driver's interrupt handler
is not implemented to handle shared interrupts, then it
generally does not return a value.
If the device driver's
xxintr is implemented to handle shared interrupts, it can return the following
values:
Value | Meaning |
INTR_SERVICED | The device driver's interrupt handler serviced the shared interrupt. |
INTR_NOT_SERVICED | The device driver's interrupt handler did not service the shared interrupt. |
controller, handler_add, handler_intr_info
General-purpose I/O control
The dsent table
int xxioctl
(dev,
cmd,
data,
flag)
dev_t
dev;
unsigned int
cmd;
caddr_t
data;
int
flag;
Device driver writers use the dev_t data type to represent a device's major and minor numbers. This data type is an abstraction of the internal representations of the major and minor numbers. Driver writers do not need to know how the system internally represents the major and minor numbers.
Many
ioctl
commands are handled by the I/O system and do not result in a
call to the device driver's
xxioctl interface.
However, when a command requires a device-specific action, this
information is passed to the driver's
xxioctl interface.
One of the values you can pass to this argument is
DEVIOCGET.
Value | Meaning |
FREAD | The device is open for reading. |
FWRITE | The device is open for reading and writing. |
FAPPEND | The device is open for writing at the end of the file. |
The xxioctl interface typically performs all device-related operations other than read or write operations. A device driver's xxioctl interface is called as a result of an ioctl system call. Only those ioctl commands that are device specific or that require action on the part of the device driver result in a call to the driver's xxioctl interface.
Some of the device-related operations performed by the xxioctl interface are:
In general, all device drivers have an xxioctl interface that identifies the device type, controller name, and other related parameters. For example, user programs may request information about disks, in which case the xxioctl interface returns disk geometry information. For user program requests about terminal devices, the xxioctl interface might return the current values of the terminal line attributes. User program requests about tape drives can result in the return of such attributes as tape density.
The device status for a tape drive, for example, might consist of the tape mark encountered, end of media encountered, positioning at the bottom of the tape, or device is write protected.
The device settings for a terminal device, for example, might consist of baud rate or parity. For disk drives, the partition-related information might be specified by the ioctl interface. For tape drives, the xxioctl interface performs tape repositioning commands, such as rewinding and forward or backward skipping of tape marks and tape records.
The xxioctl interface returns an error number from the /usr/sys/include/sys/errno.h file if there is a failure; otherwise, it returns the value ESUCCESS.
DEVIOCGET, _IO, _IOR, _IOW, _IOWR
Reference Pages Section 4: devio
Maps kernel space to user space
The dsent table
caddr_t xxmmap
(dev,
offset,
prot)
dev_t
dev;
off_t
offset;
int
prot;
Device driver writers use the dev_t data type to represent a device's major and minor numbers. This data type is an abstraction of the internal representations of the major and minor numbers. Driver writers do not need to know how the system internally represents the major and minor numbers.
Flag | Meaning |
PROT_READ | Pages can be read. |
PROT_WRITE | Pages can be written. |
The xxmmap interface is invoked by the kernel as a result of an application calling the mmap system call. The xxmmap interface verifies that the requested offset is valid for this device and returns the page frame number that corresponds to the offset. In conjunction with the mmap system call, this interface allows a user process to map device memory into the user process address space.
Some Alpha CPUs do not support an application's use of the mmap system call.
The xxmmap interface, if successful, returns the page frame number that corresponds to the page at the byte offset specified by the offset argument. Otherwise, xxmmap returns -1.
Reference Pages Section 2: mmap, munmap
Opens a device
The dsent table
int xxopen
(dev,
flag,
format)
dev_t
dev;
int
flag;
int
format;
Device driver writers use the dev_t data type to represent a device's major and minor numbers. This data type is an abstraction of the internal representations of the major and minor numbers. Driver writers do not need to know how the system internally represents the major and minor numbers.
Value | Meaning |
FREAD | The device is open for reading. |
FWRITE | The device is open for reading and writing. |
FAPPEND | The device is open for writing at the end of the file. |
Value | Meaning |
S_IFCHR | Character device |
S_IFBLK | Block device |
A device driver's xxopen interface is called when a process opens the special device file that corresponds to this driver. This correspondence is made by the open system call through the major device number, which serves as an index into either the dsent or dsent table.
A block device driver's xxopen interface opens a device to prepare it for I/O operations. This interface usually verifies that the device was identified during autoconfiguration. For tape devices, this identification may consist of bringing the device on line and selecting the appropriate density.
A character device driver's xxopen interface performs tasks similar to those performed by the block device driver. If the character device provides raw access to a block device, the xxopen interface is usually the same. Almost all character device drivers provide an xxopen interface; however, some block devices do not require this interface. For terminal devices, the xxopen interface may block waiting for the necessary modem signals, for example, carrier detect. The xxopen interface for a block or character device driver also performs the following tasks:
Upon successful completion of the open request, the xxopen interface returns ESUCCESS. Otherwise, xxopen can return error constants defined in the /usr/sys/include/sys/errno.h file. The following describes some typical constants that xxopen can return:
dsent, fcntl.h, mode.h, xxclose
Determines whether the device exists
The driver structure
int xxprobe
(bus_io_handle,
ctlr)
io_handle_t
bus_io_handle;
struct controller
*ctlr;
A device driver's xxprobe interface performs tasks necessary to determine if the device exists and is functional on a given system. The xxprobe interface typically registers a driver's interrupt handlers by using the ihandler_t and handler_intr_info structures and by calling the handler_add and handler_enable interfaces.
Other tasks performed by the xxprobe interface vary, depending on whether the device driver is statically or dynamically configured into the kernel:
The xxprobe interface typically checks some device control status register (CSR) to determine whether the physical device is present. If the device is not present, the device is not initialized and not available for use. The kernel calls the xxprobe interface for each device that you defined in the call to the create_device_struct interface.
For dynamically configured drivers, the xxprobe interface is called indirectly during the driver loading process. The driver's configure interface calls the configure_driver interface to merge the driver's connectivity information into the system (hardware) configuration tree, which consists of bus, controller, and device structures. The call to configure_driver results in the system calling xxprobe for each instance of the controller present on the bus.
When device drivers are dynamically loaded, the bus configuration code checks for the existence of the device before calling xxprobe.
The first argument associated with a driver's probe interface is bus specific. To write portable device drivers across multiple bus architectures, you need to know the first argument associated with the probe interface for that bus. See the bus-specific driver book for a description of the first argument associated with the probe interface for that bus.
The second argument for a driver's probe interface is always a pointer to a controller structure. You can use the controller structure pointer to determine the bus to which the device controller is connected. Typically, you reference the bus_name member of the bus structure through the controller structure's bus_hd member.
The Synopsis section shows the arguments associated with a probe interface for device drivers that operate on the TURBOchannel bus.
The xxprobe interface returns a nonzero value if the probe operation is successful. It returns the value zero (0) to indicate that the driver did not complete the probe operation.
Returns the size of a disk partition.
The dsent table
The xxpsize interface is a means for the upper layer of kernel interfaces to determine the size of a disk partition. The driver returns the size of the specified partition, which is initially specified in the device's partition table or disk label.
The xxpsize interface could be called during system startup in configuring the swapping functions. These functions need to know the size of the disk (in units) of the disk blocks (typically 512-byte disk blocks).
The xxpsize interface is usually implemented only in disk device drivers. Other types of device drivers that do not implement this interface should specify a value of zero (0) in the dsent table.
The xxpsize interface returns the size of the device partition in units of the disk blocks. If the specified device or partition does not exist, xxpsize returns the value -1.
Reads data from a device
The dsent table
The device driver for the raw block device is both a block and a character driver. When accessed as a block device, the system uses the driver's strategy interface as the entry point. When accessed as a character device, the driver's read and write interfaces are used as the entry points.
int xxread
(dev,
uio,
flag)
dev_t
dev;
register struct uio
*uio;
int
flag;
Device driver writers use the dev_t data type to represent a device's major and minor numbers. This data type is an abstraction of the internal representations of the major and minor numbers. Driver writers do not need to know how the system internally represents the major and minor numbers.
The xxread interface is called from the I/O system as the result of a read system call. The driver's xxread interface reads data from a device. If there is no data available, the xxread interface puts the calling process to sleep until data is available. If data is available, xxread calls the uiomove interface to copy it from the private kernel buffer to the user's process.
In the case of raw block devices, the xxread interface calls the physio kernel interface, passing to it the device-specific parameters. For terminal-oriented devices, the driver passes the read request to the generic terminal read interface.
Upon successful completion of the read request, the xxread interface returns ESUCCESS. Otherwise, xxread can return error constants defined in the /usr/sys/include/sys/errno.h file. The following describes some typical constants that xxread can return:
Some read interfaces can also return the value returned in a call to the physio interface.
dsent, fcntl.h, physio, uio, uiomove, xxwrite
Reference Pages Section 2: read
Resets the device
The dsent table
void xxreset
(busnum)
int
busnum;
The xxreset interface is used to force a device reset to place the device in a known state after a bus reset. The bus adapter support interfaces call the xxreset interface after completion of a bus reset. Note that not all buses support the reset functionality.
For a terminal device driver, the xxreset interface can consist of reenabling interrupts on all open lines and resetting the line parameters for each open line. Following a reset of terminal state and line attributes, transmission can resume on the terminal lines.
None
Determines whether read/write will block
The dsent table
int xxselect
(dev,
events,
revents,
scanning)
dev_t
dev;
short
events;
short
revents;
int
scanning;
Read input select The caller of select wants to know if input data is available on this device. A user-level process issues a select system call. The select system call then causes the kernel to call the driver's select interface.
Write output select The caller of select wants to know if the device is ready to accept data to be output.
Exception event select The caller of select wants to know if an exception event has occurred on the device. This is rarely used on device drivers. It is used on pseudoterminal devices to indicate the presence of control status information.
It is an error to issue a select on this device. Driver writers can use this bit mask to indicate a select on input to an output-only device or a select on output to an input-only device.
Indicates that the device has entered a state where it cannot perform input or output. Driver writers might set this bit mask when selecting on a terminal device and the modem connection has disconnected.
Indicates that the device is readable.
Indicates that the device is writable.
The kernel sets this argument to the value zero (0) to indicate the termination of a select call. In response to this setting, the driver should call the select_dequeue interface to remove all instances for this device that are waiting for input or output notification.
A device driver's xxselect interface is called to determine whether the device is ready to perform an I/O operation without blocking. The xxselect interface is called as a result of the select system call.
A typical use of the select system call is when an application might be performing I/O to more than one file descriptor. One such example is a graphics server that receives input from the mouse and keyboard. When this graphics server is ready to accept input, it issues a select system call on the file descriptors associated with the mouse and keyboard to determine if input is available from either of them. In this way, the select system call is a form of polling to see if the device has input data that could be received by subsequent read calls or written by subsequent write calls.
The xxselect interface is called to determine if the specified device is ready to perform an I/O operation. The xxselect interface can be called to determine if input data is available to be read without blocking or if the device is ready to output data without blocking.
The return value of the xxselect interface will eventually be the return value for the select system call. The xxselect interface can return one of the following values:
dsent, poll.h, select_dequeue, select_dequeue_all, select_enqueue, select_wakeup
Reference Pages Section 2: select
Is the shutdown interface for device drivers
None
void xxshutdown
(parameter)
caddr_t
parameter;
The argument you pass can be of any type. Typically, when you pass the argument to drvr_register_shutdown you cast it to caddr_t.
The xxshutdown interface turns off the hardware device before the system shuts down. For example, a device driver that operates on a SCSI bus connected to two host CPUs (Available Server Environment) can implement an xxshutdown interface to ensure that the SCSI adapter on the shutdown host CPU is not performing any operations on the bus.
You must have previously registered the device driver's xxshutdown interface by calling the drvr_register_shutdown interface.
None
Checks that the device is valid for this controller
The driver structure
int xxslave
(device,
bus_io_handle)
struct device
*device;
io_handle_t
bus_io_handle;
A device driver's xxslave interface is called only for a controller that has slave devices connected to it. This interface is called once for each slave attached to the controller.
The first argument for a driver's slave interface is always a pointer to a device structure. You can use the device structure pointer to reference such information as the logical unit number of the device, whether the device is functional, and the bus number the device resides on.
The second argument associated with a driver's slave interface is bus-specific. To write portable device drivers across multiple bus architectures, you need to know the second argument associated with the slave interface for that bus. See the bus-specific driver book for a description of the second argument associated with the slave interface for that bus.
The Synopsis section shows the arguments associated with a slave interface for a TURBOchannel bus.
The xxslave interface returns a nonzero value if the device is present.
Stops data transmission
The dsent table
void xxstop
(tp,
flag)
struct tty
*tp;
int
flag;
Terminal device drivers use the xxstop interface to suspend transmission on a specified line. The xxstop interface is called when the terminal driver has recognized a stop character such as ^S. There are also specific ioctl calls that request that output on a terminal line be suspended. These ioctl calls result in the general terminal driver interface calling the associated device driver's xxstop interface.
Typically, the xxstop interface sets the terminal's state to stopped. This action causes output to be suspended until the stopped state is cleared. For example, the stopped state may be cleared upon receipt of a start character such as ^Q.
None
Performs block I/O for block devices and initiates read and write operations for character devices
The dsent table
int xxstrategy
(bp)
struct buf
*bp;
The xxstrategy interface performs block I/O for block devices and initiates read and write operations for character devices.
Typically, this interface is not called directly from user-level programs; instead, the interface is called from different interfaces within the kernel. For the block driver, it is the xxstrategy interface that implements the concept of disk partitions. Disk partitions involve subdividing the physical disk into smaller logical disk partitions. Through the use of partition tables that define partition boundaries, the xxstrategy interface maps read and write requests to the correct disk offset.
The main user of the block device is the file system. File system reads and writes are usually handled through kernel interfaces. Through these interfaces and the interfaces that they call, the data is read from or written to the data cache. When the data being read is not present in the data cache, the system calls the block device xxstrategy interface to initiate a data transfer to read in the data from the disk. When a decision is made to flush the written data out of the data cache to the disk media, the system calls the block driver xxstrategy interface to initiate the transfer.
None
Writes data to a device
The dsent table
The device driver for the raw block device is both a block and a character driver. When accessed as a block device, the system uses the driver's strategy interface as the entry point. When accessed as a character device, the driver's read and write interfaces are used as the entry points.
int xxwrite
(dev,
uio,
flag)
dev_t
dev;
register struct uio
*uio;
int
flag;
Device driver writers use the dev_t data type to represent a device's major and minor numbers. This data type is an abstraction of the internal representations of the major and minor numbers. Driver writers do not need to know how the system internally represents the major and minor numbers.
The xxwrite interface is called from the I/O system as the result of a write system call. The xxwrite interface checks the software state of the device to determine if the device is in a state that permits the write operation. If not, xxwrite places the device into a writable state and writes data to the device. (Note that read/write permission is checked at the file system level, not in the device driver.)
If necessary, xxwrite allocates a private kernel buffer. It uses the uiomove kernel interface to copy the data of the user process into the private kernel buffer. It then sets up the software state of the device for the current output transfer and starts the hardware transferring the data. Following this action, xxwrite puts the process to sleep and wakes it after all of the data in the current transfer has been sent to the device.
If the device is a raw block device, the xxwrite interface calls the physio kernel interface to accomplish the write. For terminal-oriented devices, the device driver passes the write request to the generic terminal interface.
Upon successful completion of the write request, the xxwrite interface returns ESUCCESS. Otherwise, xxwrite can return error constants defined in the /usr/sys/include/sys/errno.h file. The following describes some typical constants that xxwrite can return:
Some xxwrite interfaces can also return the value returned in a call to the physio interface.
dsent, fcntl.h, physio, uio, uiomove, xxread
Reference Pages Section 2: write
Table 4-2 summarizes the bus configuration interfaces related to device drivers. Following the table are descriptions of each interface, presented in alphabetical order.
Bus Interface | Summary Description |
adp_handler_add | Registers a driver's interrupt handler. |
adp_handler_del | Deregisters a driver's interrupt handler. |
adp_handler_disable | Signifies that the driver's interrupt handler is not callable. |
adp_handler_enable | Signifies that the driver's interrupt handler is now callable. |
adp_unattach | Cleans up any in-memory data structures. |
bus_search | Searches a bus structure for specified values. |
conn_bus | Connects bus structures. |
conn_ctlr | Connects a controller structure to a bus structure. |
conn_device | Connects a device structure to a controller structure. |
ctlr_search | Searches for a controller structure connected to a specific bus. |
get_bus | Searches the static bus_list array for a bus structure. |
get_ctlr | Searches the static ctlr_list array for a controller structure. |
get_ctlr_num | Gets a controller structure that matches the specified controller name and number. |
get_device | Searches for the next device in a controller structure. |
get_sys_bus | Returns a pointer to a system bus structure. |
perf_init | Initializes the performance structure for a disk device. |
xxconfl1 | Configures the specified bus. |
xxconfl2 | Configures the specified bus. |
Registers a driver's interrupt handler
ihandler_id_t (*bus->framework->adp_handler_add)
(handler)
ihandler_t
*handler;
The adp_handler_add interface registers a driver's interrupt service interface with the appropriate parameters into the bus-specific interrupt dispatching algorithm. The ihandler_t data structure contains all of the information needed to register the interrupt handler. This information includes the interrupt service interface name and its associated formal parameter.
The Synopsis section shows that the name of the adp_handler_add interface is obtained through the bus structure's framework member. This member is a pointer to a bus_framework structure, which contains a pointer to the actual adp_handler_add interface.
The return value of adp_handler_add is a bus-specific ``key'' that can later be passed to the other adp_handler interfaces to identify the interrupt service interfaces to act upon. If adp_handler_add returns an error status, the return value for this ``key'' is -1. When adp_handler_add returns to the generic handler_add interface a value of -1, handler_add returns an error status to its caller indicating that the handler add operation failed.
bus, adp_handler_del, adp_handler_disable adp_handler_enable, ihandler_t
Deregisters a driver's interrupt handler
int (*bus->framework->adp_handler_del)
(id)
ihandler_id_t
id;
The adp_handler_del interface deregisters a driver's interrupt service interface. One task this interface might perform consists of replacing the driver's interrupt service interface with the stray interface. The adp_handler_del interface fails if adp_handler_disable was not previously called.
The Synopsis section shows that the name of the adp_handler_del interface is obtained through the bus structure's framework member. This member is a pointer to a bus_framework structure, which contains a pointer to the actual adp_handler_del interface.
The adp_handler_del interface returns the value zero (0) on success and the value -1 on an error.
bus, adp_handler_add, adp_handler_disable adp_handler_enable,
Signifies that the driver's interrupt handler is not callable
int (*bus->framework->adp_handler_disable)
(id)
ihandler_id_t
id;
The adp_handler_disable interface specifies that the driver's interrupt service interface should not be called through the bus-specific interrupt dispatching algorithm. The adp_handler_disable interface must be called to disable the device's interrupt service interface prior to calling the adp_handler_del interface.
The Synopsis section shows that the name of the adp_handler_disable interface is obtained through the bus structure's framework member. This member is a pointer to a bus_framework structure, which contains a pointer to the actual adp_handler_disable interface.
The adp_handler_disable interface returns the value zero (0) on success and the value -1 on an error.
bus, adp_handler_add, adp_handler_del, adp_handler_enable
Signifies that the driver's interrupt handler is now callable
int (*bus->framework->adp_handler_enable)
(id)
ihandler_id_t
id;
The adp_handler_enable interface signifies that the driver's interrupt service interface is now callable by the bus-specific interrupt dispatching algorithm. This interface fails if adp_handler_add was not previously called.
The Synopsis section shows that the name of the adp_handler_enable interface is obtained through the bus structure's framework member. This member is a pointer to a bus_framework structure, which contains a pointer to the actual adp_handler_enable interface.
The adp_handler_enable interface returns the value zero (0) on success and the value -1 on an error.
bus, adp_handler_add, adp_handler_del, adp_handler_disable
Cleans up any in-memory data structures
int (*bus->framework->adp_unattach)
(bus_struct)
struct bus
*bus_struct;
The adp_unattach interface is called whenever an adapter is being removed from the configuration. All controllers that might be present on it have already been disabled. This interface is responsible for cleaning up any in-memory data structures that may exist as well as any interrupt service interfaces that might have been connected.
The Synopsis section shows that the name of the adp_unattach interface is obtained through the bus structure's framework member. This member is a pointer to a bus_framework structure, which contains a pointer to the actual adp_unattach interface for this adapter.
The adp_unattach interface returns the value zero (0) on success and the value -1 on an error.
adp_handler_add, adp_handler_del, adp_handler_disable, adp_handler_enable
Searches a bus structure for specified values
struct bus * bus_search
(bus_name,
slot)
char
*bus_name;
int
slot;
The bus_search interface searches the bus_list array for a bus structure with values that match the parameters you specify. You use this interface with buses that have autoconfiguration capability.
The interface returns a zero (0) when no values match. If the bus_name argument matches the name of a bus in the bus_list array, the interface returns a pointer to the bus's associated bus structure.
Connects bus structures
void conn_bus
(hdbus,
bus)
struct bus
*hdbus;
struct bus
*bus;
The conn_bus interface logically connects the second bus structure you pass to the first bus structure you pass. Specifically, the bus_hd member in the second bus structure is set to the first bus structure you pass, and the second bus structure is added to the list of buses connected to the first (the bus_list member in the first bus structure).
None
Connects a controller structure to a bus structure
void conn_ctlr
(bus,
ctlr)
struct bus
*bus;
struct controller
*ctlr;
The conn_ctlr interface logically connects the controller structure you pass to the bus structure you pass. Specifically, the bus pointer becomes the bus_hd member in the controller structure; the pointer to the next controller on the bus (the nxt_ctlr member in the controller structure) is added to the ctlr_list (the list of controllers) member in the bus structure.
None
bus, bus_search, controller, ctlr_search, get_bus, get_ctlr
Connects a device structure to a controller structure
void conn_device
(ctlr,
device)
struct controller
*ctlr;
struct device
*device;
The conn_device interface logically connects the device structure you pass to the controller structure you pass. Specifically, the controller structure pointer you pass (the ctlr argument) becomes the ctlr_hd pointer in the device structure; the device pointer is added to the list of devices on the controller (the dev_list member) in the controller structure.
None
controller, ctlr_search, device, get_ctlr, get_device
Searches for a controller structure connected to a specific bus
struct controller * ctlr_search
(num,
name)
int
num;
char
*name;
The ctlr_search interface searches for a controller structure connected to a specific bus. Buses without autoconfiguration capabilities use this interface. You call this interface repeatedly until all controllers connected to the specified bus are found.
The interface returns the value zero (0) when no (or the last) controllers are connected to the bus you specify. Otherwise, it returns a pointer to the controller structure connected to this bus.
bus, conn_ctlr, controller, get_ctlr
Searches the static bus_list array for a bus structure
struct bus * get_bus
(name,
slot,
bus_name,
num)
char
*name;
int
slot;
char
*bus_name;
int
num;
The get_bus interface searches the static bus_list array for a bus structure that matches values you pass. Buses that can automatically configure themselves use this interface.
The interface returns the value zero (0) if none of the values you pass matches. Otherwise, the interface returns a pointer to the bus structure associated with the bus in bus_list whose values match those you passed.
Searches the static ctlr_list array for a controller structure
struct controller * get_ctlr
(ctlr_name,
slot,
bus_name,
bus_num)
char
*ctlr_name;
int
slot;
char
*bus_name;
int
bus_num;
The get_ctlr interface searches the static ctlr_list array for a controller structure whose values match the ones you pass. Buses that can automatically configure the bus use this interface.
The get_ctlr interface returns the value zero (0) if the values you pass do not match those in the associated members in the controller structures residing in ctlr_list. Otherwise, the interface returns a pointer to the controller structure that matches the values you passed.
Gets a controller structure that matches the specified controller name and number
struct controller * get_ctlr_num
(ctlr_name,
ctlr_num)
char
*ctlr_name;
int
ctlr_num;
The get_ctlr_num interface searches the static ctlr_list array for a controller structure with values that match the passed parameters. Specifically, get_ctlr_num compares the values passed to the ctlr_name and ctlr_num arguments to the ctlr_name and ctlr_num members for each controller structure in the ctlr_list array.
Graphics device drivers use this interface to gain access to a specific controller data structure, for example, fb0. This action occurs during console initialization when the controller structures are not connected to devices.
The get_ctlr_num interface returns the value zero (0) if the values you pass do not match any of the controller structures in ctlr_list. Otherwise, the interface returns a pointer to the controller structure that matches the values you passed.
controller, ctlr_search, get_ctlr, get_device
Searches for the next device in a controller structure
struct device * get_device
(ctlr)
struct controller
*ctlr;
The get_device interface returns a pointer to the device structure associated with the next device that was connected to the controller in the system configuration file.
The get_device interface returns the value zero (0) if there was no device connected to the controller associated with the specified controller structure. Otherwise, it returns a pointer to the device structure associated with the next device that was connected to the controller in the system configuration file.
controller, ctlr_search, device, get_ctlr
Returns a pointer to a system bus structure
struct bus * get_sys_bus
(bus_name)
char
*bus_name;
The get_sys_bus interface searches the bus_list array for the system bus structure that matches the name you specified in the bus_name argument. A system bus structure is one whose connect_num member is set to the value -1. The system bus structure is sometimes referred to as nexus.
The get_sys_bus interface causes the following system panic message if the bus_name argument you specified does not match the bus_name member of any system bus structure in the bus_list array:
No system bus structure
If the name matches, however, the interface returns a pointer to the associated system bus structure.
Initializes the performance structure for a disk device
void perf_init
(device)
struct device
*device;
The perf_init interface initializes the performance structure for a disk device. This interface sets the private member of the device structure associated with this disk device to the value -1 if the dev_type member of the specified device structure points to the string disk and the number of disk units on the system is less than 256.
None
Configure the specified bus
void xxconfl1
(bus_type,
bus_info,
bus)
int
bus_type;
caddr_t
bus_info;
struct bus
*bus;
void xxconfl2
(bus_type,
bus_info,
bus)
int
bus_type;
caddr_t
bus_info;
struct bus
*bus;
The xxconfl1 and the xxconfl2 interfaces perform configuration tasks for the bus. The system first calls xxconfl1 interfaces for all buses and then calls xxconfl2 interfaces for all buses.
None