Linux STREAMS (LiS)


Configuration

Contents

Introduction

Config Files

SVR4 Compatibility

Loadable STREAMS Drivers and Modules

The strconf Utility

Configuration File Syntax

Driver Specification 

Module Specification 

Node Specification

Device Specifications

Driver Initialization Specification

Driver Termination Specification

Driver Interrupt Specification

Object Name Specification

Loadable specification

Autopush Specification

Tunable Parameter Specification 

The Space.c File 

A Simple Example

Installing Your Driver

 

Introduction

When LiS is built, its makefiles gather configuration information about the STREAMS drivers that are to be linked in with LiS. This information comes from several ASCII files within the LiS directory tree. 

Once all of the configuration information is consolidated into a single file, the file is processed by a utility program strconf to produce several output files, which, in turn, are input to the final stages of the LiS build process. 

This document describes this process and the strconf program itself. 

Back to Contents

Config Files 

There are several locations in the LiS directory tree in which a file by the special name Config appears. Each Config file describes configuration information for one or more STREAMS drivers. These Config files are all concatenated together for processing by the strconf utility program. 

Drivers that are built into LiS are located in the directory /usr/src/LiS/drivers/str. This directory contains a Config file which describes these drivers for the strconf program. In this case a single Config file describes multiple drivers. 

Drivers that are added to LiS in binary form at build time reside in subdirectories of the directory /usr/src/LiS/pkg. Each subdirectory contains a Config file for its own driver. All such Config files are concatenated into the directory /usr/src/LiS/pkg into a file named config.pkg

During the LiS build procedure, in the directory /usr/src/LiS, the Config file from the drivers/str directory is concatenated with the config.pkg file into a file named Config.master. This file is processed by the strconf utility to produce the files config.h, modconf.c and makenodes.c

The config.h file is available to be included in the compilation of individual Space.c files which appear in the /usr/src/LiS/pkg subdirectories. The contents of the config.h file summarize the information contained in the Config files in C language #defines which can be used for building driver configuration tables.  It is placed in the directory /usr/src/LiS/include/sys/LiS.

The modconf.c file is compiled as a component of LiS. It contains initialized tables for all of the STREAMS drivers and pushable modules that LiS is configured to manage. 

The makenodes.c file is compiled into a utility program, makenodes, which will create all of the entries for STREAMS drivers in the /dev directory. 

Back to Contents

SVR4 Compatibility

Configuration of drivers in LiS is similar in flavor to the method used in SVR4, but is different in almost all details. Included with LiS is a PERL script (nodeconfig.pl) that can be used to process an SVR4 Node(4dsp) file into an LiS Config file. This is an unsupported contribution from an LiS user.

Back to Contents

Loadable STREAMS Drivers and Modules 

In order to support loadable STREAMS drivers and modules, the LiS configuration file language contains keywords to support the notion of object files. 

An object file contains one or more drivers or modules. It is typically a file with suffix ".o" containing linkable object code built by compiling C language source with the "-c" option. 

By default, object files are linked with LiS at compile time, but you can use the "loadable" keyword in a Config file to specify that an object file should be considered a kernel loadable module. This allows individual STREAMS drivers or modules to have the status of Linux loadable modules. 

For an example of this observe how the "ldl" driver is built and installed as a part of the LiS package itself. The driver source resides in drivers/str/linux. The Config file that contains enties for "ldl" is in drivers/str. You can observe the LiS build process to see how the driver is named and copied to the appropriate subdirectory of /lib/modules.

You can place a Config file in a subdirectory of the pkg directory without placing any driver object code there. This is sufficient for LiS to process your Config file entries and make proper preparations for your loadable driver, such as assigning it a major device number. See the document section on installing pre-compiled drivers for more information on this process.

If the kernel is configured with support for kerneld(8), a loadable module will be demand loaded. All kernel module names defined within LiS begin with the prefix "streams" to avoid name clashes with other Linux kernel modules. 

For a non-clone device, the kernel will demand load the module under the name "char-major-nn". This will cause kerneld(8) to autoload a Linux kernel module using the aliases in /etc/conf.modules (or /etc/modules.conf). If /etc/conf.modules contains an alias for a STREAMS driver then the driver can be autoloaded via this mechanism. To the kernel a loadable STREAMS driver is just a character driver known by its major device number. 

When the clone device is opened for a major configured in a loadable object file "myobj" (for example), LiS will ask kerneld(8) to load "streams-myobj". If this fails, LiS tries to demand load a module named "char-major-nn". If this also fails, an error is logged and the open fails. 

