[comp.unix.wizards] I/O Chain Programs and C

wilcox@nosc-tecr.arpa (DWIGHT) (11/19/86)

     I have a machine that provides independently programmed I/O
channels.  The programs executed by the I/O channels are called
I/O chain programs.  Chain programs specify both integer constants
and address constants in their fields.  The address constants
point to things like buffer definition structures and words containing
interface modes.
     If it is not too much trouble, I would like to be able to program
I/O drivers in the "C" language.  The question is how do I represent
the chain programs.  Should I use the asm() function?  Should I try
and declare an array of words whose words are initialized with constants
equal to the instruction binary equivalents?  I tried the second method
and ran into all kinds of typing problems.
     Anyone have any ideas or experience?  Should I give up and go to
assembly language?
     Thanks in advance,
     --Dwight Wilcox
       NOSC Code 424
       San Diego, CA  92015-5000
       wilcox@nosc-tecr.arpa
------

rhg@fortune.UUCP (Roy Gordon) (11/21/86)

In article <914@brl-adm.ARPA> you write:
>     If it is not too much trouble, I would like to be able to program
>I/O drivers in the "C" language.  The question is how do I represent
>the chain programs.  Should I use the asm() function?  Should I try
>and declare an array of words whose words are initialized with constants
>equal to the instruction binary equivalents?  I tried the second method
>and ran into all kinds of typing problems.
>     Anyone have any ideas or experience?  Should I give up and go to
>assembly language?

Efficiency is the only reason to use assembler in any driver as long as
the device's registers are in the memory map.

The general coding strategy is to define a structure the members of which
are the registers of the i/o chip assigned a proper type, i.e. a char for
a one byte register, a short for a two byte register, etc.  Any "holes" in
the chip's memory must be accounted for in the structure so that the
compiler will generate the proper offsets for structure members.
Then you cast the address of the chip in your memory map as a pointer to
this type of structure.

For example, suppose you had an i/o controller that had a one byte status
register at offset 0 on the chip and a word command register at offset 2 on the 
chip and nothing else.  Suppose also that the chip lived at address 0x8000
in your memory map.  Then you could do the following:

	struct iochip 
	{
		char status;
		char unused01;		/* fills in hole - needed by compiler */
		short cmmd;
	};

	#define IOCHIP	(struct iochip *)0x8000;

Then, for example, to test the low bit of the status register you could say:

	if (IOCHIP->status & 1)

If the chip executed a command setting the proper bit(s) in the
command register (assuming the chip is enabled) then if writing a 2 caused
the device to read you could have:

   in header file for chip:

	#define IOREAD	0x2		/* chip read command value */

   in driver code:

	IOCHIP->cmmd = IOREAD;		/* issue read request */

Hope this helps you.