home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 420.lha / Example_device / Ex_UnitMgr.asm < prev    next >
Assembly Source File  |  1990-09-29  |  16KB  |  323 lines

  1. ;*********************************************************************
  2. ;*                                                                   *
  3. ;* All changes I made are hereby in the Public Domain.  Commodore    *
  4. ;* retains its copyright, if any, of the original code in the Rom    *
  5. ;* Kernel manuals since this is a derivative work.  -Jeff Rush       *
  6. ;*                                                                   *
  7. ;*********************************************************************
  8. ;*                           History                                 *
  9. ;*                                                                   *
  10. ;* 20Sep89 jrr Original crib from Amiga Rom Kernel Manual.           *
  11. ;* 23Jul90 jrr Extensive descriptive prose added.                    *
  12. ;*                                                                   *
  13. ;*********************************************************************
  14.         TITLE   Example Device Driver for Tutorial Use
  15.         SMALLOBJ    ; Use PC-Relative Addressing
  16.         OPTIMON     ; Enable C.A.P.E. 68K Optimizations
  17.  
  18.         SECTION TheOnlySection
  19.  
  20.         ;************
  21.         ;* Includes *
  22.         ;************
  23.         NOLIST
  24.         INCLUDE "exec/types.i"
  25.         INCLUDE "exec/devices.i"
  26.         INCLUDE "exec/initializers.i"
  27.         INCLUDE "exec/memory.i"
  28.         INCLUDE "exec/resident.i"
  29.         INCLUDE "exec/io.i"
  30.         INCLUDE "exec/ables.i"
  31.         INCLUDE "exec/errors.i"
  32.         INCLUDE "exec/tasks.i"
  33.         INCLUDE "exec/semaphores.i"
  34.         INCLUDE "hardware/intbits.i"
  35.  
  36.         INCLUDE "asmsupp.i"
  37.  
  38.         INCLUDE "Example.i"     ; Device-Specific Definitions
  39.         LIST
  40.  
  41.         ;*************
  42.         ;* Constants *
  43.         ;*************
  44.  
  45.         ;******************
  46.         ;* Public Symbols *
  47.         ;******************
  48.         XDEF    InitUnit        ; Initialize a Unit Descriptor and Fire Up a Task
  49.         XDEF    FreeUnit        ; Deallocate the Memory for the Unit Descriptor
  50.         XDEF    ExpungeUnit     ; Terminate a Unit Task and Deallocate the Unit Descriptor
  51.  
  52.         ;********************
  53.         ;* External Symbols *
  54.         ;********************
  55.         ; This Name is for Debugging Use, to Annotate Serial-Debug Output
  56.         IFNE    INFO_LEVEL      ; If Any Debugging Enabled at All
  57.         XREF    subSysName
  58.         ENDC
  59.  
  60.         ; Defined in Ex_Support.Asm
  61.         XREF    PerformIO       ; Beginning of I/O Dispatch Point
  62.  
  63.         ; Defined in Ex_Main.Asm
  64.         XREF    MyName          ; Name of This Device (for Tagging Ports and Tasks)
  65.  
  66. ;*********************************************************************
  67. ;*                     InitUnit Helper Routine                       *
  68. ;*                                                                   *
  69. ;* InitUnit() is used to allocate a unit descriptor and optionally   *
  70. ;* spawn a task to manage that unit.                                 *
  71. ;*                                                                   *
  72. ;* Inputs:                                                           *
  73. ;*   A6 - Ptr to our Device node.                                    *
  74. ;*   A3 - Scratch Register.                                          *
  75. ;*   D2 - Unit Number Desired.                                       *
  76. ;*                                                                   *
  77. ;* Outputs:                                                          *
  78. ;*   D0        - ?????                                               *
  79. ;*                                                                   *
  80. ;* All Original Registers Must Be Preserved Across Function Call!!!! *
  81. ;*                                                                   *
  82. ;*********************************************************************
  83. InitUnit:
  84.         PUTMSG  30,<'%s/InitUnit: called'>
  85.         MOVEM.L D2-D4/A2,-(SP)              ; Preserve Original Registgers
  86.         ;
  87.         ; Allocate Some Memory for a Unit Descriptor Structure
  88.         MOVE.L  #MyDevUnit_Sizeof,D0        ; Size of Structure --> D0
  89.         MOVE.L  #MEMF_PUBLIC!MEMF_CLEAR,D1  ; Type of Memory    --> D1
  90.         LINKSYS AllocMem,md_SysLib(A6)      ; Allocate Memory
  91.         TST.L   D0                          ; Did It Work?
  92.         BEQ     InitUnit_End                ; Nope, Exit Function Early
  93.         MOVE.L  D0,A3                       ; Save Ptr to Allocation in A3
  94.         ;
  95.         ; Initialize the Unit Descriptor
  96.         MOVEQ.L #0,D0               ; Signal InitStruct() to Not Re-Zero Structure
  97.         MOVE.L  A3,A2               ; Ptr to Structure to Initialize    --> A2
  98.         LEA.L   mdu_Init(PC),A1     ; Ptr to Initialization Definitions --> A1
  99.         LINKSYS InitStruct,md_SysLib(A6)    ; Initialize Unit Descriptor
  100.  
  101.         MOVE.B  D2,mdu_UnitNum(A3)      ; Initialize the Unit Number
  102.         MOVE.L  A6,mdu_Device(A3)       ; Initialize the Ptr to the Device Node
  103.  
  104.         ;
  105.         ; Start up the unit task.  We do a trick here; we set his message
  106.         ; port to PA_IGNORE until the new task has a chance to set it up.
  107.         ; We cannot go to sleep here: it would be very nasty if someone
  108.         ; else tried to open the unit.  Exec's OpenDevice() has done a
  109.         ; Forbid() for us, we depend on this to become single threaded.
  110.  
  111.         ;
  112.         ; Initialize the Stack Boundaries
  113.         LEA     mdu_Stack(A3),A0            ; Define Low End of Task Stack
  114.         MOVE.L  A0,mdu_Tcb+TC_SPLOWER(A3)
  115.         LEA     TASKSTKSIZE(A0),A0          ; Define High End of Task Stack
  116.         MOVE.L  A0,mdu_Tcb+TC_SPUPPER(A3)
  117.  
  118.         MOVE.L  A3,-(A0)                    ; Pass Ptr to Unit Descriptor on New Task's Stack
  119.         MOVE.L  A0,mdu_Tcb+TC_SPREG(A3)     ; Define Position of New Task's Stack Pointer
  120.         LEA     mdu_Tcb(A3),A0              ; Ptr to Unit's Task Structure --> A0
  121.         MOVE.L  A0,MP_SIGTASK(A3)           ; Set Message Port's Monitor Task to Unit's Task
  122.  
  123.         IFGE INFO_LEVEL-30
  124.         MOVE.L  A0,-(SP)
  125.         MOVE.L  A3,-(SP)
  126.         PUTMSG  30,<'%s/InitUnit, unit= %lx, task=%lx'>
  127.         ADDQ.L  #8,SP
  128.         ENDC
  129.  
  130.         LEA     MP_MSGLIST(A3),A0
  131.         NEWLIST A0                      ; Initialize the Message Port's List
  132.         ;
  133.         ; Start the Unit Task
  134.         LEA     mdu_Tcb(A3),A1          ; Pickup a Ptr to the Task Control Block
  135.         LEA     UnitTask_Begin(PC),A2   ; Pickup Ptr to Task's Code Entry Point
  136.         MOVE.L  A3,-(SP)                ; Preserve the Ptr to the Unit Descriptor
  137.         ;
  138.         ; If Unit Task ever Returns, Generate an Artificial Address Error
  139.         LEA     -1,A3                   ; It Should Never Return, We RemTask() It when Done
  140.         CLEAR   D0
  141.         PUTMSG  30,<'%s/About to add task'>
  142.         LINKSYS AddTask,md_SysLib(A6)
  143.         MOVE.L  (SP)+,A3                ; Restore the Ptr to the Unit Descriptor
  144.         ;
  145.         ; Mark New Unit as Ready to Operate
  146.         MOVE.L  D2,D0                   ; Pick up Unit Number in D0
  147.         LSL.L   #2,D0                   ; Multiply by 4 Bytes Per Entry
  148.         MOVE.L  A3,md_Units(A6,D0.L)    ; Set Ptr to Unit Descriptor into Unit Table
  149.         PUTMSG  30,<'%s/InitUnit: ok'>
  150.  
  151. InitUnit_End:
  152.         MOVEM.L (SP)+,D2-D4/A2          ; Restore Original Registers
  153.         RTS
  154.  
  155.         ;****************************************************
  156.         ;* Initialization Definitions for a Unit Descriptor *
  157.         ;****************************************************
  158. mdu_Init:
  159.         INITBYTE    MP_FLAGS,PA_IGNORE      ;\
  160.         INITBYTE    LN_TYPE,NT_MSGPORT      ; > Message Port
  161.         INITLONG    LN_NAME,MyName          ;/
  162.         INITLONG    mdu_Tcb+LN_NAME,MyName  ;\
  163.         INITBYTE    mdu_Tcb+LN_TYPE,NT_TASK ; > Task Control Block
  164.         INITBYTE    mdu_Tcb+LN_PRI,5        ;/
  165.         DC.L        0
  166.  
  167. ;*********************************************************************
  168. ;*                     FreeUnit Helper Routine                       *
  169. ;*                                                                   *
  170. ;* FreeUnit() is used to deallocate the memory occupied by a unit    *
  171. ;* descriptor.  It assumes the task has already been stopped.        *
  172. ;*                                                                   *
  173. ;* Inputs:                                                           *
  174. ;*   A6 - Ptr to our Device node.                                    *
  175. ;*   A3 - Ptr to Unit Descriptor.                                    *
  176. ;*                                                                   *
  177. ;* Outputs:                                                          *
  178. ;*   None                                                            *
  179. ;*                                                                   *
  180. ;*********************************************************************
  181. FreeUnit:
  182.         MOVE.L  A3,A1
  183.         MOVE.L  #MyDevUnit_Sizeof,D0
  184.         LINKSYS FreeMem,md_SysLib(A6)   ; Release the Memory
  185.         RTS
  186.  
  187. ;*********************************************************************
  188. ;*                   ExpungeUnit Helper Routine                      *
  189. ;*                                                                   *
  190. ;* ExpungeUnit() is used to stop the unit task, free its descriptor  *
  191. ;* and unlink it from the unit table.                                *
  192. ;*                                                                   *
  193. ;* Inputs:                                                           *
  194. ;*   A6 - Ptr to our Device node.                                    *
  195. ;*   A3 - Ptr to Unit Descriptor.                                    *
  196. ;*                                                                   *
  197. ;* Outputs:                                                          *
  198. ;*   None                                                            *
  199. ;*                                                                   *
  200. ;*********************************************************************
  201. ExpungeUnit:
  202.         PUTMSG  10,<'%s/ExpungeUnit: called'>
  203.         MOVE.L  D2,-(SP)                ; Preserve Original D2 Across Function
  204.  
  205.         LEA     mdu_Tcb(A3),A1
  206.         LINKSYS RemTask,md_SysLib(A6)   ; Remove the Unit's Task
  207.  
  208.         CLEAR   D2
  209.         MOVE.B  mdu_UnitNum(A3),D2      ; Save the Unit# in D2 for a Moment
  210.  
  211.         BSR     FreeUnit                ; Free the Unit Descriptor Structure Itself
  212.  
  213.         ;------ clear out the unit vector in the device
  214.         LSL.L   #2,D2                   ; Compute an Index into the Unit Table
  215.         CLR.L   md_Units(A6,D2.L)       ; Clear the Ptr to the Unit Descriptor
  216.  
  217.         MOVE.L  (SP)+,D2                ; Restore Original D2
  218.         RTS
  219.  
  220. ;*********************************************************************
  221. ;*                 Unit Task Code (Reentrant)                        *
  222. ;*                                                                   *
  223. ;* This block of code serves as the executable port of a spun-off    *
  224. ;* that handles each unit.  There may be multiple unit tasks using   *
  225. ;* the same code in a reentrant fashion, therefore the device author *
  226. ;* must take steps to coordinate shared accesses.                    *
  227. ;*                                                                   *
  228. ;* An alternative architecture is to create only a single task and   *
  229. ;* let all unit request flow into it.  The choice depends upon the   *
  230. ;* specific hardware being managed and your design requirements.     *
  231. ;*                                                                   *
  232. ;* Register Usage:                                                   *
  233. ;*   A3 - Ptr to the Unit Descriptor.                                *
  234. ;*   A6 - Ptr to the Exec Library.                                   *
  235. ;*   A5 - Ptr to our Device node.                                    *
  236. ;*   A4 - Ptr to Task Control Block (-NOT- a DOS Process)            *
  237. ;*   D7 - Event Wait Mask                                            *
  238. ;*                                                                   *
  239. ;* Notes:                                                            *
  240. ;*   This task never terminates, it is simply removed suddenly.      *
  241. ;*                                                                   *
  242. ;*********************************************************************
  243.  
  244.         ; Some DOS Magic, useful for Processes (not us).  A process is
  245.         ; started at the first  executable address  after a segment list.
  246.         ; We hand craft a segment list here.  See the the DOS technical
  247.         ; reference if you really need to know more about this.
  248.         ; The next instruction after the segment list is the first
  249.         ; executable address.
  250.  
  251.         CNOP    0,4     ; Align the Following on a Long Word Boundary
  252.         DC.L    16      ; Length of Segment (Dummy Value, Any will Do)
  253. UnitTask_Seglist:
  254.         DC.L    0       ; NULL Pointer to the Next Segment
  255.  
  256. UnitTask_Begin:
  257.         PUTMSG  35,<'%s/Task_Begin'>
  258.         MOVE.L  ABSEXECBASE,A6      ; Pickup Ptr to Exec Library
  259.         ;
  260.         ; Pickup a Ptr to the Unit Descriptor as Passed to Us on
  261.         ;   our Initial Stack
  262.         MOVE.L  4(SP),A3            ; Pickup Ptr to Unit Descriptor
  263.         MOVE.L  mdu_Device(A3),A5   ; Pickup Ptr to our Device node
  264.         ;
  265.         ; Allocate a Signal Bit for Use with Our Message Port
  266.         MOVEQ   #-1,D0              ; Any Signal Will Do (-1 = Any)
  267.         CALLSYS AllocSignal         ; Allocate a Signal Bit
  268.         MOVE.B  D0,MP_SIGBIT(A3)    ; Note Signal Bit Allocated for Future
  269.         MOVE.B  #PA_SIGNAL,MP_FLAGS(A3) ; Make our Message Port 'Live'
  270.  
  271.         MOVEQ   #0,D7               ; Change the Signal Bit# into a Mask
  272.         BSET    D0,D7               ;   and Save in D7 for Future Reference
  273.  
  274.                                     ; Because our Message Port was Marked PA_IGNORE
  275.                                     ;   for a while (in InitUnit), We jump to the
  276.                                     ;   GetMsg() code upon entry.  This is because
  277.                                     ;   our first message will probably be posted
  278.                                     ;   -before- our task gets a chance to run.
  279.         BRA.S   Task_StartHere      ; Jump into Incoming-Message Waiting Loop
  280.  
  281.         ;***********************
  282.         ;* Main Loop of Device *
  283.         ;***********************
  284. Task_Unlock:
  285.         AND.B   #$FF&(~(UNITF_ACTIVE!UNITF_INTASK)),UNIT_FLAGS(A3)
  286.  
  287. Task_MainLoop:
  288.         PUTMSG  75,<'%s/++Sleep'>
  289.         MOVE.L  D7,D0
  290.         CALLSYS Wait            ; Wait for an Incoming Message
  291.  
  292.         IFGE    INFO_LEVEL-5
  293.         BCHG.B  #1,$BFE001      ; Blink the Power LED for Each Message Received
  294.         ENDC
  295.  
  296. Task_StartHere:
  297.         PUTMSG   75,<'%s/++Wakeup'>
  298.  
  299.         BTST    #MDUB_STOPPED,UNIT_FLAGS(A3) ; Is this Unit Suspended (Stopped)?
  300.         BNE.S   Task_MainLoop               ; Yes, Ignore Messages
  301.  
  302.         BSET    #UNITB_ACTIVE,UNIT_FLAGS(A3) ; Mark the Device as Active
  303.         BNE     Task_MainLoop               ; If Device was Already In-Use, Ignore Message
  304. Task_NextMessage:
  305.         MOVE.L  A3,A0                       ; Pickup a Ptr to the Incoming Message Port
  306.         CALLSYS GetMsg                      ; Pull a Message from the Message Port
  307.         PUTMSG  1,<'%s/GotMsg'>
  308.         TST.L   D0                          ; Did We Get One?
  309.         BEQ     Task_Unlock                 ; No, Go Back to Waiting for One
  310.  
  311.         MOVE.L  D0,A1                       ; Ptr to I/O Request Block (Msg) --> A1
  312.         EXG     A5,A6                       ; Ptr to Device node             --> A6
  313.                                             ; Ptr to Unit Descriptor         --> A3
  314.         BSR     PerformIO                   ; Dispatch to I/O Handler Function
  315.         EXG     A5,A6                       ; Get Ptr to Exec Library Back in A6
  316.         BRA.S   Task_NextMessage            ; Go Process Next Message Already at Port
  317.  
  318. ;*********************************************************************
  319. ;*                                                                   *
  320. ;*********************************************************************
  321.         END
  322.  
  323.