When the name of a STREAMS module "mymod" configured in a loadable object file "myobj" is used for I_PUSH, LiS demand loads a kernel module named "streams-myobj". If this fails, LiS will try to demand load a kernel module named "streams-mymod". If this also fails, an error is logged and the I_PUSH fails. 

When an unknown module name "mymod" is used for I_PUSH, LiS tries to demand load a kernel module named "streams-mymod". 

The strconf utility will emit a file with the aliases needed for kerneld(8) support. This file can be incorporated into the file /etc/conf.modules. Refer to the "-L" option for the strconf utility, below. 

Back to Contents

The strconf Utility 

In order to construct a Config file, it is useful to know the syntax of the contents of the file. The strconf utility is used to process a Config file and generate the output files mentioned above. 

Command Line Syntax 

strconf options input-file

The options for strconf consist of zero or more of the following. 
 

  -bnumber

Set the base major number for automatic assignment of major device numbers. The LiS Configure script, run from the top level "make", uses the value of the environment variable LIS_MAJOR_BASE to set this parameter, or a default value if this variable is not defined. By defining this symbol in your environment you can override the default base for major device numbers.

  -hfile

Set the output header file name to something other than the default "config.h".

  -lfile

Set the output driver configuration makefile include file name to something other than the default "drvrconf.mk".

  -Lfile

Set the output Linux loadable module configuration file name to something other than the default "conf.modules".

  -mfile

Set the output file name for the program that will make the nodes to something other than "makenodes.c". This program is compiled and then run to create all the /dev entries for the STREAMS drivers.

  -Mname

The name of the mknod() routine to call in the makenodes.c program. The default is "mknod".

  -ofile

Set the output file name to something other than the default name "modconf.c". This is the file that must be linked in with STREAMS.

  -pperm

Set default permissions to something other than 0666 for /dev entries created by the makenodes.c program.

  -rname

The name of the routine to build in makenodes.c. The default is "main".

The input-file parameter is the name of the file containing the configuration information in ASCII. 

Example: 

strconf -b51 config.master

This command bases the major device numbers for STREAMS drivers at 51 and outputs files to the standard places. 

Back to Contents

Configuration File Syntax 

The input to the strconf program is informally referred to as a Config file. This file consists of lines of ASCII text which is interpreted by the strconf program. 

Blank lines are ignored. The "#" serves as a comment symbol, terminating any line on which it appears. 

Input to strconf consists of a series of tokens, which are strings of ASCII characters with no embedded white space. Some tokens are keywords known to strconf; some are numbers in C language syntax; some are identifiers supplied by the user to give names to drivers, etc. Tokens are separated from one another by white space. 

Each line in the file is self-contained. That is, a construct consisting of a keyword followed by its arguments must all appear on the same line of the file. 

Strconf processes lines for the following constructs. 

Back to Contents

Driver Specification 

driver driver-name prefix major minors 

driver-name is the name of the STREAMS driver (not pushable module), for example loop-around. It is any string of characters not including "white space" characters. 

prefix is alphanumeric, plus underscore, and will be prefixed to any table entries referencing variables within this driver. For example, the prefix loop_ will be used to derive the reference to the streamtab entry loop_info. The driver must have a variable declared within it by the name prefixinfo of type struct streamtab

major specifies the major device number that will be assigned to the device. The character "*" means that the config program will choose the major number. A numeric value is used as it is given. 

minors is the number of minors the device has. If this field is omitted, the number 1 will be used. The value of this field is not used for anything except to generate a #define in the config.h output file. 

Example: 

driver loop-around loop_ *

This declares a driver which has the name "loop-around" for reference purposes within the strconf program. Its prefix is "loop_", and the strconf program is to assign its major device number. 

Back to Contents

Module Specification 

module name prefix

name is the name of the module, for example relay-mod. It is any string of characters not including "white space" characters. 

prefix is alphanumeric, plus underscore, and will be prefixed to any table entries referencing variables within this module. For example, the prefix relay_ will be used to derive the reference to the streamtab entry relay_info. The module must have a variable declared within it by the name prefixinfo of type struct streamtab

Example: 

module relay-mod relay_

This example declares a pushable module to be referred to internally as "relay-mod". Its prefix is "relay_". 

Back to Contents

Node Specification 

node dev-name type perm major minor

The keyword "node" introduces this entry. 

dev-name is the full path name of the device file to be created, for example, /dev/loop. 

