[comp.os.os9] Writing device drivers

pgh@stl.stc.co.uk (P.G.Hamer) (04/22/91)

I am a novice OS/9 user on a 68020 box, no 68K assembler experience. So far
I have been able to stay in C and everything is going well.

BUT we need to run a small C routine in response to externally generated
interrupt every 10mS. 

From the manual it looks like we have to write a (minimal) device handler
to do this. [Polling is definitely out, there is a fair bit of concurrency.]

Does anybody have code for a small device driver we could hack? Or other
advice to offer. 

Regards, Peter

ps3@ph3hp840.physik.uni-stuttgart.de (ps-Gruppe) (05/07/91)

In article <4310@stl.stc.co.uk> "P.G.Hamer" <pgh@stl.stc.co.uk> writes:
>...
>BUT we need to run a small C routine in response to externally generated
>interrupt every 10mS.
>
>From the manual it looks like we have to write a (minimal) device handler
>to do this. [Polling is definitely out, there is a fair bit of concurrency.]
>
>Does anybody have code for a small device driver we could hack? Or other
>advice to offer.

To handle interrupts you must use the os9-function F$IRQ. With this function
call you can put an assembler-routine into the interrupt-daisy-chain. The
parameter a3 (port address) is not used by OS9, it is just given to your
interrupt-routine. So you may use it for any purpose.
Refer to your technical OS9-Manual for further information about F$IRQ
or ask me.
No problem so far - but the F$IRQ-Call is a privileged system state servivce
request. This means, the caller programm must run in supervisor state.
But this is a bad solution, because :
  - system state routines are not timesliced. So you stop your Multitasking.
  - There's no memory protection
  - If your process stops irregular the whole system may crash
So you have to use an other solution:
You can either write a device driver or a traphandler, which is running in
supervisor state. If you prefer a device driver, you may communicate with
this device by read, write, setstt and/or getstt.
If you prefer a traphandler, I can give you a complete solution:

You just have to write a traphandler with the 'SupStat'-bit set in the
module header. This handler is allowed to do the F$IRQ-call. It has two
functions: One for installing an interrupt service routine and one for
removing it. All your program has to do, is loading the traphandler into
memory (F$TLink). Then you can use the two functions provided by the
traphandler by putting the parameters to the registers and
calling the handler with "trap #Trapnumber", where Trapnumber is the number
you used in the F$TLink-call.

The traphandler is included at the end of the mail. It is quite short and
easy to understand. I've left my comments in german, because I'm short in time.
I hope you understand the comments. There's a good explanation in the technical
Manual. But there's 1 important thing missing: In the supervisor-mode the
status-register is saved on the stack (which is not in normal-mode). So you
have to leave the traphandler with "RTE" instead of "RTS".


We are using this traphandler with Modula 2. If you are interested, I can
send the interface Module between Modula and the Traphandler.

>>>>>>>>> traphandler for installing interupt service routines <<<<<<<<<<<

            nam IRQ Handler
            ttl Traphandler fuer IRQ

*****************************************************************************
* Dieser Traphandler dient zum sauberen Einhaengen von Interrupts.          *
*                                                                           *
*                                                                           *
* Funktion 1 :                                                              *
* ============                                                              *
*                                                                           *
* Zweck   : Haengt eine Interruptroutine ins System ein                     *
* Aufruf  : Trap #Nummer,1                                                  *
* Eingabe : A0.L : Zeiger auf Interruptroutine                              *
*           A3.L : Portadresse (Platz fuer Variablen)                       *
*           D0.B : Vektornummer des Interrupts                              *
*           D1.B : Prioritaet des Interrupts; 0 = alleiniger Besitz         *
* Ausgabe : D1.W : 0, wenn kein Fehler auftrat; sonst Fehlernummer          *
*                                                                           *
*                                                                           *
* Funktion 2 :                                                              *
* ============                                                              *
*                                                                           *
* Zweck   : Entfernt die Interruptroutine wieder aus dem System             *
* Aufruf  : Trap #Nummer,2                                                  *
* Eingabe : D0.B : Vektornummer des Interrupts                              *
* Ausgabe : D1.W : 0, wenn kein Fehler auftrat; sonst Fehlernummer          *
*                                                                           *
*                                                                           *
* History:                                                                  *
* 05.09.89  to.3    erste offizielle Version                                *
* 30.05.90  to.3    Fehler, dass a2 zerstoert wurde, behoben.               *
*****************************************************************************


            use <oskdefs.d>

Type        set (TrapLib<<8)+Objct      Traphandler, Maschinensprache
Revs        set (SupStat<<8)+1          Supervisormodus, Revision
Edition     set 0
Stack       set 8                       zusaetzliche Stackgroesse

            psect IRQHandler,Type,Revs,Edition,Stack,TrapEnt

            dc.l TrapInit
            dc.l TrapTerm

            align
TrapInit    movem.l (a7)+,a6-a7         keine Initialisierung noetig
            rte

TrapEnt     movem.l a0/a2,-(a7)         Rette verwendete Register
            move.w  $0c(a7),d3          Offset = 4 + Anzahl der gesavten Reg.
            subq.b  #$01,d3
            beq.s   Funktion1
            subq.b  #$01,d3
            beq.s   Funktion2

* Falsche Funktionsnummer
            moveq   #$1,d1              Fehlernummer
            bra.s   Ende

* Funktion 1 wurde aufgerufen
Funktion1   move.l  #$00,a2             global static pointer; nicht benutzt
            bra.s   weiter

* Funktion 2 wurde aufgerufen
Funktion2   move.l  #$00,a0             delete from IRQ-Table
            move.l  #$00,a2

weiter      os9     F$IRQ               fuehre Funktion aus
            bcs.s   Ende                Es trat Fehler auf
            moveq   #$00,d1             kein Fehler

Ende        movem.l (a7)+,a0/a2/a6-a7
            rte

TrapTerm    move.w  #1<<8+199,d1        nie aufgerufen, fuer zukuenftige
            os9     F$Exit              Versionen Error 001:199

            ends

>>>>>>>>>>>>>>>>> end of listing <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<