[comp.sys.apollo] Writing device drivers

e_holen%vax.runit.unit.uninett@TOR.NTA.NO (Endre Holen) (04/06/88)

I want to write a device driver to a graphics board that sits in the AT-compatible bus in a DN3000. The driver should only do the following :
Read and write to the Status port 
Read and write to the data port 

These two ports are at base adress and base+2 .

The documentation for using GPIO calls are rather poor, (or maybe I am stupid), but I have a bit problems with finding out how to get access to the CSR page.

Has anybody done something similar ?

Endre Holen
Super Computing Centre
University of Trondheim

trb@stag.UUCP ( Todd Burkey ) (04/11/88)

In article <66*e_holen@vax.runit.unit.uninett> e_holen%vax.runit.unit.uninett@TOR.NTA.NO (Endre Holen) writes:
>
>The documentation for using GPIO calls are rather poor, (or maybe I am stupid), but I have a bit problems with finding out how to get access to the CSR page.
>
I have had similar problems dealing with the Aegis GPIO docs. For the
life of me, I can't figure out how to get the PBU Control call to work
correctly (I want to swap words). All I can figure out is that it may
be a NOP command when combined with the PBU map controller command
(the 20 bit call option...I am writing this from home, so can't
remeber the exact call syntax's). The docs reference manual made no
mention of what sequencing was necessary for the calls and the example
sets didn't include the swap words/bytes options. Guess I will have to
break all my datastructures down to the

a.xref_point.value.up:=b.point.value.up
a.xref_point.value.lo:=b.point.value.lo

level of coding...what a waste.

-Todd Burkey
 trb@stag.UUCP

ced@apollo.uucp (Carl Davidson) (04/19/88)

From article <372@stag.UUCP>, by trb@stag.UUCP ( Todd Burkey ):
> I have had similar problems dealing with the Aegis GPIO docs. For the
> life of me, I can't figure out how to get the PBU Control call to work
> correctly (I want to swap words). All I can figure out is that it may
> be a NOP command when combined with the PBU map controller command
> (the 20 bit call option...I am writing this from home, so can't
> remeber the exact call syntax's). The docs reference manual made no
> mention of what sequencing was necessary for the calls and the example
> sets didn't include the swap words/bytes options. Guess I will have to
> break all my datastructures down to the
> 
> a.xref_point.value.up:=b.point.value.up
> a.xref_point.value.lo:=b.point.value.lo
> 
> level of coding...what a waste.
> 
> -Todd Burkey
>  trb@stag.UUCP

I ran into a similar problem about a year ago when coding a driver 
and  have a solution for you.

Assuming that you are running something other than SR9.7, and that you are
coding your driver in C, you can do the following:

    In the source file in which you call pbu_$control make the following
    definitions:

#define NULL_SET    0
#define MAP_R       1
#define MAP_RW      2
#define SWAP_OFF    4
#define SWAP_WORDS  8
#define SWAP_BYTES 16

    You need to do this because until recently /sys/ins/pbu.ins.c had incorrect
    definitions for the Pascal set PBU_$OPTS_T (this has been fixed on SR 9.7,
    at least, maybe earlier) and this resulted in the call failing silently.
    Well, actually, it resulted in the call doing what you told it to do, but
    not what you wanted it to.

    You can then call pbu_$control as follows:

    pbu_$control(*unit, SWAP_WORDS + MAP_RW, old_opts, 0, status -> all);

    This will give you word swapping AND byte swapping (i.e. everything you
    write across the bus will be treated the same way).  You need to read
    Chapter 1, section 1.4 of Rev 10 of the GPIO manual to understand why this
    is so. The explanation is too long to repeat here.

If you are writing in Pascal, or are already on SR9.7, and you are still having
trouble, it is *probably* because you are not driving a 20-bit Multibus (that
doesn't appear to be the case here, but this call is a no-op for any other bus -
AT, VME, or 16-bit Multibus).

It is important for C programmers to remember that any parameter passed into
the initialization routine (this is where you should be calling pbu_$control) is
passed by *reference* and is therefore a pointer and needs to be de-referenced
before being passed to any system calls because of the STD_$CALL convention. 
This is why both unit and status.all are de-referenced in the example above.

You can test the results of your call to pbu_$control by making another call to
pbu_$control with a null set (NULL_SET) as the second parameter and printing out
the value returned in "old_opts".  I do this with:

    pbu_$control(*unit, NULL_SET, old_opts, 0, status -> all);
    printf("\nPBU_$CONTROL is %d \n", old_opts);

It ain't pretty, but it works.

Also, if you would like to see your initialization routine run in the debugger,
you can declare a do-nothing initialization routine in the DDF and call the real 
initialization routine from your test program.

This is also the easiest way to debug interrupt service routines. In the ISR case,
your test program needs to wait on the PBU event count and then call the ISR when 
it advances.  Using this method I have successfully debugged ISRs installed in the call 
library and then moved them to the interrupt library when they are "bug-free".  In one
case, we located latent controller firmware bugs in a matter of minutes that would have
taken hours or days the conventional way.

If none of this helps, drop me some mail and I'll be glad to help further.

This technique also works well for interrupt service routines.  In 
-- 
--Carl Davidson                                 "Science is what you do
  Apollo Computer Inc.                           after  you  guess well."
  Chelmsford, MA 01824                 
  {decvax,mit-eddie,umix}!apollo!ced