type is the type of file to create. This consists of a single letter as follows: 
 
  b block special device (S_IFBLK)
  c character special device (S_IFCHR)
  p pipe device (S_IFIFO)

perm is the device permissions to use, 0666 gives everyone permission to use the device. perm can be "*" in which case default permissions are supplied (see -p command line option). 

major is the major device number to assign to this entry. It can be a number, but is usually the name of the associated driver entry. The major specified for the named driver is then used. 

minor is the minor device number to assign to this entry. It can be a number or the name of another driver. If the name form is used then the major number of the other driver is used as the minor number of the device being created. 

Example: 

    node /dev/loop c * loop-around 1 
    
    node /dev/loop_clone c * clone-drvr loop-around

The first example defines a device /dev/loop as a character special device with default permissions as minor device 1 of the "loop-around" driver. 

The second example defines a device /dev/loop_clone as a character device with default permissions with major device number equal to that assigned to the driver named "clone-drvr" and minor device number equal to that assigned to the driver named "loop-around". 

Back to Contents

Device Specifications 

These entries are used to describe the configuration of each physical device or port of a multi-port device on the system. Those familiar with the Unix sdevice file format will see some similarity to this format. The syntax for this type of entry is as follows: 

device driver-name unit port nports irq-share irq mem mem-size dma1 dma2

All 11 fields must be on the same line. Only the "device" keyword and driver-name fields are mandatory. 

driver-name is the name of the driver that handles the device. It must match the name of a declared driver in this file. 

unit is the unit number of the device being declared. A unit number means anything that the driver writer wants it to. It is assumed to be a small integer that will index a configuration table that is built from #defines generated by running this program. If this field is missing it is set to -1. 

port is the I/O port that the device uses. Set to -1 if the device does not use any I/O ports. If this field is missing it is set to -1. 

nports is the number of consecutive I/O ports used by the driver. If ports is -1 then nports can be any value, zero is suggested. If this field is missing it is set to zero. 

irq-share is a letter-coded field as follows: 
 
  n No sharing of IRQ
  s Sharing of IRQ
  S Sharing of IRQ but only with the same driver
  x Don't care, the device does not use an IRQ

If the irq-share field is missing it is defaulted to the value corresponding to "x". 

irq is the interrupt number for the device. The value -1 is used when the device does not have an interrupt. If this value is specified then it is assumed that there exists a routine with the name prefixintr, where prefix is the driver prefix specified in the driver section. If this field is missing it is set to -1. 

mem is the shared-memory address used by this device, if any. Set to 0 if the device does not use shared memory. If this field is missing it is set to zero. 

mem-size is the amount of shared memory used, in bytes. If this field is missing it is set to zero. 

dma1 and dma2 specify up to two DMA channels used by this device. Set to -1 if no DMA channels are being used. If either of these fields is missing it is set to -1. 

The device entry causes a set of #defines to be generated into the file config.h. This file may be #included into a driver configuration file to load tables, etc. The form of the #defines in the config.h file is compatible with the form used by Unix SVR4. Thus, if you are porting a STREAMS driver from SVR4 you can use a variant of your System file entries as the device entries and use the resulting config.h file in your existing Space.c file. 

The present implementation of LiS does not dispatch interrupts for STREAMS drivers. It is possible that some future version will do so, in which case the IRQ specifications will be more meaningful. At present these specifications only cause entries to be generated in the config.h file. You can utilize this information in a Space.c file to build a table that your driver uses to attach its IRQ from its initialization routine. 

Example: 

device cdip 0 0x310 8 S 10 0xD0000 0x4000

This example declares a device entry for the driver named "cdip". Its unit number field is zero. It has eight I/O ports starting at port address 0x310. The device can share IRQ10 with other devices of the same driver. It has shared memory based at 0xD0000 which is 16K bytes (0x4000) in size. It does not use any DMA channels. 

Back to Contents

Driver Initialization Specification 

initialize driver-name

The driver-name is the name of the driver whose "init" routine is to be called. The driver must supply a routine such as the following: 

void prefixinit(void)
{
}

Example: 

initialize loop-around

This leads to a call to the routine loop_init() since "loop_" is the associated prefix for the "loop-around" driver. This routine is called by LiS when LiS is initialized. If LiS is linked with the kernel then this call occurs at system boot time. If it is loaded as a module then the call occurs at module initialization time for LiS. 

Back to Contents
 

Driver Termination Specification 

terminate driver-name

The driver-name is the name of the driver whose "term" routine is to be called. The driver must supply a routine such as the following: 

