HPlogo STREAMS/UX for the HP 9000 Reference Manual > Chapter 5 How to Compile and Link STREAMS/UX Drivers, Modules, and Applications

Linking STREAMS/UX Drivers and Modules into the Kernel

» 

Technical documentation

Complete book in PDF

 » Table of Contents

 » Index

Linking STREAMS/UX drivers and modules into the kernel is a multi-step process. A summary of the steps is:

  1. Create or modify your master file to reflect changes.

  2. Add a driver header with the information previously located in the
    /etc/master
    file into the etc/master.d directory.

  3. Add a driver install routine for both STREAMS drivers and STREAMS modules ("driver" in the case of the STREAMS subsystem refers to both STREAMS drivers and STREAMS modules).

  4. Adjust any STREAMS/UX tunables if necessary.

  5. Create your library and copy it to /usr/conf/lib.

  6. Re-generate your kernel using mk_kernel(1).

  7. Once the system is re-booted, use lsdev(1M) to determine the value of any dynamically-assigned major numbers, if applicable.

  8. Create device files with mknod(1M).

Details about the Driver Header, Driver Install Routine, and lsdev(1) follow.

Adding Driver Header and Driver Install Routine

The STREAMS driver writer must add a driver header and a driver install routine for their STREAMS drivers and modules. The driver header consists of three data structure declarations (for a STREAMS driver and actually only one for a STREAMS module). The driver install function will get called by the I/O system to "install" your pseudo driver into the I/O subsystem tables. The driver header essentially contains the information previously contained in the master file.

The main job of your driver install routine is to call one or both of the functions, install_driver (CDIO3) and/or str_install().

For a STREAMS driver, your driver install routine will need to call both the function install_driver (CDIO3) and str_install(). And for a STREAMS module, your driver install routine will only need to call the str_install() routine.

The call to install_driver() initializes the cdevsw entry points and d_flags for your STREAMS driver. The call to the str_install() function fills out either the dmodsw (for a STREAMS driver) or the fmodsw (for a STREAMS module) switch tables used by the STREAMS subsystem.

NOTE: The str_install() function will replace the open, close, read, write, ioctl, select, and option1 cdevsw entry points with the STREAMS/UX-specific entry points. So it is best to use NULLs in the drv_ops_t structure as illustrated in the example later in this section.

Keep in mind that you can call your driver_link routine from the driver install to perform any necessary driver initialization tasks. You should not perform any operations which require returning error conditions or data. Plus, it is best to keep driver install routines small and clean to avoid bootup problems.

If you are writing MP STREAMS drivers and STREAMS modules, refer to Chapter 4 for specific MP requirements. Chapter 4 provides examples of driver headers and driver install routines relating to MP drivers and modules.

The driver header can be declared in either a .h or in the .c file that contains the driver install entry point. The driver install entry point MUST be in a .c file.

For both STREAMS drivers and STREAMS modules, the following include files contain the needed structures and defines:

#include "../h/conf.h"
#include "../h/stream.h"

Streams Driver

For STREAMS drivers, the following data structures will need to be declared in the .h or .c file: drv_info_t, drv_ops_t and streams_info_t.

An example of these declarations using the STREAMS test driver, "tlo" is as follows: (The STREAMS tlo test driver is used only as an example throughout this section. Please tailor this example to your specific driver configuration).

drv_info_t

static drv_info_t tlo_drv_info = {
"tlo", /* driver name */
"pseudo", /* driver class */
DRV_CHAR | DRV_PSEUDO | DRV_MP_SAFE, /* flages */
-1, /* block major number */
-1, /* char major number */
NULL, NULL, NULL, /* cdio, gio_private and
cdio_
private always NULL
*/};
drv_ops_t

static drv_ops_t tlo_drv_ops = {
NULL, /* d_open */
NULL, /* d_close */
NULL, /* d_strategy */
NULL, /* d_dump */
NULL, /* d_psize */
NULL, /* d_mount */
NULL, /* d_read */
NULL, /* d_write */
NULL, /* d_ioctl */
NULL, /* d_select */
NULL, /* d_option1 */
NULL, NULL, NULL, NULL, /* reserved entry points */
NULL, /* d_flags */
};
streams_info_t

static streams_info_t tlo_str_info = {
"tlo", /* name */
-1, /* dynamic major number */
{ &tlorinit, &tlowinit, NULL
NULL }, /* streamtab */
STR_IS_DEVICE | MGR_IS_MP | /* streams flags */
STR_SYSV4_OPEN,
SQLVL_QUEUE, /* sync level */
"", /* elsewhere sync name */
};

The definitions of the streams_flags used in the streams_info_t structure are (see stream.h and conf.h):

STR_IS_DEVICE   /* Indicates a driver is being installed */
STR_IS_MODULE /* Indicates a module is being installed */
STR_SYSV4_OPEN /* Indicates SVR4 open is being used, SVR3 open
is default */
MGR_IS_MP /* Module/driver is MP-scalable */

The sync level used in the streams_info_t structure is one of the following defined in stream.h:

