Directories
-----------

The I/O manager framework always creates a directory for your devices,
even if you only have one device.  If you were to run the
pipe sample code as:

    pipe a &

then you would have /testing with device 'a' under it.  If you were to run
it as:

    pipe -p/pipes a b &

then you would have /pipes with devices 'a' and 'b' under it.

The directory management code adds only about 4k to your code size.
The default maximum number of devices you can create is 8.  You can
override this maximum using the -n option.

    pipe -n10 a b &

The above example will allow you to create up to 10 devices.

The only function which you provide for directory management is
a create function which is called whenever creating a new device
under a directory.  This function is the only mandatory function
and is described in detail below in the section called "The create_dev
Function".

For the example above create_dev is called when devices 'a' and 'b' are
being created.  It is also called if you do something like:

    touch /pipes/c

This would have the effect of creating a third device called 'c'
under /pipes.
    

The create_dev function
-----------------------

You must supply a function with the following name and prototype:

    int create_dev( inode_t **ip )
    
create_dev() will be called whenever a device is created (for example
by a process calling open() with O_CREAT).  It's job is to create an
instance of an inode_t, fill it out, and return with *ip containing
the address of the new inode_t.

The following are steps that you should consider doing.  The order
in which they are done is important.

Step 1.
    Fill out an instance of type iofuns and set its members to the addresses
    of functions to called whenever I/O is being done to the device.
    Leave the addresses of any functions that you are not providing
    as 0.  Default functions will be provided for these.
    
    This need only be done once for all devices of a particular type.
    For example if you are making an I/O manager to manage multiple
    pipes then all of those pipes will use the same set of functions.
    Therefore only one instance of an iofuns would be needed and it
    will only need to be filled out the first time create_dev() is called..

    <-- code snippet starts here ---------------------------------------->
    int
    create_dev(inode_t **ip)
    {
        inode_t         *io;
        static iofuns   pclass;

        if (!pclass.write) {
            /*-
             * pipe_write and pipe_read are functions that can be found
             * in the example pipe.c
             */
            pclass.write = pipe_write;
            pclass.read  = pipe_read;
        }
        ...
    }
    <-- code snippet ends here ------------------------------------------>

Step 2.
    Each device will need its own instance of an inode_t.  Create the
    instance of inode_t by calling inode_alloc().  It allocates memory
    for an inode_t and returns a pointer to it.  Pass inode_alloc() the
    address of the iofuns set up in step 1.  Note that the the address
    of the iofuns will be copied, not its contents.
    
    <-- code snippet starts here ---------------------------------------->
    int
    create_dev(inode_t **ip)
    {
        inode_t         *io;
        static iofuns   pclass; /* notice that this is static */

        ...
        if ((io=inode_alloc(&pclass)) == 0) {
            /* do any cleanup here */
            return ENOMEM;
        }
        ...
        *ip = io;
        return EOK;
    }
    <-- code snippet ends here ------------------------------------------>

Step 3.
    Each class or type of device has a particular major device number.
    The first time the iofuns is passed to inode_alloc() this major
    device number is obtained and filled into the "major" member of
    iofuns.  All subsequent calls to inode_alloc() that are passed that
    same iofuns will use that same major device number.
    
    Each device that uses that major device number also has a unique
    minor device number.  If more than one device will be created then
    you will also want to increment iofuns.minor.  Do this after the call
    to inode_alloc() (i.e. after step 2).  So if iofuns.minor was initially
    0 then the device currently being created will have a minor device
    number of 0 and since you've incremented it, the next device that is
    create will have a minor device number of 1.

    <-- code snippet starts here ---------------------------------------->
    int
    create_dev(inode_t **ip)
    {
        inode_t         *io;
        static iofuns   pclass;

        ...
    }
    <-- code snippet ends here ------------------------------------------>

Step 4.
    Modify any other parts of the inode_t.