void prefixterm(void)
{
}

Example: 

terminate loop-around

This leads to a call to the routine loop_term() since "loop_" is the associated prefix for the "loop-around" driver. This routine is called by LiS when LiS is terminating. If LiS is linked with the kernel then this call never occurs because LiS is never terminated. If LiS is loaded as a module then the call occurs at module termination time for LiS. This occurs just prior to unloading LiS from memory.
 
  Back to Contents

Driver Interrupt Specification 

interrupt driver-name

The driver-name is the name of the driver whose "intr" routine is to be attached. The driver must supply a routine such as the following: 

void prefixintr(void)
{
}

Example: 

interrupt loop-around

This causes LiS to register the driver's interrupt routine for each of the IRQs used in the driver's device specifications.  This occurs at module init time within LiS.  The routine is unregistered when LiS is unloaded.

Back to Contents

Object Name Specification 

objname type name object-name

The keyword "objname" specifies the base name of the object code file for a driver or module. Several drivers and modules may reside in the same object file. If an object-name is never specified for a driver or module, the object-name defaults to the name of the driver or module. 

type is either "driver" for a streams driver or "module" for a streams module. 

name is the name of the driver or module. 

object-name is the base name of the object code file used for this driver or module. 

The purpose of this keyword is twofold: 

  1. It specifies to the drivers/str make process the names of the object files that need to be compiled. These names need not be the same as the configuration names.
  2. If name is also specified as loadable and the Linux kernel is compiled with kerneld(8) support, LiS will demand load name by asking kerneld(8) for "streams-object-name".

Example: 

objname driver loop-around loop

Back to Contents

Loadable specification 

loadable object-name

The keyword "loadable" specifies that an object code file (as specified by the "objname" keyword) is a Linux kernel loadable module. If the kernel is compiled with kerneld(8) support, LiS will ask kerneld(8) to load the module on demand

Please note that you will have to explicitly declare object-name with the "objname" keyword first. Default object-names will not do for this keyword, as they may be changed later in the configuration file. 

Object-name is the base name of the object code file. 

Example: 

loadable loop

Back to Contents

Autopush Specification 

autopush driver-name minor last-minor module-list

The keyword "autopush" specifies a list of modules that should be pushed onto a stream when it is opened. 

driver-name is the name of a driver. The autopush specification only applies to this driver. 

minor specifies the first minor device number that this autopush specification applies to. If minor is -1, last-minor is ignored and the autopush applies to all minors of this driver. 

last-minor specifies the last minor in a range that this autopush specification applies to. If last-minor is 0, this autopush specification applies only to the single minor device number minor, otherwise last-minor must be greater than minor and the autopush applies to all minor devices of the named driver from minor to last-minor inclusively. 

