home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 508.lha / IO_Expansion_Board / NewPAR / NewPar.asm < prev   
Assembly Source File  |  1991-05-06  |  26KB  |  901 lines

  1. *****************************************************************************
  2. * Program:  eightbit.asm - Copyright ©1990,91 DigiSoft
  3. * Function: A "parallel.device" compatible driver for the Rockwell 65C22
  4. *
  5. * Author:   Paul Coward       ©1990 DigiSoft
  6. * History:  11/12/90 PC V0.50 Adapted from Sharer project to suit independent
  7. *                             IO PD project initiated by Jeff Lavin.
  8. *           01/14/91 PC V0.53 Finally !!!
  9. *
  10. * [To all: Please don't forget to bump the revision numbers
  11. *          if you do *any* modifications at all.  -Jeff]
  12. *****************************************************************************
  13.  
  14. **    Tabstops : 8
  15. **    Assemble with Macro68
  16.  
  17.  
  18.     ifnd    __m68
  19.     fail    'Wrong assembler!'
  20.     endc
  21.     exeobj
  22.     incpath    Includes:
  23.     macfile IOexp.i        ;The One & Only include file
  24.     objfile    ram:eightbit.device
  25.  
  26. ;   Name    P2   Centronics    (VIA_1)
  27. ;   ====    ==   ==========
  28. ;   CA2.2    2   1  STROBE*
  29. ;   PA0.2    3   2  DATA0
  30. ;   PA1.2    4   3  DATA1
  31. ;   PA2.2    5   4  DATA2
  32. ;   PA3.2    6   5  DATA3
  33. ;   PA4.2    7   6  DATA4
  34. ;   PA5.2    8   7  DATA5
  35. ;   PA6.2    9   8  DATA6
  36. ;   PA7.2   10   9  DATA7
  37. ;   CA1.2    1  10  ACK*
  38. ;   GND    PAD  16  GND
  39.  
  40. *****************************************************************************
  41. *     Everything in this block will eventually be transferred to ioexp.i    *
  42. *****************************************************************************
  43.  
  44. PVERSION    equ    1    ;major version number
  45. PREVISION    equ    6    ;minor version number
  46.  
  47. pcrBits    equ    %10101010    ;pulse output
  48. ierABits    equ    %00000010    ;CA1
  49. ierBBits    equ    %00010000    ;CB1
  50.  
  51. IOR    equ    0
  52. DDR    equ    DDRA-ORA
  53.  
  54. cdPri    equ    5
  55. mduStackSize    equ    $200
  56. mdTaskPri    equ    5
  57.  
  58.  
  59. ; --- Unit flags - pdu_devFlags
  60.  
  61.     BITDEF    rw,EOFMODE,0    ;unit read/write flag
  62.     BITDEF    rw,NULLMODE,1    ;unit read/write null terminated flag
  63.     BITDEF    io,SHARED,2    ;unit shared access allowed
  64.  
  65. ; my device data area structure
  66.  
  67.     setso    LIB_SIZE
  68. dev_Flags    so.b    1
  69. dev_MyFlags    so.b    1
  70. dev_SegList    so.l    1
  71. dev_Units    so.b    MD_NUMUNITS*4
  72. dev_SizeOf    soval
  73.  
  74.  
  75.     setso    UNIT_SIZE
  76. pdu_UnitNum    so.b    1
  77. pdu_devFlags    so.b    1
  78. pdu_IOparFlags    so.b    1
  79.     alignso    0,4
  80. pdu_stack    so.b    mduStackSize
  81. pdu_tcb    so.b    TC_SIZE
  82. pdu_Device    so.l    1
  83. pdu_HardwareBase    so.l    1
  84. pdu_IOReg    so.w    1
  85. pdu_ifrMask    so.w    1
  86. pdu_SigMask    so.l    1
  87. pdu_is    so.b    IS_SIZE
  88. pdu_rwBufferLocation so.l    1
  89. pdu_lengthCounter    so.l    1
  90. pdu_CurrentIOB    so.l    1
  91. pdu_TermArray    soval
  92. pdu_TermArray_0    so.b    (PTERMARRAY_SIZE/2)
  93. pdu_TermArray_1    so.b    (PTERMARRAY_SIZE/2)
  94. pdu_Sizeof    soval
  95.  
  96.     BITDEF    DEV,ACTIVE,0    ;device active flag
  97.     BITDEF    UNIT,STOPPED,2    ;status bit flag for unit stopped
  98.  
  99. *****************************************************************************
  100. *                    These will be local to this program                    *
  101. *****************************************************************************
  102.  
  103.     ifne    PTERMARRAY_SIZE-8
  104.     fail    'Commodore has changed PTERMARRAY size'
  105.     endc
  106.  
  107. INFO_LEVEL    equ    0
  108.  
  109. ***************************************
  110.  
  111. ;The first executable location.  This should return an error in case someone
  112. ;tried to run us as a program (instead of loading us as a device).
  113.  
  114.     moveq    #-1,d0
  115.     rts
  116.  
  117. ;A romtag structure.  After your driver is brought in from disk, the
  118. ;disk image will be scanned for this structure to discover magic constants
  119. ;about you (such as where to start running you from...).
  120.  
  121. initDevDescript:
  122.     dw    RTC_MATCHWORD
  123.     dl    initDevDescript
  124.     dl    EndCode
  125.     db    RTF_AUTOINIT    ;RT_FLAGS
  126.     db    PVERSION
  127.     db    NT_DEVICE
  128.     db    cdPri    ;RT_PRI
  129.     dl    cdName
  130.     dl    cdIDString
  131.     dl    DevInit    ;RT_INIT
  132.  
  133. cdName:    PARDEVNAME    ;This is the name that the device will have
  134.  
  135. ;This is an identifier tag to help in supporting the device
  136. ;format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
  137.  
  138. cdIDString:
  139.     PARIDENT
  140.  
  141. ;The romtag specified that we were "RTF_AUTOINIT".  This means that the
  142. ;RT_INIT structure member points to one of these tables below.  If the
  143. ;AUTOINIT bit was not set then RT_INIT would point to a routine to run.
  144.  
  145. DevInit:
  146.     dl    dev_SizeOf    ;data space size
  147.     dl    funcTable    ;pointer to function initializers
  148.     dl    dataTable    ;pointer to data initializers
  149.     dl    initRoutine    ;routine to run
  150.  
  151. funcTable:
  152.     dl    Open    ;standard system routines
  153.     dl    Close
  154.     dl    Expunge
  155.     dl    ExtFunc    ;Reserved for future use!
  156.     dl    BeginIO    ;my device definitions
  157.     dl    AbortIO
  158.     dl    -1    ;function table end marker
  159.  
  160. ;The data table initializes static data structures. The format is
  161. ;specified in exec/InitStruct routine's manual pages.  The
  162. ;INITBYTE/INITWORD/INITLONG macros are in the file "exec/initializers.i".
  163. ;The first argument is the offset from the device base for this
  164. ;byte/word/long. The second argument is the value to put in that cell.
  165. ;The table is null terminated
  166.  
  167. dataTable:
  168.     INITBYTE LH_TYPE,NT_DEVICE
  169.     INITLONG LN_NAME,cdName
  170.     INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
  171.     INITWORD LIB_VERSION,PVERSION
  172.     INITWORD LIB_REVISION,PREVISION
  173.     INITLONG LIB_IDSTRING,cdIDString
  174.     dl     0    ;terminate list
  175.  
  176.  
  177. ;This routine gets called after the device has been allocated.  The device
  178. ;pointer is in D0.  The AmigaDOS segment list is in a0.  If it returns the
  179. ;device pointer, then the device will be linked into the device list.  If it
  180. ;returns NULL, then the device will be unloaded.
  181. ;
  182. ;This call is single-threaded by exec; please read the description for
  183. ;"Open" below.
  184. ;
  185. ; Register Usage
  186. ; ==============
  187. ; a3 -- Points to temporary RAM
  188. ; a4 -- Expansion library base
  189. ; a5 -- device pointer
  190. ; a6 -- Exec base
  191.  
  192. initRoutine:    movea.l    d0,a1        ;get device pointer
  193.     move.l    a0,(dev_SegList,a1)    ;save a pointer to our loaded code
  194.     rts
  195.  
  196.  
  197. ;Here begins the system interface commands.  When the user calls OpenDevice/
  198. ;CloseDevice/RemDevice, this eventually gets translated into a call to the
  199. ;following routines (Open/Close/Expunge).  Exec has already put our device
  200. ;pointer in a6 for us.
  201. ;
  202. ;Open sets the IO_ERROR field on an error. If it was successful, we should
  203. ;also set up the IO_UNIT and LN_TYPE fields.  exec takes care of setting up
  204. ;IO_DEVICE.
  205. ;
  206. ;NOTE: We must also copy the current prefs for this unit into the user's
  207. ;extended iorequest fields.
  208. ;
  209. ; Register Usage
  210. ; ==============
  211. ; d0 -- unitnum
  212. ; d1 -- flags
  213. ; a1 -- iob
  214. ; a6 -- Device ptr
  215.  
  216. Open:    pushm    d2/a2-a4
  217.     PUTDEBUG 1,<10,10,'STARTING NEW DEBUG RUN',10,10>
  218.     movea.l    a1,a2    ;save the iob
  219.     moveq    #MD_NUMUNITS,d2    ;see that the unit number is in range
  220.     cmp.l    d2,d0
  221.     bcc.b    .openError
  222.     move.l    d0,d2    ;see if the unit is already initialized
  223.     lsl.l    #2,d0
  224.     lea    (dev_Units,a6,d0.l),a4
  225.     move.l    (a4),d0
  226.     beq.b    1$    ;unit not open - so open it
  227.     movea.l    d0,a0
  228.     btst    #ioB_SHARED,(pdu_devFlags,a0)    ;see if unit allows shared access
  229.     beq.b    .openError    ;error if not
  230.     btst    #PARB_SHARED,d1    ;see if the open request allows shared access
  231.     bne.b    .openUnitOK
  232.     bra.b    .openError    ;unit can have only ONE client
  233. 1$    bsr    InitUnit    ;try and conjure up a unit
  234.     move.l    (a4),d0    ;see if it opened ok
  235.     beq.b    .openError
  236. .openUnitOK:    movea.l    d0,a3    ;unit pointer
  237.     move.l    d0,(IO_UNIT,a2)
  238.     addq.w    #1,(LIB_OPENCNT,a6)    ;mark us as having another customer
  239.     addq.w    #1,(UNIT_OPENCNT,a3)
  240.     bclr    #LIBB_DELEXP,(dev_Flags,a6)    ;prevent delayed expunges
  241.     btst    #PARB_SHARED,d1    ;see if the open request allows shared access
  242.     beq.b    2$
  243.     bset    #ioB_SHARED,(pdu_devFlags,a3)    ;unit allows shared access
  244. 2$    clr.b    (IO_ERROR,a2)
  245.     btst    #PARB_EOFMODE,(IO_PARFLAGS,a2)    ;eof enabled mode set ?
  246.     beq.b    .openEnd
  247.     move.l    (pdu_TermArray,a3),(IO_PTERMARRAY+PTERMARRAY_0,a2)
  248.     move.l    (pdu_TermArray+4,a3),(IO_PTERMARRAY+PTERMARRAY_1,a2)
  249. .openEnd:    popm    d2/a2-a4
  250.     rts
  251.  
  252. .openError:    move.b    #IOERR_OPENFAIL,(IO_ERROR,a2)
  253.     PUTDEBUG 95,<'Open device routine exiting with error'>
  254.     bra.b    .openEnd
  255.  
  256.  
  257.  
  258. ;--------------------------------------------------------------
  259. ; --- initunit initializes a device unit and starts up the 
  260. ; --- associated unit task
  261. ;--------------------------------------------------------------
  262.  
  263. ; --- (unit number:D2 scratch:A3 device:A6)
  264.  
  265. InitUnit:    pushm    d2/a2/a5-a6
  266.     PUTDEBUG 90,<'InitUnit routine called'>
  267.     movea.l    a6,a5        ;device pointer
  268.     movea.l    (SysBase).w,a6
  269.     move.l    #pdu_Sizeof,d0
  270.     move.l    #MEMF_PUBLIC!MEMF_CLEAR,d1
  271.     jsr    (_LVOAllocMem,a6)
  272.     tst.l    d0
  273.     beq    .initUnitEnd
  274.  
  275.     movea.l    d0,a3
  276.     movea.l    a3,a2        ;for InitStruct
  277.     moveq    #0,d0        ;don't 0 the rest
  278.     lea    (UnitInitStruct,pc),a1
  279.     jsr    (_LVOInitStruct,a6)
  280.     move.b    d2,(pdu_UnitNum,a3)    ;initialize unit number
  281.     move.l    a5,(pdu_Device,a3)
  282.     lea    (pdu_stack,a3),a0
  283.     move.l    a0,(pdu_tcb+TC_SPLOWER,a3)
  284.     lea    (mduStackSize,a0),a0
  285.     move.l    a0,(pdu_tcb+TC_SPUPPER,a3)
  286.     move.l    a3,-(a0)    ;pass unit pointer on the stack
  287.     move.l    a0,(pdu_tcb+TC_SPREG,a3)
  288.     lea    (pdu_tcb,a3),a0
  289.     move.l    a0,(MP_SIGTASK,a3)
  290.     lea    (MP_MSGLIST,a3),a0
  291.     NEWLIST    a0
  292.     lea    (pdu_tcb,a3),a1
  293.     lea    (mdTask_Start,pc),a2    ;for AddTask
  294.     PUSH    a3
  295.     suba.l    a3,a3
  296.     subq.l    #1,a3        ;force odd address GURU if the task ever exits
  297.     moveq    #0,d0
  298.     jsr    (_LVOAddTask,a6)
  299.     POP    a3
  300.     lsl.l    #2,d2
  301.     move.l    a3,(dev_Units,a5,d2.l)    ;put unit pointer into device structure
  302.     add.w    d2,d2
  303.     move.w    (hardwareBaseArray,pc,d2.l),(pdu_IOReg,a3)
  304.     move.w    (hardwareBaseArray+2,pc,d2.l),(pdu_ifrMask,a3)
  305.     move.l    (hardwareBaseArray+4,pc,d2.l),(pdu_HardwareBase,a3)
  306.     move.l    a3,(pdu_is+IS_DATA,a3)
  307.     move.l    #InterruptCode,(pdu_is+IS_CODE,a3)
  308.     movea.l    (pdu_HardwareBase,a3),a0
  309.     move.b    (pdu_ifrMask+1,a3),(INTER,a0)    ;make sure interrupts are off
  310.     move.b    #pcrBits,(PERCR,a0)    ;set up the controll register (both ports - dosn't matter)
  311. .initUnitEnd:    popm    d2/a2/a5-a6
  312.     rts
  313.  
  314.  
  315. ;Table of VIA base addresses for the 4 units
  316.  
  317. hardwareBaseArray:
  318.     dw    ORA    ;register offset from hardware base
  319.     dw    ierABits    ;interrupt flag mask
  320.     dl    VIA_Base+VIA0    ;base address for hardware unit 0
  321.     dw    ORB    ;register offset from hardware base
  322.     dw    ierBBits    ;interrupt flag mask
  323.     dl    VIA_Base+VIA0    ;base address for hardware unit 1
  324.     dw    ORA    ;register offset from hardware base
  325.     dw    ierABits    ;interrupt flag mask
  326.     dl    VIA_Base+VIA1    ;base address for hardware unit 2
  327.     dw    ORB    ;register offset from hardware base
  328.     dw    ierBBits    ;interrupt flag mask
  329.     dl    VIA_Base+VIA1    ;base address for hardware unit 3
  330.  
  331.  
  332. ; --- (unitptr:A3 deviceptr:A6)
  333.  
  334. FreeUnit:    movea.l    a3,a1
  335.     PUTDEBUG 85,<'FreeUnit routine called'>
  336.     move.l    #pdu_Sizeof,d0
  337.     push    a6
  338.     movea.l    (SysBase).w,a6
  339.     jsr    (_LVOFreeMem,a6)
  340.     pop    a6
  341. ExtFunc:    moveq    #0,d0
  342.     rts
  343.  
  344.  
  345. ; --- (unitptr:A3 deviceptr:A6)
  346.  
  347. ExpungeUnit:    push    d2
  348.     PUTDEBUG 85,<'ExpungeUnit routine called'>
  349.     lea    (pdu_tcb,a3),a1
  350.     push    a6
  351.     movea.l    (SysBase).w,a6
  352.     jsr    (_LVORemTask,a6)
  353.     pop    a6
  354.     moveq    #0,d2
  355.     move.b    (pdu_UnitNum,a3),d2    ;save the unit number
  356.     bsr    FreeUnit    ;free the unit structure
  357.     lsl.l    #2,d2
  358.     clr.l    (dev_Units,a6,d2.l)    ;clear the unit vector from the device
  359.     pop    d2
  360.     rts
  361.  
  362. ;There are two different things that might be returned from the Close
  363. ;routine.  If the device wishes to be unloaded, then Close must return
  364. ;the segment list (as given to Init).  Otherwise close MUST return NULL.
  365. ; ( device:a6, iob:a1 )
  366.  
  367. Close:    pushm    a2-a3
  368.     PUTDEBUG 80,<'Close device routine called'>
  369.     movea.l    a1,a2        ;save iob pointer
  370.     movea.l    (IO_UNIT,a2),a3
  371.     moveq    #-1,d0        ;make sure that the iob is not used again
  372.     move.l    d0,(IO_UNIT,a2)
  373.     move.l    d0,(IO_DEVICE,a2)
  374.     subq.w    #1,(UNIT_OPENCNT,a3)    ;see if the unit is still in use
  375.     bne.b    .closeDevice
  376.     bsr    ExpungeUnit
  377. .closeDevice:    subq.w    #1,(LIB_OPENCNT,a6)
  378.     bne.b    .closeEnd
  379.     btst    #LIBB_DELEXP,(pd_Flags,a6)
  380.     beq.b    .closeEnd
  381.     bsr    Expunge
  382. .closeEnd:    popm    a2-a3
  383.     rts
  384.  
  385. ;Expunge is called by the memory allocator when the system is low on
  386. ;memory.
  387. ;
  388. ;There are two different things that might be returned from the Expunge
  389. ;routine.  If the device is no longer open then Expunge may return the
  390. ;segment list (as given to Init).  Otherwise Expunge may set the
  391. ;delayed expunge flag and return NULL.
  392. ;
  393. ;One other important note: because Expunge is called from the memory
  394. ;allocator, it may NEVER Wait() or otherwise take long time to complete.
  395. ;
  396. ; A6          - library base (scratch)
  397. ; D0-D1/A0-A1 - scratch
  398.  
  399. Expunge:    pushm    d2/a5/a6
  400.     moveq    #0,d2
  401.     movea.l    a6,a5
  402.     movea.l    (SysBase).w,a6
  403.     tst.w    (LIB_OPENCNT,a5)    ;any users left ?
  404.     beq.b    1$
  405.     bset    #LIBB_DELEXP,(pd_Flags,a5)    ;if there then delay the expunge
  406.     bra.b    .expungeEnd
  407.  
  408. 1$    move.l    (dev_SegList,a5),d2
  409.     movea.l    a5,a1
  410.     jsr    (_LVORemove,a6)        ;unlink from the library list
  411.     moveq    #0,d0        ;release our memory
  412.     movea.l    a5,a1
  413.     move.w    (LIB_NEGSIZE,a5),d0
  414.     suba.l    d0,a1
  415.     add.w    (LIB_POSSIZE,a5),d0
  416.     jsr    (_LVOFreeMem,a6)
  417. .expungeEnd:    move.l    d2,d0        ;set up our return value
  418.     popm    d2/a5/a6
  419.     rts
  420.  
  421. ;------------------------------------------------------------------------------
  422. ;
  423. ;    Here begins the real device stuff
  424. ;
  425. ;------------------------------------------------------------------------------
  426.  
  427. ;BeginIO starts all incoming io.  The IO is either queued up for the
  428. ;unit task or processed immediately.
  429. ;
  430. ;BeginIO often is given the responsibility of making devices single
  431. ;threaded... so two tasks sending commands at the same time don't cause
  432. ;a problem.  Once this has been done, the command is dispatched via
  433. ;PerformIO.
  434. ;
  435. ;There are many ways to do the threading.  This example uses the
  436. ;UNITB_ACTIVE bit.  Be sure this is good enough for your device before
  437. ;using!  Any method is ok.  If immediate access can not be obtained, the
  438. ;request is queued for later processing.
  439. ;
  440. ;Some IO requests do not need single threading. These can be performed
  441. ;immediatley.
  442. ;
  443. ;IMPORTANT:
  444. ; The exec WaitIO() function uses the IORequest node type (LN_TYPE)
  445. ; as a flag.  If set to NT_MESSAGE, it assumes the request is
  446. ; still pending and will wait.  If set to NT_REPLYMSG, it assumes the
  447. ; request is finished.  It's the responsibility of the device driver
  448. ; to set the node type to NT_MESSAGE before returning to the user.
  449. ;
  450. ;Notes: This routine will look at io_command to determine which task
  451. ;to use. Break with QUEUEDBRK and Write requests go to the write
  452. ;task. Read requests (only) go to the read task. 
  453. ;Break requests without QUEUEDBRK initiate a write task exception.
  454. ;The actual break job is started, and finished, within that exception.
  455. ;At the end of the exception, the write task resumes whatever it was
  456. ;doing before the break.
  457. ;All other requests are performed immediately, i.e. within the caller's
  458. ;context.
  459. ;
  460. ; ( iob: a1, device:a6 )
  461.  
  462. AbortIO:    clr.b    (IO_ERROR,a1)
  463.     movea.l    (IO_UNIT,a1),a0
  464.     cmpa.l    (pdu_CurrentIOB,a0),a1
  465.     bne.b    1$
  466.     clr.l    (pdu_CurrentIOB,a0)
  467. 1$    rts
  468.  
  469.  
  470. ;This define is used to tell which commands should be handled
  471. ;immediately (on the caller's schedule).
  472. ;
  473. ;The immediate commands are Invalid, Reset, Stop, Start, Flush, Clear,
  474. ;Query, and SetParams
  475. ;
  476. ;Note that this method limits you to just 32 device specific commands,
  477. ;which may not be enough.
  478.  
  479. IMMEDIATES    equ    %00000000000000000000000111000011
  480. ;         --------========--------========
  481. ;         FEDCBA9876543210FEDCBA9876543210
  482.  
  483. VIATASK    equ    $0000000C
  484.  
  485.  
  486. BeginIO:    push    a4
  487.     clr.b    (IO_ERROR,a1)
  488.     move.b    #NT_MESSAGE,(LN_TYPE,a1)
  489.     movea.l    (IO_UNIT,a1),a4
  490.     move.w    (IO_COMMAND,a1),d0
  491.     cmpi.w    #PDCMD_SETPARAMS,d0
  492.     bgt    .noCmd
  493.     PUTDEBUG 75,<'BeginIO -- got a valid command'>
  494.     Disable    a0
  495.     move.w    #IMMEDIATES,d1
  496.     btst    d0,d1
  497.     bne    .immediate
  498.     move.w    #VIATASK,d1
  499.     btst    d0,d1
  500.     bne    .queueMsg
  501.     btst    #UNITB_STOPPED,(UNIT_FLAGS,a4)
  502.     bne.b    .queueMsg
  503.     bset    #UNITB_ACTIVE,(UNIT_FLAGS,a4)
  504.     beq.b    .immediate
  505. .queueMsg:    bset    #UNITB_INTASK,(UNIT_FLAGS,a4)
  506.     bclr    #IOB_QUICK,(IO_FLAGS,a1)
  507.     Enable    a0
  508.     movea.l    a4,a0
  509.     push    a6
  510.     movea.l    (SysBase).w,a6
  511.     jsr    (_LVOPutMsg,a6)
  512.     pop    a6
  513.     bra.b    .end
  514. .immediate:    Enable    A0
  515.     bsr    PerformIO
  516. .end:    pop    a4
  517.     rts
  518.  
  519. .noCmd:    move.b    #IOERR_NOCMD,(IO_ERROR,a1)
  520.     bra.b    .end
  521.  
  522. ;Cmdtable is used to look up the address of a routine that will
  523. ;implement the device command.
  524.  
  525. cmdtable:
  526.     dw    Invalid-cmdtable
  527.     dw    MyReset-cmdtable
  528.     dw    Read-cmdtable
  529.     dw    Read-cmdtable
  530.     dw    Invalid-cmdtable
  531.     dw    Clear-cmdtable
  532.     dw    MyStop-cmdtable
  533.     dw    Start-cmdtable
  534.     dw    Flush-cmdtable
  535.     dw    Query-cmdtable
  536.     dw    SetParams-cmdtable
  537.  
  538.  
  539. PerformIO:    pushm    a2-a3
  540.     movea.l    a1,a2
  541.     movea.l    (pdu_HardwareBase,a4),a3
  542.     move.w    (IO_COMMAND,a2),d0
  543.     ifge    INFO_LEVEL-65
  544.     push    d0
  545.     push    a1
  546.     PUTDEBUG 65,<'PerformIO --- IOB @ $%lx --- Command =%ld'>
  547.     addq.w    #8,sp
  548.     endc
  549.     add.w    d0,d0
  550.     lea    (cmdtable,pc),a0
  551.     adda.w    (0,a0,d0.w),a0
  552.     jsr    (a0)
  553.  
  554. ; --- (iob:A2 unitptr:A4 device:A6)
  555.  
  556. TermIO:    move.w    (IO_COMMAND,a2),d0
  557.     move.w    #IMMEDIATES,d1
  558.     btst    d0,d1
  559.     bne.b    .termIOimmediate
  560.     btst    #UNITB_INTASK,(UNIT_FLAGS,a4)
  561.     bne.b    .termIOimmediate
  562.     bclr    #UNITB_ACTIVE,(UNIT_FLAGS,a4)
  563. .termIOimmediate:
  564.     btst    #IOB_QUICK,(IO_FLAGS,a2)
  565.     bne.b    .termIOend
  566.     ifge    INFO_LEVEL-70
  567.     push    a2
  568.     PUTDEBUG 70,<'TermIO --- Reply msg IOB @ $%lx'>
  569.     addq.w    #4,sp
  570.     endc
  571.     movea.l    a2,a1
  572.     push    a6
  573.     movea.l    (SysBase).w,a6
  574.     jsr    (_LVOReplyMsg,a6)
  575.     pop    a6
  576. .termIOend:    popm    a2-a3
  577.     rts
  578.  
  579. ;------------------------------------------------------------------------------
  580. ; --- Invalid command sent to this device - return error
  581. ; --- Clear - do nothing - not supported
  582. ;------------------------------------------------------------------------------
  583.  
  584. Invalid:    move.b    #IOERR_NOCMD,(IO_ERROR,a1)
  585. Clear:    rts
  586.  
  587. ;------------------------------------------------------------------------------
  588. ; --- Reset the hardware for this unit
  589. ;------------------------------------------------------------------------------
  590.  
  591. MyReset:    bsr.b    Flush
  592.     move.b    #pcrBits,(PERCR,a3)
  593.     move.b    (pdu_ifrMask+1,a4),(INTFR,a3)
  594.     move.b    (pdu_ifrMask+1,a4),(INTER,a3)
  595.     rts
  596.  
  597. ;------------------------------------------------------------------------------
  598. ; --- Stop the unit
  599. ; --- Start the unit
  600. ;------------------------------------------------------------------------------
  601.  
  602. MyStop:    bset    #UNITB_STOPPED,(UNIT_FLAGS,a4)
  603.     clr.l    (IO_ACTUAL,a1)
  604.     rts
  605.  
  606. Start:    bsr.b    InternalStart
  607.     movea.l    a2,a1
  608.     clr.l    (IO_ACTUAL,a1)
  609.     rts
  610.  
  611. InternalStart:    bclr    #UNITB_STOPPED,(UNIT_FLAGS,a4)    ;turn processing back on
  612.     movea.l    a4,a1        ;kick the task to start it moving
  613.     moveq    #0,d0
  614.     move.b    (MP_SIGBIT,a4),d1
  615.     bset    d1,d0
  616.     push    a6
  617.     movea.l    (SysBase).w,a6
  618.     jsr    (_LVOSignal,a6)
  619.     pop    a6
  620.     rts
  621.  
  622. ;------------------------------------------------------------------------------
  623. ; --- Flush pulls all io requests off the que and sends them back.
  624. ; -- We must be carefull not to destroy work in progress, and also
  625. ; -- that we do not let some io requests slip by.
  626. ;
  627. ; --- Some funny magic goes on with the STOPPED bit in here.  Stop is
  628. ; -- defined as not being reentrant.  We therefore save the old state
  629. ; -- of the bit and then restore it later.  This keeps us from needing
  630. ; -- to DISABLE in flush.  It also fails miserably if someone does a
  631. ; -- start in the middle of a flush.
  632. ;------------------------------------------------------------------------------
  633.  
  634. Flush:    pushm    d2/a6
  635.     clr.l    (pdu_CurrentIOB,a4)
  636.     movea.l    (SysBase).w,a6
  637.     bset    #UNITB_STOPPED,(UNIT_FLAGS,a4)
  638.     sne    d2
  639. Flush_Loop:    movea.l    a4,a0
  640.     jsr    (_LVOGetMsg,a6)
  641.     tst.l    d0
  642.     beq.b    Flush_End
  643.     movea.l    d0,a1
  644.     move.b    #IOERR_ABORTED,(IO_ERROR,a1)
  645.     jsr    (_LVOReplyMsg,a6)
  646.     bra.b    Flush_Loop
  647. Flush_End:    move.l    d2,d0
  648.     popm    d2/a6
  649.     tst.b    d0
  650.     beq.b    1$
  651.     bsr    InternalStart
  652. 1$    movea.l    a2,a1
  653.     rts
  654.  
  655. ;------------------------------------------------------------------------------
  656. ; --- Query the parallel device unit status
  657. ;------------------------------------------------------------------------------
  658.  
  659. Query:    clr.b    (IO_PARSTATUS,a1)    ;return the current status
  660.     rts
  661.  
  662. ;------------------------------------------------------------------------------
  663. ; --- Set the parallel device unit parameters
  664. ;------------------------------------------------------------------------------
  665.  
  666. SetParams:    btst    #UNITB_ACTIVE,(pdu_devFlags,a4)
  667.     beq.b    .modeIsCorrect
  668.     move.b    #1,(IO_ERROR,a1)
  669.     bra.b    .return
  670. .modeIsCorrect:    move.b    (IO_PARFLAGS,a1),(pdu_IOparFlags,a4)
  671.     btst    #PARB_EOFMODE,(pdu_IOparFlags,a4)
  672.     beq.b    .return
  673.     move.l    (IO_PTERMARRAY+PTERMARRAY_0,a1),(pdu_TermArray_0,a4)
  674.     move.l    (IO_PTERMARRAY+PTERMARRAY_1,a1),(pdu_TermArray_1,a4)
  675. .return:    rts
  676.  
  677. ;------------------------------------------------------------------------------
  678. ; --- Read/Write
  679. ;------------------------------------------------------------------------------
  680.  
  681. Read:    tst.l    (IO_LENGTH,a1)
  682.     bne.b    .performIO
  683.     clr.l    (IO_ACTUAL,a1)
  684.     rts
  685.  
  686. .performIO:    push    a6
  687.     PUTDEBUG 50,<'Read/Write'>
  688.     move.w    (pdu_IOReg,a4),d7
  689.     bclr    #rwB_NULLMODE,(pdu_devFlags,a4)
  690.     bset    #IOPARB_ACTIVE,(IO_FLAGS,a1)    ;active
  691.     move.l    (IO_DATA,a1),(pdu_rwBufferLocation,a4)    ;initialize buffer pointer
  692.     clr.l    (pdu_lengthCounter,a4)    ;clear buffer counter
  693.     move.l    a1,(pdu_CurrentIOB,a4)    ;store the current IOB structure
  694.     tst.l    (IO_LENGTH,a1)    ;a -1 here means read to eof
  695.     bpl.b    .notEOFmode
  696.     bset    #rwB_NULLMODE,(pdu_devFlags,a4)
  697. .notEOFmode:    lea    (0,a3,d7.w),a0
  698.     cmpi.w    #CMD_READ,(IO_COMMAND,a1)
  699.     beq.b    .setDataDirectionIN
  700. .setDataDirectionOUT:
  701.     move.b    #0,(IOR,a0)
  702.     move.b    #-1,(DDR,a0)
  703.     bra.b    .letTheInterruptWork
  704.  
  705. .setDataDirectionIN:
  706.     move.b    #0,(IOR,a0)    ;just for the hell of it
  707.     move.b    #0,(DDR,a0)
  708.  
  709. .letTheInterruptWork:
  710.     move.w    (pdu_ifrMask,a4),d0
  711.     move.b    d0,(INTFR,a3)    ;clear the interrupt bit
  712.     lea    (pdu_is,a4),a1
  713.     moveq    #INTB_EXTER,d0    ;(level 6) interrupt
  714.     movea.l    (SysBase).w,a6
  715.     jsr    (_LVOAddIntServer,a6) 
  716.     Disable
  717.     move.w    (pdu_ifrMask,a4),d0
  718.     ori.w    #$80,d0
  719.     move.b    d0,(INTER,a3)    ;enable chip interrupt
  720.     move.l    (pdu_SigMask,a4),d0
  721.     ifge    INFO_LEVEL-50
  722.     push    d0
  723.     push    (ThisTask,a6)
  724.     PUTDEBUG 50,<'Task @ $%lx waiting -- sigmask = $%lx'>
  725.     addq.w    #8,sp
  726.     endc
  727.     jsr    (_LVOWait,a6)    ;sleep while the interrupt does the work
  728.     PUTDEBUG 70,<'Got signal'>
  729.     Enable
  730.     lea    (pdu_is,a4),a1
  731.     moveq    #INTB_EXTER,d0
  732.     jsr    (_LVORemIntServer,a6)    ;remove the interrupt server
  733.     PUTDEBUG 50,<'Read/Write finished'>
  734.     pop    a6
  735.     rts
  736.  
  737. ****************************************
  738. ***   ===   INTERRUPT DRIVER   ===   ***
  739. ****************************************
  740.  
  741. InterruptCode:    pushm    d1-d7/a0-a6
  742.     movea.l    a1,a4
  743.     movea.l    (pdu_HardwareBase,a4),a3
  744.     move.b    (INTFR,a3),d7
  745.     and.w    (pdu_ifrMask,a4),d7
  746.     bne.b    .isMine
  747.     popm    d1-d7/a0-a6
  748.     moveq    #0,d0
  749.     rts
  750.  
  751. .isMine:    move.l    (pdu_CurrentIOB,a4),d0
  752.     beq    .noCurrentIOB
  753.     movea.l    d0,a1
  754.     move.w    (pdu_IOReg,a4),d7
  755. .read_write:    movea.l    (pdu_rwBufferLocation,a4),a0
  756.     btst    #IOPARB_ABORT,(IO_FLAGS,a1)
  757.     bne    .rwFINISHED
  758.     cmpi.w    #CMD_WRITE,(IO_COMMAND,a1)
  759.     bne.b    .READdata
  760.     ifge    INFO_LEVEL-200
  761.     pea    (IOR,a3,d7.w)
  762.     moveq    #0,d0
  763.     move.b    (a0),d0
  764.     push    d0
  765.     PUTDEBUG 100,<'Writing byte $%lx to IOR @ $%08lx'>
  766.     addq.w    #8,sp
  767.     endc
  768.     move.b    (a0)+,(IOR,a3,d7.w)
  769.     bne    .updateCounters
  770.     btst    #rwB_NULLMODE,(pdu_devFlags,a4)
  771.     beq.b    .updateCounters
  772.     bra    .rwFINISHED
  773.  
  774. .READdata:    move.b    (IOR,a3,d7.w),d0
  775.     bne.b    .notNullCharRead
  776.     ifge    INFO_LEVEL-200
  777.     pea    (IOR,a3,d7.w)
  778.     andi.l    #$ff,d0
  779.     push    d0
  780.     PUTDEBUG 100,<'Read non-zero byte = $%08lx from IOR @ $%lx'>
  781.     addq.w    #8,sp
  782.     endc
  783.     btst    #rwB_NULLMODE,(pdu_devFlags,a4)
  784.     bne    .rwFINISHED
  785. .notNullCharRead:
  786.     movea.l    (pdu_rwBufferLocation,a4),a0
  787.     move.b    d0,(a0)+
  788. .updateCounters:
  789.     move.l    a0,(pdu_rwBufferLocation,a4)
  790.     addq.l    #1,(pdu_lengthCounter,a4)
  791.     btst    #PARB_EOFMODE,(IO_PARFLAGS,a1)    ;test EOF mode enabled bit in IOB
  792.     beq.b    .noTermArraySet
  793.     lea    (IO_PTERMARRAY+PTERMARRAY_0,a1),a0
  794.     moveq    #8-1,d1
  795. .checkForTermMatch:
  796.     cmp.b    (a0)+,d0
  797.     dbcc    d1,.checkForTermMatch
  798.     beq.b    .rwFINISHED
  799. .noTermArraySet:
  800.     move.l    (IO_LENGTH,a1),d0
  801.     bmi    .rwUntilNullTerm
  802.     cmp.l    (pdu_lengthCounter,a4),d0
  803.     bgt    .rwUntilNullTerm
  804.  
  805. .rwFINISHED:    move.l    (pdu_lengthCounter,a4),(IO_ACTUAL,a1)
  806.     bclr    #IOPARB_ACTIVE,(IO_FLAGS,a1)    ;clear request queued or current bit
  807. .noCurrentIOB:    bclr    #rwB_NULLMODE,(pdu_devFlags,a4)
  808.     bclr    #DEVB_ACTIVE,(pdu_devFlags,a4)
  809.     clr.l    (pdu_CurrentIOB,a4)
  810.     movea.l    (SysBase).w,a6
  811.     move.l    (pdu_SigMask,a4),d0
  812.     lea    (pdu_tcb,a4),a1
  813.     ifge    INFO_LEVEL-50
  814.     push    d0
  815.     push    a0
  816.     PUTDEBUG 65,<'Signaling task @ $%lx with signal $%lx'>
  817.     addq.w    #8,sp
  818.     endc
  819.     jsr    (_LVOSignal,a6)
  820.     move.b    (pdu_ifrMask+1,a4),(INTER,a3)    ;disable chip interrupt
  821. .rwUntilNullTerm:
  822.     popm    d1-d7/a0-a6
  823.     moveq    #1,d0        ;terminate the interrupt chain
  824.     rts
  825.  
  826.  
  827. ;------------------------------------------------------------------------------
  828. ; --- Sub-task related stuff
  829. ;------------------------------------------------------------------------------
  830. ;------------------------------------------------------------------------------
  831. ;
  832. ;    Register Usage
  833. ;        A6 = exec pointer
  834. ;        A5 = device pointer
  835. ;        A4 = unit pointer
  836. ;        D7 = wait mask
  837. ;
  838. ;------------------------------------------------------------------------------
  839. ;------------------------------------------------------------------------------
  840.  
  841.  
  842. mdTask_Start:    movea.l    (SysBase).w,a6
  843.     movea.l    (4,sp),a4    ;unit pointer
  844.     movea.l    (pdu_Device,a4),a5    ;device pointer
  845.     moveq    #-1,d0        ;-1 is any signal at all
  846.     jsr    (_LVOAllocSignal,a6)
  847.     moveq    #0,d7
  848.     bset    d0,d7
  849.     move.l    d7,(pdu_SigMask,a4)    ;signal for when interrupt is finished
  850.     moveq    #-1,d0        ;-1 is any signal at all
  851.     jsr    (_LVOAllocSignal,a6)
  852.     move.b    d0,(MP_SIGBIT,a4)
  853.     move.b    #PA_SIGNAL,(MP_FLAGS,a4)
  854.     moveq    #0,d7
  855.     bset    d0,d7
  856.     bra.b    .checkStatus
  857.  
  858. .unlock:    andi.b    #$FF&(~(UNITB_ACTIVE!UNITB_INTASK)),(UNIT_FLAGS,a4)
  859. .mainLoop:    move.l    d7,d0
  860.     jsr    (_LVOWait,a6)
  861. .checkStatus:    btst    #UNITB_STOPPED,(UNIT_FLAGS,a4)    ;see if we are stopped
  862.     bne.b    .mainLoop
  863.     bset    #UNITB_ACTIVE,(UNIT_FLAGS,a4)
  864.     bne.b    .mainLoop    ;device in use
  865. .nextMessage:    movea.l    a4,a0
  866.     jsr    (_LVOGetMsg,a6)
  867.     tst.l    d0
  868.     beq.b    .unlock        ;no message ?
  869.     movea.l    d0,a1        ;IOB
  870.     exg    a5,a6        ;put the device pointer in right register
  871.     bsr    PerformIO
  872.     PUTDEBUG 100,<'Unit Task --- returned from PerformIO'>
  873.     exg    a5,a6        ;get exec back in A6
  874.     bra.b    .nextMessage
  875.  
  876. *******************************************************************************
  877.  
  878. UnitInitStruct:
  879.     INITBYTE LH_TYPE,NT_DEVICE
  880.     INITBYTE LIB_FLAGS,LIBF_CHANGED
  881.     INITWORD LIB_VERSION,PVERSION
  882.     INITWORD LIB_REVISION,PREVISION
  883.     INITBYTE pdu_is+LN_TYPE,NT_INTERRUPT
  884.     dc.l     0
  885.  
  886. ;------------------------------------------------------------------------------
  887. ;EndCode is a marker that shows the end of your code.  Make sure that it
  888. ;does not span sections nor is before the rom tag in memory!  It is ok to
  889. ;put it right after the rom tag -- that way you are always safe.  I put it
  890. ;here because it is the right thing to do, and i know that it is safe in
  891. ;this case    
  892. ;------------------------------------------------------------------------------
  893.  
  894.     ISDEBUG    'eightbit'
  895.  
  896. EndCode:
  897.  
  898. *******************************************************************************
  899.  
  900.     end
  901.