home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 420.lha / Example_device / Ex_EntryPts.asm < prev    next >
Assembly Source File  |  1990-09-29  |  32KB  |  567 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    LoadInitRoutine ; Initialization when Device First Loads into Memory
  49.         XDEF    DevOpen         ; Unit Allocation for Each Time Device is Opened
  50.         XDEF    DevClose        ; Unit Deallocation for Each Time Device is Opened
  51.         XDEF    DevExpunge      ; Remove Device from Memory if No One is Using It
  52.         XDEF    DevNull         ; Reserved for Future Expansion
  53.         XDEF    DevBeginIO      ; Initiate an I/O Request either Now or Put in Queue
  54.         XDEF    DevAbortIO      ; Abort an I/O Request either Active or in Queue
  55.  
  56.         ;********************
  57.         ;* External Symbols *
  58.         ;********************
  59.         ; This Name is for Debugging Use, to Annotate Serial-Debug Output
  60.         IFNE    INFO_LEVEL      ; If Any Debugging Enabled at All
  61.         XREF    subSysName
  62.         ENDC
  63.  
  64.         ; Defined in Ex_Support.Asm
  65.         XREF    LockGlobal      ; Obtain Exclusive Access to Device Global Data
  66.         XREF    UnlockGlobal    ; Release Exclusive Access to Device Global Data
  67.         XREF    PerformIO       ; Common Fork or Dispatch to Handle Device Commands
  68.  
  69.         ; Defined in Ex_UnitMgr.Asm
  70.         XREF    InitUnit    ; Initialize a Unit Descriptor and Fire Up a Task
  71.         XREF    ExpungeUnit ; Terminate a Unit Task and Deallocate the Unit Descriptor
  72.  
  73. ;*********************************************************************
  74. ;*       Device-Just-Loaded-Into-Ram Initialization Routine          *
  75. ;*                                                                   *
  76. ;* This routine gets called immediately after the device has been    *
  77. ;* loaded into Ram, in order to allow it to set up its environment.  *
  78. ;*                                                                   *
  79. ;* Inputs:                                                           *
  80. ;*   D0 - Ptr to base of the newly allocated device node structure.  *
  81. ;*   A0 - BPtr to the segment list for the device's code.            *
  82. ;*   A6 - Ptr to the Exec Library.                                   *
  83. ;*                                                                   *
  84. ;* Outputs:                                                          *
  85. ;*   D0 - Ptr to base of where the device has been loaded or NULL    *
  86. ;*        if initialization failed and the device is to be unloaded. *
  87. ;*                                                                   *
  88. ;* All Original Registers Must Be Preserved Across Function Call!!!! *
  89. ;*                                                                   *
  90. ;* Notes:                                                            *
  91. ;*   The call to this routine is single-threaded by Exec, providing  *
  92. ;*   it does not perform a Wait(), either directly or indirectly.    *
  93. ;*   This means that it cannot perform any DOS calls, even to open   *
  94. ;*   a disk-based library.  Libraries which are -known- to be in     *
  95. ;*   ram can be opened however, such as Exec, Expansion, etc.        *
  96. ;*                                                                   *
  97. ;*   This function is called once per time the device is loaded into *
  98. ;*   ram, unlike DevOpen() which is called each time the device is   *
  99. ;*   opened by a caller.  An Exec device can be loaded once and      *
  100. ;*   opened multiple times, either for different units or in         *
  101. ;*   succession without an intervening expunge.                      *
  102. ;*                                                                   *
  103. ;*   At the time this function is called, the device node is -NOT-   *
  104. ;*   yet linked into the system lists.                               *
  105. ;*                                                                   *
  106. ;*   If you don't use the "RTF_AUTOINIT" feature, there is an        *
  107. ;*   additional caveat.  If you allocate memory in your Open         *
  108. ;*   function, remember that allocating memory can cause an Expunge, *
  109. ;*   including an expunge of your device.  This must not be fatal.   *
  110. ;*   The easy solution is to avoid adding your device to the public  *
  111. ;*   list until after it is ready for action, to prevent your being  *
  112. ;*   on the list of expunge candidates.                              *
  113. ;*                                                                   *
  114. ;*********************************************************************
  115. LoadInitRoutine:
  116.         PUTMSG  5,<'%s/Init: called'>
  117.  
  118.         MOVEM.L D1-D7/A0-A5,-(SP)   ; Preserve ALL modified registers
  119.  
  120. ;Debug  CALLSYS Debug               ; Enter ROMWack Debugger to Determine My Address
  121.  
  122.         MOVE.L  D0,A5               ; Set A5 to Base of Our Device
  123.         MOVE.L  A6,md_SysLib(A5)    ; Keep a Ptr to the Exec Library
  124.         MOVE.L  A0,md_SegList(A5)   ; Keep a Ptr to our Seglist
  125.         ;
  126.         ; Initialize the Device Global Data Arbitration Semaphore
  127.         LEA.L   md_SemLock(A5),A0   ; Pickup Ptr to the Arbitration Semaphore
  128.         CALLSYS InitSemaphore       ; Obtain Control of the Device Node
  129.  
  130.         MOVE.L  A5,D0               ; Signal Success via Device Ptr in D0
  131.         MOVEM.L (SP)+,D1-D7/A0-A5   ; Restore ALL modified registers
  132.         RTS
  133.  
  134. ;*********************************************************************
  135. ;*                      Open Device Routine                          *
  136. ;*                                                                   *
  137. ;* When the user calls OpenDevice(), this eventually gets translated *
  138. ;* into a call to this routine.  By the time this routine gets       *
  139. ;* control, the device node has already been linked into the system  *
  140. ;* list of known devices.                                            *
  141. ;*                                                                   *
  142. ;* Inputs:                                                           *
  143. ;*   A6 - Ptr to our Device node.                                    *
  144. ;*   A1 - Ptr to the caller's I/O request block.                     *
  145. ;*   D0 - Unit number desired.                                       *
  146. ;*   D1 - Device-Specific Flags indicating desired.                  *
  147. ;*                                                                   *
  148. ;* Outputs:                                                          *
  149. ;*   D0        - Error code of operation (0 if open succeeded).      *
  150. ;*   IO_ERROR  - Error code of operation (another copy as a byte).   *
  151. ;*   IO_UNIT   - Some unit identification information (if success).  *
  152. ;*   IO_DEVICE - Set up by Exec on behalf of device.                 *
  153. ;*   LN_TYPE   - Signal end of operation (unclear on requirement)    *
  154. ;*                                                                   *
  155. ;* All Original Registers Must Be Preserved Across Function Call!!!! *
  156. ;*                                                                   *
  157. ;* Notes:                                                            *
  158. ;*   The call to this routine is single-threaded by Exec, providing  *
  159. ;*   it does not perform a Wait(), either directly or indirectly.    *
  160. ;*   Because of this, do not take very much time.                    *
  161. ;*                                                                   *
  162. ;*********************************************************************
  163. DevOpen:
  164.         PUTMSG  20,<'%s/Open: called'>
  165.         MOVEM.L D2/A2/A3/A4,-(SP)   ; Preserve Original Registers Across Call
  166.         MOVE.L  A1,A2               ; Save Ptr to the I/O Block in A2
  167.  
  168.         ADDQ.W  #1,LIB_OPENCNT(A6)  ; Add Fake Opener to Prevent Expunge
  169.         BSR     LockGlobal          ; Obtain Exclusive Access to Device Node
  170.  
  171.         ;
  172.         ; Insure the Specified Unit Number is In-Range
  173.         CMP.L   #MD_NUMUNITS,D0
  174.         BCC.S   Open_Range_Error    ; Unit Number is Out of Range!!
  175.         ;
  176.         ; See if the Specified Unit is Already Initialized
  177.         MOVE.L  D0,D2               ; Save Unit Number in D2
  178.         LSL.L   #2,D0               ; Multiply Unit Number by 4
  179.         LEA.L   md_Units(A6,D0.L),A4   ; Index into Unit Table
  180.         MOVE.L  (A4),D0             ; Pickup Ptr to Unit Descriptor
  181.         BNE.S   Open_UnitOK         ; Descriptor is Non-Null, Unit is Ready!
  182.         ;
  183.         ; Unit is Uninitialized, Attempt to Conjure One Up
  184.         BSR     InitUnit            ; Scratch:A3, Unit Number:D2, Ptr to Device:A6
  185.         MOVE.L  (A4),D0             ; Did It Initialize Ok?
  186.         BEQ.S   Open_Error          ; Nope, Error!
  187.         ;
  188.         ; Unit is Located and Ready for Us
  189. Open_UnitOK:
  190.         MOVE.L  D0,A3               ; Put Ptr to Unit Descriptor into A3
  191.         MOVE.L  D0,IO_UNIT(A2)
  192.         ;
  193.         ; Adjust Reference Counts to Track Number of Openers
  194.         ADDQ.W  #1,LIB_OPENCNT(A6)      ; One More User of the Device
  195.         ADDQ.W  #1,UNIT_OPENCNT(A3)     ; One More User of the Specific Unit Too
  196.  
  197.         BCLR    #LIBB_DELEXP,md_Flags(A6)   ; Prevent Delayed Expunges
  198.  
  199.         MOVEQ.L #0,D0                   ; Return Error Code in D0 and in IO_ERROR
  200.         CLR.B   IO_ERROR(A2)            ; Signal "No Error Occurred During Open"
  201.  
  202.         MOVE.B  #NT_REPLYMSG,LN_TYPE(A2) ; IMPORTANT: Mark IORequest as "Complete"
  203. Open_End:
  204.         SUBQ.W  #1,LIB_OPENCNT(A6)  ; Remove Fake Opened Now¨the Open is Done
  205.         BSR     UnlockGlobal        ; Release Exclusive Access to Device Node
  206.  
  207.         MOVEM.L (SP)+,D2/A2/A3/A4   ; Restore Original Registers
  208.         RTS
  209.  
  210. Open_Range_Error:
  211. Open_Error:
  212.         MOVEQ   #IOERR_OPENFAIL,D0  ; Return Error Code in D0 and in IO_ERROR
  213.         MOVE.B  D0,IO_ERROR(A2)
  214.  
  215.         MOVE.L  D0,IO_DEVICE(A2)    ; IMPORTANT: Trash IO_DEVICE on Open Failure
  216.  
  217.         PUTMSG  2,<'%s/Open: failed'>
  218.         BRA.S   Open_End
  219.  
  220. ;*********************************************************************
  221. ;*                     Close Device Routine                          *
  222. ;*                                                                   *
  223. ;* When the user calls CloseDevice(), this eventually gets changed   *
  224. ;* into a call to this routine which terminates communication with   *
  225. ;* the device.  Upon closing, the device's input buffers are freed   *
  226. ;* and the memory occupied by the device (code and data) may or may  *
  227. ;* not be freed.                                                     *
  228. ;*                                                                   *
  229. ;* Inputs:                                                           *
  230. ;*   A6 - Ptr to our Device node.                                    *
  231. ;*   A1 - Ptr to the caller's I/O request block as initialized by    *
  232. ;*        OpenDevice().                                              *
  233. ;*                                                                   *
  234. ;* Outputs:                                                          *
  235. ;*   D0        - Device unload indicator:                            *
  236. ;*                 device seglist as given to Init (causes unload)   *
  237. ;*                 zero (causes device to stay around in memory)     *
  238. ;*   IO_ERROR  - Error code of operation (another copy as a byte).   *
  239. ;*                                                                   *
  240. ;* All Original Registers Must Be Preserved Across Function Call!!!! *
  241. ;*                                                                   *
  242. ;* Notes:                                                            *
  243. ;*   The call to this routine is single-threaded by Exec, providing  *
  244. ;*   it does not perform a Wait(), either directly or indirectly.    *
  245. ;*   Because of this, do not take very much time.                    *
  246. ;*                                                                   *
  247. ;*   All I/O requests -must- be complete before closing.  If any are *
  248. ;*   pending, the user's program must AbortIO() then WaitIO() for    *
  249. ;*   each one to complete it.                                        *
  250. ;*                                                                   *
  251. ;*********************************************************************
  252. DevClose:
  253.         MOVEM.L D1/A2-A3,-(SP)      ; Preserve Registers D1, A2 and A3 Across Call
  254.         BSR     LockGlobal          ; Obtain Exclusive Access to Device Node
  255.  
  256.         PUTMSG  20,<'%s/Close: called'>
  257.         ;
  258.         ; Obtain a Ptr to the Appropriate Unit Descriptor
  259.         MOVE.L  A1,A2               ; Move IOB Ptr to A2
  260.         MOVE.L  IO_UNIT(A2),A3      ; Pickup a Ptr to the Unit Descriptor in A3
  261.         ;
  262.         ; Mark the IOB Closed to Prevent Accidental Reuse
  263.         MOVEQ.L #-1,D0
  264.         MOVE.L  D0,IO_UNIT(A2)      ; Scribble Over Ptr to Unit Descriptor
  265.         MOVE.L  D0,IO_DEVICE(A2)    ; Scribble Over Ptr to Device Descriptor
  266.         ;
  267.         ; Decrement Unit Reference Count and Optionally Expunge Unit if No Users
  268.         SUBQ.W  #1,UNIT_OPENCNT(A3)
  269.         BNE.S   Close_Device        ; Reference Count -not- Zero, Do Not Release Unit
  270.         BSR     ExpungeUnit         ; A3:UnitPtr, A6:DevicePtr
  271.         NOP     ; Required to Handle a Null Jump to the Next Byte
  272.         ; Do Not Expunge Ramdisks or the Contents Will Vanish!
  273. Close_Device:
  274.         CLEAR   D0
  275.         ;
  276.         ; Decrement Device Reference Count and Optionally Expunge Device if Asked
  277.         SUBQ.W  #1,LIB_OPENCNT(A6)  ; Decrement Device Reference Count
  278.         BNE.S   Close_End           ; Reference Count -not- Zero, Do Not Release Device
  279.         ;
  280.         ; See If There is a Delayed Expunge Pending
  281.         BTST    #LIBB_DELEXP,md_Flags(A6)   ; Check for a Delayed Expunge Pending...
  282.         BEQ.S   Close_End           ; Nope, No Request for Us to Unload is Pending
  283.  
  284.         BSR     DevExpunge          ; A6:DevicePtr
  285. Close_End:
  286.         BSR     UnlockGlobal        ; Release Exclusive Access to Device Node
  287.         MOVEM.L (SP)+,D1/A2-A3      ; Restore Original Registers D1, A2 and A3
  288.         RTS                         ; Must Return Either Zero or Device Seglist in D0
  289.  
  290. ;*********************************************************************
  291. ;*                     Expunge Device Routine                        *
  292. ;*                                                                   *
  293. ;* This routine frees all system resources and dependencies used by  *
  294. ;* the device by any unit.  If the device is currently closed, the   *
  295. ;* expunge takes place immediately.  Otherwise, this routine sets a  *
  296. ;* Delayed Expunge bit and returns a device unload indicator of zero *
  297. ;* (do not unload device at this time).                              *
  298. ;*                                                                   *
  299. ;* Expunge() is called by the memory allocator when the system is    *
  300. ;* low on memory.                                                    *
  301. ;*                                                                   *
  302. ;* Inputs:                                                           *
  303. ;*   A6 - Ptr to our Device node.                                    *
  304. ;*   A1 - Ptr to the caller's I/O request block as initialized by    *
  305. ;*        OpenDevice().                                              *
  306. ;*                                                                   *
  307. ;* Outputs:                                                          *
  308. ;*   D0        - Device unload indicator:                            *
  309. ;*                 device seglist as given to Init (causes unload)   *
  310. ;*                 zero (causes device to stay around in memory)     *
  311. ;*   IO_ERROR  - Error code of operation (zero means success).       *
  312. ;*                                                                   *
  313. ;* All Original Registers Must Be Preserved Across Function Call!!!! *
  314. ;*                                                                   *
  315. ;* Notes:                                                            *
  316. ;*   The call to this routine is single-threaded by Exec, providing  *
  317. ;*   it does not perform a Wait(), either directly or indirectly.    *
  318. ;*   Because of this, do not take very much time.                    *
  319. ;*                                                                   *
  320. ;*   Because Expunge() is called from the memory allocator, it may   *
  321. ;*   -never- Wait() or otherwise take a long time to complete.       *
  322. ;*                                                                   *
  323. ;*********************************************************************
  324. DevExpunge:
  325.         PUTMSG  10,<'%s/Expunge: called'>
  326.         MOVEM.L D1/D2/A5/A6,-(SP)   ; Preserve ALL Modified Registers Across Call
  327.  
  328.         MOVE.L  A6,A5               ; Move Device Ptr into A5
  329.         MOVE.L  md_SysLib(A5),A6    ; Pickup the Stashed Ptr to the Exec Library
  330.  
  331.         TST.W   LIB_OPENCNT(A5)     ; See if Device Reference Count is Zero (No Users)
  332.         BEQ     1$                  ; No Users, Device Can Be Unloaded
  333.         ;
  334.         ; Device is Still Open by Someone, Request Expunge in the Future
  335.         BSET    #LIBB_DELEXP,md_Flags(A5)   ; Set the Delayed Expunge Flag
  336.         CLEAR   D0                  ; Set up to Return Zero to Prevent Device Unload
  337.         BRA.S   Expunge_End         ; Jump to Function Exit
  338. 1$:
  339.         ;
  340.         ; Device has No Users, It Can Be Unloaded
  341.         MOVE.L  md_SegList(A5),D2   ; Pickup the Device Seglist in D2
  342.  
  343.         MOVE.L  A5,A1               ; Get Ptr to Device Node into A1 for Remove()
  344.         CALLSYS Remove              ; Remove Device Node from Global Linked List of Devices
  345.  
  346.         ;
  347.         ; Device-Specific Closing Operations Here...
  348.         ; (Do Not Break Forbid!)
  349.         ;
  350.  
  351.         ;
  352.         ; Free the Memory Occupied by the Device Node
  353.         ; (Size Depends Upon Size of Jump Table and Device-Global Data)
  354.         ; (The Code and Data Part will be Freed as a Seglist)
  355.         ;------ free our memory (must calculate from LIB_POSSIZE & LIB_NEGSIZE)
  356.         MOVE.L  A5,A1               ; Get Ptr to Device Node into A1
  357.         CLEAR   D0                  ; Clear Calculation Accumulator
  358.         MOVE.W  LIB_NEGSIZE(A5),D0  ; Pickup Negative Extent of Device Node
  359.         SUBA.L  D0,A1               ; Adjust Ptr to Device Node Down To Base of Device Node
  360.         ADD.W   LIB_POSSIZE(A5),D0  ; Add in Positive Extent of Device Node (Functions + Data)
  361.         CALLSYS FreeMem             ; Free Memory Occuppied by Device Node
  362.  
  363.         MOVE.L  D2,D0               ; Set up to Return Our Device Seglist to Cause Unload
  364. Expunge_End:
  365.         MOVEM.L (SP)+,D1/D2/A5/A6   ; Restore Original Registers
  366.         RTS                         ; Must Return Either Zero or Device Seglist in D0
  367.  
  368. ;*********************************************************************
  369. ;*                       Null Device Routine                         *
  370. ;*                                                                   *
  371. ;* This routine handles a null entry point into the device provided  *
  372. ;* for future expansion.  It performs no function.                   *
  373. ;*                                                                   *
  374. ;* Inputs:                                                           *
  375. ;*   A6 - Ptr to our Device node.                                    *
  376. ;*                                                                   *
  377. ;* Outputs:                                                          *
  378. ;*   D0 - Must return zero (NULL) for future compatibility.          *
  379. ;*                                                                   *
  380. ;* All Original Registers Must Be Preserved Across Function Call!!!! *
  381. ;*                                                                   *
  382. ;*********************************************************************
  383. DevNull:
  384.         PUTMSG  1,<'%s/Null: called'>
  385.         CLEAR   D0
  386.         RTS
  387.  
  388. ;*********************************************************************
  389. ;*                     BeginIO Device Routine                        *
  390. ;*                                                                   *
  391. ;* BeginIO starts all incoming I/O.  The I/O is either queued up for *
  392. ;* the unit task or processed immediately.                           *
  393. ;*                                                                   *
  394. ;* BeginIO is often given the responsibility of making devices       *
  395. ;* single threaded, so that two tasks sending commands at the same   *
  396. ;* time don't cause a problem.  Once this has been done, the command *
  397. ;* is dispatched via PerformIO to the actual implementation code.    *
  398. ;*                                                                   *
  399. ;* There are many ways to do the threading.  This example uses the   *
  400. ;* UNITB_ACTIVE bit.  Be sure this method is good enough for your    *
  401. ;* device before using.  Any method is ok.  If immediate access can  *
  402. ;* not be obtained, the request is queued for later processing.      *
  403. ;*                                                                   *
  404. ;* Some I/O requests do not need single threading.  These can be     *
  405. ;* performed immediately.                                            *
  406. ;*                                                                   *
  407. ;* Inputs:                                                           *
  408. ;*   A6 - Ptr to our Device node.                                    *
  409. ;*   A1 - Ptr to the caller's I/O request block as initialized by    *
  410. ;*        OpenDevice().                                              *
  411. ;*                                                                   *
  412. ;*   Within the I/O request block:                                   *
  413. ;*      IO_COMMAND   The specific command desired by the caller.     *
  414. ;*      IO_LENGTH    Depends upon the particular command issued.     *
  415. ;*      IO_DATA      Depends upon the particular command issued.     *
  416. ;*      IO_MESSAGE   An mn_ReplyPort is required.                    *
  417. ;*      IO_DEVICE    Set by the OpenDevice() function.               *
  418. ;*      IO_UNIT      Set by the OpenDevice() function.               *
  419. ;*      IO_FLAGS     If the IOB_QUICK bit is set, the device will    *
  420. ;*                   -attempt- to handle the command on the caller's *
  421. ;*                   thread and avoid the overhead of a context      *
  422. ;*                   switch when the Exec Message System is used.    *
  423. ;*                                                                   *
  424. ;*                   If the command had to be queued (and therefore  *
  425. ;*                   the Exec Message System must be used), then     *
  426. ;*                   IOB_QUICK bit is cleared in the request block.  *
  427. ;*                   This means that the caller must use CheckIO()   *
  428. ;*                   and WaitIO() calls to detect when the command   *
  429. ;*                   is finished.                                    *
  430. ;*                                                                   *
  431. ;* Outputs:                                                          *
  432. ;*   D0        - ?????                                               *
  433. ;*   IO_ERROR  - Error code of operation (zero means success).       *
  434. ;*                                                                   *
  435. ;* All Original Registers Must Be Preserved Across Function Call!!!! *
  436. ;*                                                                   *
  437. ;* Notes:                                                            *
  438. ;*   The call to this routine is *NOT* single-threaded by Exec.      *
  439. ;*                                                                   *
  440. ;*   The Exec WaitIO() function uses the IORequest node type         *
  441. ;*   (LN_TYPE) as a flag.  If set to NT_MESSAGE, it assumes the      *
  442. ;*   request is still pending and will wait.  If set to NT_REPLYMSG, *
  443. ;*   it assumes the request is finished.  It's the responsibility of *
  444. ;*   the device to set the node type to NT_MESSAGE before returning  *
  445. ;*   to the user.                                                    *
  446. ;*                                                                   *
  447. ;*********************************************************************
  448. DevBeginIO:
  449.         IFGE    INFO_LEVEL-1
  450.         BCHG.B  #1,$BFE001      ; Blink the Power LED for Debugging Purposes
  451.         ENDC
  452.  
  453.         IFGE    INFO_LEVEL-3
  454.         CLR.L   -(SP)           ; Allocate and Clear a 32-bit Scratch Word on the Stack
  455.         MOVE.W  IO_COMMAND(A1),2(SP)  ; Pickup the 16-bit Command Word
  456.         PUTMSG  3,<'%s/BeginIO  --  %ld'>   ; Display a Debugging Message w/Command Code
  457.         ADDQ.L  #4,SP           ; Deallocate the 32-bit Scratch Word from the Stack
  458.         ENDC
  459.  
  460.         MOVEM.L D1/A0/A3,-(SP)  ; Preserve Original Registers
  461.         ;
  462.         ; Perform Basic Operation Setup
  463.         MOVE.B  #NT_MESSAGE,LN_TYPE(A1) ; Set Node Type so WaitIO() is Happy
  464.         MOVE.L  IO_UNIT(a1),A3          ; Pick up Ptr to Unit Descriptor in A3
  465.         MOVE.W  IO_COMMAND(A1),D0       ; Pick up Desired Command Code in D0
  466.         ;
  467.         ; Validate the Range of the Command Code
  468.         CMP.W   #CMDRANGE_END,D0        ; Is It In Range?
  469.         BCC     BeginIO_NoCmd           ; Nope, Reject It and Signal Error
  470.         ;
  471.         ; Check For an Immediate Command and Process Them Now
  472.         MOVE.L  #IMMEDIATES,D1          ; Pick up the Immediate Command Mask
  473.         DISABLE A0                      ; Disable Interrupts (Also Prevents Task Switches)
  474.         BTST.L  D0,D1                   ; Test Command Against Classification Mask
  475.         BNE     BeginIO_Immediate       ; Yes, It is an Immediate Command!
  476.         ;
  477.         ; Check For a Never-Immediate Command and Queue Them
  478.         MOVE.L  #NEVERIMMED,D1          ; Pick up the Never-Immediate Command Mask
  479.         BTST.L  D0,D1                   ; Test Command Against Classification Mask
  480.         BNE.S   BeginIO_QueueMsg        ; Yes, It is a Never-Immediate Command!
  481.         ;
  482.         ; See if the Unit is Stopped and Queue the Command If So
  483.         BTST    #MDUB_STOPPED,UNIT_FLAGS(A3)    ; Test Unit-Stopped Flag
  484.         BNE     BeginIO_QueueMsg        ; Yes, Go Queue the Command for Later
  485.         ;
  486.         ; This is not an immediate command.  See if the device is busy.
  487.         ; If the device is not, do the command on the user's thread,
  488.         ; else fire up the unit task.  This type of arbitration is not
  489.         ; really needed for a ram disk, but it is essential for a device
  490.         ; to reliably work with shared hardware.
  491.         ;
  492.         ; When the lines below are ";" commented out, the task gets a
  493.         ; better workout.  When the lines are active, the calling process
  494.         ; is usually used for the operation.
  495.         ;
  496.         ; REMEMBER: Never Wait() on the user's thread in BeginIO()!  The
  497.         ; only exception is when the user has indicated it is ok by
  498.         ; setting the "quick" bit.
  499.         BSET    #UNITB_ACTIVE,UNIT_FLAGS(A3)   ; Set the Unit-Active Flag
  500.         BEQ.S   BeginIO_Immediate
  501.         ;
  502.         ; Queue I/O Request for Unit Task for Pick Up and Execute
  503. BeginIO_QueueMsg:
  504.         BSET    #UNITB_INTASK,UNIT_FLAGS(A3)
  505.         BCLR    #IOB_QUICK,IO_FLAGS(A1)   ; Clear the I/O Quick Flag
  506.         ENABLE  A0                        ; Enable Interrupts (and Task Switching)
  507.  
  508.         IFGE INFO_LEVEL-250
  509.         MOVE.L  A1,-(SP)        ; Allocate and Store into a 32-bit Scratch Word
  510.         MOVE.L  A3,-(SP)        ; Allocate and Store into a 32-bit Scratch Word
  511.         PUTMSG  250,<'%s/PutMsg: Port=%lx Message=%lx'>
  512.         ADDQ.L  #8,SP           ; Deallocate Scratch Words from Stack
  513.         ENDC
  514.         ;
  515.         ; Send I/O Request Message to the Unit Task's Message Port
  516.         MOVE.L  A3,A0           ; Put Ptr to Unit Descriptor into A0 for PutMsg()
  517.         LINKSYS PutMsg,md_SysLib(A6)   ; Ptr to Port:A0, Ptr to Message:A1
  518.         BRA.S   BeginIO_End     ; Command Queued for Later, Jump to Function Exit
  519.         ;
  520.         ; Perform the Command on the Thread of the Calling Process
  521. BeginIO_Immediate:
  522.         ENABLE  A0              ; Enable Interrupts (and Task Switches)
  523.         BSR.S   PerformIO
  524. BeginIO_End:
  525.         PUTMSG  200,<'%s/BeginIO_End'>
  526.         MOVEM.L (SP)+,D1/A0/A3              ; Restore Original Registers
  527.         RTS
  528.  
  529. BeginIO_NoCmd:
  530.         MOVE.B  #IOERR_NOCMD,IO_ERROR(A1)   ; Signal Error - No Such Command
  531.         BRA.S   BeginIO_End                 ; Jump to Function Exit
  532.  
  533. ;*********************************************************************
  534. ;*                     AbortIO Device Routine                        *
  535. ;*                                                                   *
  536. ;* This function aborts an I/O request in progress.  If the request  *
  537. ;* is active, it is stopped immediately.  If the request is still    *
  538. ;* queued, it is removed from the queue.  The request is returned    *
  539. ;* in the same way as if it had normally completed.                  *
  540. ;*                                                                   *
  541. ;* Inputs:                                                           *
  542. ;*   A6 - Ptr to our Device node.                                    *
  543. ;*   A1 - Ptr to the caller's I/O request block as initialized by    *
  544. ;*        OpenDevice().                                              *
  545. ;*                                                                   *
  546. ;* Outputs:                                                          *
  547. ;*   D0        - Set to #IOERR_ABORTED                               *
  548. ;*   IO_ERROR  - ?????                                               *
  549. ;*                                                                   *
  550. ;* All Original Registers Must Be Preserved Across Function Call!!!! *
  551. ;*                                                                   *
  552. ;* Notes:                                                            *
  553. ;*  An AbortIO() is a -request- to "hurry up" processing of an I/O   *
  554. ;*  request.  If the request was already complete, nothing happens.  *
  555. ;*  The message must be replied with ReplyMsg() as normal.           *
  556. ;*                                                                   *
  557. ;*********************************************************************
  558. DevAbortIO:
  559.         MOVEQ   #IOERR_NOCMD,D0 ; Return "AbortIO() Request Failed"
  560.         RTS                     ; (Can't Abort I/O to Our Ramdisk)
  561.  
  562. ;*********************************************************************
  563. ;*                                                                   *
  564. ;*********************************************************************
  565.         END
  566.  
  567.