module-list is a list of one or more STREAMS modules that should be pushed onto the stream when it is opened. The leftmost module is pushed first. 

  • Warning: Autopush status is currently "complete, untested". 
  • Example: 

    autopush loop-around 8 15 relay

    Back to Contents

    Tunable Parameter Specification 

    This type of entry allows you to insert define text into the output file (config.h default). These values can be used as parameters for drivers or the streams package itself. 

    The syntax is: 

    define name value

    The name is the identifier that is being defined. It must be constructed of characters that comprise a legal C language identifier. 

    The value is any text up to the end of the line. 

    The output for this entry is of the form: 

    #define name value

    Example: 

    define MAX_PORTS 16

    Generates the following in the output file: 

    #define MAX_PORTS 16

    Back to Contents

    The Space.c File 

    The Space.c file plays a role in LiS configuration similar to the file of the same name in Unix SVR4. It is a file associated with each driver package which contains configuration information for the driver. It is compiled during the LiS build phase. 

    The Space.c file can utilize information obtained by processing the Config files using strconf. This processing is automatic and is a part of the LiS build procedure. The strconf utility is run prior to compiling the Space.c file for each driver package. 

    The Space.c file can include the file config.h which contains #defines for the information gleaned from the Config files. This allows the Space.c file for a particular driver to capture this information in a table that the driver can consult during initialization. The LiS build procedure supplies the proper "-I" command line option to make the config.h file visible when compiling the Space.c files. 

    The #defines generated by strconf are of the following form. 

    For each driver: 
     
      #define prefix 1
      #define prefix_CTLS Nr-device-entries
      #define prefix_UNITS minors
      #define prefix_CMAJORS majors
      #define prefix_CMAJOR_0 assigned-major-device-number
      #define prefix_TYPE -1

    For each declared device: 
     
      #define prefix_unit 1
      #define prefix_unit_SIOA port
      #define prefix_unit_EIOA port+nports-1
      #define prefix_unit_VECT irq
      #define prefix_unit_SCMA mem
      #define prefix_unit_ECMA mem+mem-size-1
      #define prefix_unit_CHAN dma1
      #define prefix_unit_CHAN dma2

    Back to Contents

    A Simple Example 

    Let us suppose that you have a STREAMS driver for which you have chosen the prefix "xylo_". You need to make a Config file to go with your driver. In the Config file you need to declare the existence of your driver as follows. 

    driver mydrvr xylo_ *

    By doing this you are declaring that you have a driver named "mydrvr" which uses the symbol-name prefix "xylo_" and you don't care what its major device number is. The "mydrvr" is a name that you make up that is not used anywhere but in the Config file to refer to this driver. The "xylo_" is the prefix that you used in coding your driver. It is used to synthesize the name "xylo_info", the main streamtab structure for your driver. The "*" says that you don't care what major number your driver is assigned. The "n-minors" field is a place to say how many minor devices your driver handles, but it is not used anywhere, and thus is left empty. 

    Use the "driver" declaration for hardware drivers and STREAMS multiplexor drivers. 

    If your driver had been a pushable module rather than an actual driver then you would have used, something like the following. 

    module mydrvr xylo_

    You will probably want some /dev entries made so that you can access your driver via the stream head and the file system. Do that by including a "node" section of the Config file. For example: 

    #       name              type  perm    major           minor
    node    /dev/xylo            c  *       mydrvr          0
    node    /dev/xylo_clone      c  *       clone-drvr      mydrvr
               

    In this case we have added an entry that opens minor device zero (/dev/xylo) and a clone entry that will open your driver via the STREAMS clone driver (/dev/xylo_clone). The name "clone-drvr" is always present when LiS processes your Config file. 

    The clone driver is a special feature of STREAMS. You can read all about it in the reference documents, or the drivers page of the LiS documentation, but the gist of the idea is to make it easy for an application program to open a file to the STREAM and always get an available minor device. In the case of a non-clone device, the application has to "guess" as to which minor device numbers are unused. For a clone device, the driver itself assigns the minor device number and always picks one that is unused for the newly opened file. 

    The mechanism for the clone device involves the use of a special driver, the clone driver. It is declared in a Config file just like any other STREAMS driver under the name "clone-drvr". The clone driver has a specified major device number. It also has minor devices that are opened via directed (non-clone) opens. The minor device numbers of the clone driver are the major device numbers of another STREAMS driver. The clone driver's open routine calls the open routine of the second STREAMS driver by using the minor device number of the open to /dev/clone_drvr as the major device number of the driver whose open routine is to be called. 

    This is why the entry in the "node" section of the Config file for a clone device has the name of the clone driver in the major number field and the name of the driver which eventually gets the open call in its minor number field. 

    Note that the cflag parameter to the driver open routine will indicate a clone open if the open has passed through the clone driver. This allows your driver to distinguish between directed (non-clone) opens and clone opens. 

    Back to Contents

    Installing Your Driver 

    To install your driver so that it is linked with LiS when LiS is built you need to do the following. 

    Go to the directory /usr/src/LiS/pkg. Make a subdirectory for your driver. For example, mkdir xylo

    Then copy the object code (.o) file for your driver into that directory. Also copy your driver's Config file to that directory.  For a loadable driver, do not copy your driver's object code file to the pkg/xylo subdirectory, instead, copy it to /lib/modules/kernel-version/misc/streams-xylo.o. There are special considerations for demand loadable drivers.

    If your driver needs to build any tables for configuration based on the config.h file that is generated from running the LiS strconf utility then you need to create a file named Space.c and copy it to the pkg/xylo directory. 

    You also need to create a Makefile for your pkg/xylo directory. If you do not have a Space.c file then your Makefile can consist of just the following. 

    nothing:

    If you have a Space.c file then your Makefile can consist of this. 

    include ../proto/Makefile

    The ../proto/Makefile contains a rule to compile your Space.c file into Space.o

    That is all you have to do. The LiS build will concatenate your Config file with the LiS built-in Config file and produce a config.h file. It will enter your directory and perform a "make". It will then link in all files ending in ".o" from your directory into the streams.o file.  The streams.o file is the file that is loaded when the command insmod streams is executed.

    Back to Contents