SQLVL_DEFAULT 
SQLVL_GLOBAL
SQLVL_ELSEWHERE
SQLVL_MODULE
SQLVL_QUEUEPAIR
SQLVL_QUEUE

For STREAMS drivers, a driver install routine needs to be added to the .c file for your driver. This function MUST be called xxxx_install, where xxxx is the driver handle used for your driver. Exactness is needed so that your driver install routine is correctly called by the I/O subsystem during bootup.

Illustrated below is an example of the driver install routine for the example tlo driver.

int
tlo_install()
{
int retval;

if ((retval = install_driver (&tlo_drv_info, &tlo_drv_ops)) !=0)
return (retval);

if ((retval = str_install (&tlo_str_info)) !=0) {
uninstall_driver (&tlo_drv_info);
return (retval);
}
return (0); /* return success */
}

In this tlo example, a major number of -1 was defined in both the tlo_drv _info and tlo_str_info structure declarations. This invokes the dynamic major facility. When using this facility, you will need to obtain the system assigned "dynamic" major number by running the lsdev(1) command after the system has rebooted with the kernel that includes your driver. There are details later in this section on lsdev(1).

STREAMS Module

For STREAMS modules, steps identical to those executed for a STREAMS driver are needed, but with the following exceptions:

For the driver header, you only need to declare a streams_info_t structure. This is because STREAMS modules do not have any cdevsw-related information. They only have STREAMS-specific information and this is configured by calling str_install() with a defined streams_info_t.

For the driver install routine, you need only to call the str_install() function. There is no need to call install_driver(CDIO3).

An example of these declarations using the STREAMS test module, "lmodb," is as follows: (The STREAMS lmodb test module is used only as an example. Please tailor this example to your specific module configuration).

streams_info_t

static streams_info_t lmodb_str_info = {
"lmodb", /* name */
-1, /* major number */
{ &lmodbrinit, &lmodbwinit, NULL, NULL},/* streamtab */
STR_IS_MODULE, /* streams flags */
SQLVL_QUEUEPAIR, /* sync level */
"", /* elsewhere sync name */
};

The streams_flags and the sync level to be used in the streams_info_t structure are the same as illustrated above in the "STREAMS Driver" section, except we are using "STR_IS_MODULE," instead of "STR_IS_DEVICE."

Illustrated below is an example of the driver install routine required for a STREAMS module, using the example lmodb module.

int
lmodb_install()
{
int retval;

if ((retval = str_install (&lmodb_str_info)) != 0)
{
return (retval);
}
return 0; /* return success */
};

Modifying Your Master File

In 10.0, the /etc/master file is replaced by a collection of files located in /usr/conf/master.d directory. It is recommended that you create your own individual master file, calling it something appropriate. See
/usr/conf/master.d/streams
for the master file used by the STREAMS/UX framework. You may use the STREAMS master file as a template for creating your specific master file.

You will need to add entries for each of your STREAMS drivers to the $DRIVER_INSTALL section of your master file. See the master(4) manpage for a description of the master file section layouts and dynamic major numbers.

An example $DRIVER_INSTALL section from the STREAMS/UX master file is as follows:

$DRIVER_INSTALL
*************************************************************************
* Driver install table
*
* This table contains the name of drivers which have converged I/O header
* structures and install entry points. Drivers in this table should not
* be defined in the driver table above.
*************************************************************************
* Driver Block major Char major
clone -1 72
strlog -1 73
sad -1 74
echo -1 116

* Example driver entry which must use dynamic major numbers indicated by -1
tlo -1 -1

In addition, you will also need to add additional entries for any STREAMS modules to the $DRIVER_INSTALL section as well. Using the example lmodb module:

$DRIVER_INSTALL
*************************************************************************
* Driver install table
*
* This table contains the name of drivers which have converged I/O header
* structures and install entry points. Drivers in this table should not
* be defined in the driver table above.
*************************************************************************
* Driver Block major Char major
lmodb -1 -1

When adding an entry to the $DRIVER_INSTALL section of your master file, do NOT add an entry to the $DEVICE section of your master file. This will result in a possible conflict (such as duplicate major numbers) and/or a lack of a call to your driver install routine at bootup. The only way to use the dynamic major number facility is to configure your STREAMS driver as documented in this section.

For more details on driver headers and driver install routines, please read the HP-UX Driver Development Guide (P/N 98577-90000-E1).

Dynamically-Assigned Major Numbers and lsdev(1)

When using the dynamic major number facility, you will need to determine which major number was assigned to your driver during bootup, by consulting lsdev(1). Once the system is booted with your new kernel, run the lsdev(1) command. See the lsdev(1) manpage for all the option details, but in brief you can use lsdev(1) as shown below.

NOTE: For STREAMS-clonable devices, use 72 for the major and your driver's assigned major number for the minor number.
lsdev -h -d <your_driver_name_here>

(the -h means that lsdev does not print a header)

and use the result for your mknod(1M):

mknod /dev/<device_file_name> c 72  0x<dyn_major result>

mknod /dev/<device_file_name> c <dyn_major result> 0x0

The first mknod command is for a clonable device. The second is for a non-clonable device.

© 1995 Hewlett-Packard Development Company, L.P.