title NAME.LDD device driver for S3/S3a/S3c/S3../HC subttl Copyright PSION PLC November 1995 name NAME ; VERSION DATE DESCRIPTION ; ------- -------- --------------- ; 1.0 12/01/95 Template Asic4/5 LDD ; Written by Jason Robinson January 1995 BUILDSB equ 1 Asic4Type =0 Asic5Type =0 NeedTheInterrupt =0 NeedClocking =0 StartChannelInOpen =0 include ..\inc\epoc.inc include ..\inc\epocser.inc include ..\inc\epoclib.inc include ..\inc\epocsibo.inc include ..\srcs\ossibo.inc include ..\srcs\ospack.inc WeSupportS3Only equ Lcd240X80 WeSupportS3aOnly equ Lcd480X160 WeSupportS3cOnly equ Lcd240X100 WeSupportHCOnly equ Lcd160X80 if Consumer NumberOfChannels equ 1 if Asic9 TheMachineWeSupport equ WeSupportS3aOnly else TheMachineWeSupport equ WeSupportS3Only endif else NumberOfChannels equ 3 if Asic9 TheMachineWeSupport equ WeSupportS3cOnly else TheMachineWeSupport equ WeSupportHCOnly endif endif A4PERIPH_MASK equ 0f0h TheInfoByteThatWeWant equ 1 TmpltEnt struc TmpltEntOpen db ? ; Channel open flag TmpltChannelStarted db ? ; Channel should be running TmpltHwChannel dw ? ; The harware we want TmpltStructPtr dw ? ; Ptr to CB in Apps DS TmpltTckHandle dw ? ; Tick Handle TmpltChannelRunning db ? ; Can channel really run TmpltInterruptMask db ? ; InterruptMask TmpltChannel db ? ; Channel if NeedTheInterrupt TmpltInterruptNumber db ? ; Interrupt Number TmpltInterruptVector dw ? ; Were to Jump To if Asic5Type and NeedClocking TmpltA5Clocking db ? ; Asic5 baud rate clocking TmpltSpare db ? endif else TmpltSpare db ? endif TmpltEnt ends TmpltStruct struc Tmpltblk ChanEnt <> ; I/O control block TmpltEntPtr dw ? ; Ptr to our CS CB TmpltStruct ends dgroup group stack assume ds:dgroup,es:dgroup,ss:dgroup CodeSeg ProcBegin@ TmpltLDD ; =================== dw LDDSignature db 'HSB',0,0,0,0,0 dw (TableEnd-TableStart)/2 TableStart: dw TmpltInstall dw TmpltRemove dw TmpltHold dw TmpltResume dw TmpltReset dw TmpltUnits dw TmpltOpen dw TmpltStrategy MonitorVector: dw MonitorInt TableEnd: if Consumer if Asic9 SetupTable db mask A9MSlave,SelectChannel5 db (mask A9MClockEnable5 shr 8),HwIrq2Revector if NeedTheInterrupt dw offset Interrupt0 endif else SetupTable db mask Asic2Int,SelectChannel7 db (mask ClockEnable7 shr 8),HwIrq4Revector if NeedTheInterrupt dw offset Interrupt0 endif endif else if Asic9 SetupTable db mask A9MExpIntA,SelectChannel3 db (mask A9MClockEnable3 shr 8),HwIrq4Revector if NeedTheInterrupt dw offset Interrupt0 endif db mask A9MExpIntB,SelectChannel4 db (mask A9MClockEnable4 shr 8),HwIrq5Revector if NeedTheInterrupt dw offset Interrupt1 endif db mask A9MSlave,SelectChannel5 db (mask A9MClockEnable5 shr 8),HwIrq2Revector if NeedTheInterrupt dw offset Interrupt2 endif else SetupTable db mask ExpIntLeftA,ExpChannelLeftA db (mask ClockEnable6 shr 8),HwIrq3Revector if NeedTheInterrupt dw offset Interrupt0 endif db mask ExpIntRightB,ExpChannelRightB db (mask ClockEnable5 shr 8),HwIrq2Revector if NeedTheInterrupt dw offset Interrupt1 endif db mask Asic2Int,SelectChannel7 db (mask ClockEnable7 shr 8),HwIrq4Revector if NeedTheInterrupt dw offset Interrupt2 endif endif endif CsHeldFlag db 0 ; Ldd under a hold? MachineType db 0 if Consumer Channel0 TmpltEnt <> else Channel0 TmpltEnt <> Channel1 TmpltEnt <> Channel2 TmpltEnt <> endif ProcEnd noret ProcBegin@ TmpltInstall,far ; =========================== ; Install the driver ; Exit with carry clear for okay GenLcdType ; Do we only run on mov MachineType,al ; particular machines? cmp al,TheMachineWeSupport jne CannotInstallOnThisMachine pushf cli push ds mov ax, cs mov ds, ax mov CsHeldFlag, 0 ; Initialise all mov cx, NumberOfChannels ; the variables mov di, offset Channel0 mov si, offset SetupTable ResetAllChannelsLoop: mov [di].TmpltEntOpen, 0 lodsb mov [di].TmpltInterruptMask, al lodsb mov [di].TmpltChannel, al lodsb if NeedClocking mov [di].TmpltA5Clocking, al endif lodsb if NeedTheInterrupt mov [di].TmpltInterruptNumber, al lodsw mov [di].TmpltInterruptVector, ax endif add di,size TmpltEnt loop ResetAllChannelsLoop pop ds popf FinishedOkay: clc ret CannotInstallOnThisMachine: mov ax,NotSupportedErr stc ret ProcEnd noret ProcBegin@ TmpltRemove,far ; ========================== ; Remove the driver ; Exit with carry clear for okay ; Exit with carry set if channel still open mov cx,NumberOfChannels mov di,offset Channel0 xor ax,ax CheckAllChannelsClosedLoop: cmp cs:[di].TmpltEntOpen,al jne WeHaveAnOpenChannelSoFail add di,size TmpltEnt loop CheckAllChannelsClosedLoop jmp FinishedOkay WeHaveAnOpenChannelSoFail: mov ax,InUseErr stc ret ProcEnd noret ProcBegin@ TmpltUnits,far ; ========================= ; Return the Number of channels that can be opened in AX mov ax,NumberOfChannels ; We have ? channels ret ProcEnd noret ProcBegin@ TmpltReset,far ; ========================= ; Reset the open channel mov di,cx cmp cs:[di].TmpltEntOpen,0 ; Somethings gone je NotOpenToReset ; wrong with the mov ah,DevHoldPowerDown ; application that call StopTheChannel ; opened us. call FreeHardware ; Stop interupts and mov cs:[di].TmpltEntOpen,0 ; free the channel NotOpenToReset: ret ProcEnd noret ProcBegin@ TmpltHold,far ; ======================== ; Hold the channels ; Hold reason in AH mov cx,1 xchg cl,CsHeldFlag ; Stop any interrupts cmp cl,0 ; Mark channel as jne AlreadyHeld ; under a normal hold DoHold: mov cx,NumberOfChannels mov di,offset Channel0 HoldAllTheChannelsLoop: cmp cs:[di].TmpltEntOpen,0 je DontHoldBecauseNotOpen cmp cs:[di].TmpltChannelStarted,0 je DontHoldBecauseNotOpen push ax push cx call StopTheChannel pop cx pop ax DontHoldBecauseNotOpen: add di,size TmpltEnt loop HoldAllTheChannelsLoop AlreadyHeld: ret ProcEnd noret ProcBegin@ TmpltResume,far ; ========================== ; Resume the channel xor cx,cx ; Be warned during an xchg cl,CsHeldFlag ; on/off the power to cmp cl,0 ; ASIC4 is not restored je AlreadyResumed ; until after this GenDataSegment ; A resume is pointless HwGetSsdData ; if there is still no mov bx,ax ; power to the port cmp es:[bx].SsdDoorStatus,DoorOpen ; Leave the resume je DoorsAreOpen ; to the tick DoResume: mov cx,NumberOfChannels mov di,offset Channel0 ; Right hardware? ResumeAllTheChannelsLoop: ; Else restart cmp cs:[di].TmpltEntOpen,0 ; interrupts je DontResumeBecauseNotOpen cmp cs:[di].TmpltChannelStarted,0 je DontResumeBecauseNotOpen push cx call StartTheChannel pop cx DontResumeBecauseNotOpen: add di,size TmpltEnt loop ResumeAllTheChannelsLoop AlreadyResumed: ret DoorsAreOpen: mov CsHeldFlag,2 ret ProcEnd noret ProcBegin@ TmpltOpen,far ; ======================== ; Open the channel ; DS,ES,SS Applications data space ; Handle in DX cld pushf cli call FindFreeChannel jnc GotFreeChannel popf LockedError: mov ax,LockedErr stc ret AllErrorsExitHere: push ax HeapFreeCell pop ax FreeTckAndChannel: push ax call FreeHardware pop ax FreeTckAndExit: push ax mov bx,cs:[di].TmpltTckHandle IoClose pop ax CloseThenFree: mov cs:[di].TmpltEntOpen,0 stc ret GotFreeChannel: mov cs:[di].TmpltEntOpen,1 mov cs:[di].TmpltChannelStarted,0 mov cs:[di].TmpltChannelRunning,0 popf xor ax,ax push ax mov ax,((':' shl 8)+'K') push ax mov ax,(('C' shl 8)+'T') push ax mov bx,sp IoOpen jnc GotATickChannel add sp,6 mov ax,LockedErr jmp CloseThenFree GotATickChannel: add sp,6 mov cs:[di].TmpltTckHandle,ax push dx mov bx,ax mov ax,IoFuncStart mov cx,1 push cx ; Frequency 1 tick push di ; Data is our CS CB push dx ; Our device handle mov cx,(MonitorVector-TableStart)/2 ; Vector to call push cx mov cx,sp IoWithWait add sp,8 pop dx call GetHardware jc FreeTckAndExit mov cx,(size TmpltStruct) ; Get ourselfs a CB HeapAllocateCell ; In the applications jc FreeTckAndChannel ; Data space mov bx,ax mov [bx].Tmpltblk.ChanNext,bx mov [bx].Tmpltblk.ChanSignature,IoChanSignature mov [bx].Tmpltblk.ChanLibHandle,dx mov [bx].TmpltEntPtr,di push bx mov bx,dx mov cx,di IoRequestReset pop bx if StartChannelInOpen call StartChannelFromOpen endif xor ax,ax ret ProcEnd noret StrategyVectorTable label word dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault dw offset TmpltClose dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault dw offset StrategyDefault ProcBegin@ TmpltStrategy,far ; ============================ ; BX is our control block ; SI points to the parameters ; DS,ES Applications data space mov ax,[si].RqFunction mov dx,[si].RqA1Ptr cmp ax,IoFuncSuperFrame ja StrategyDefault shl ax,1 mov di,ax push StrategyVectorTable[di] mov di,[bx].TmpltEntPtr retn StrategyDefault: IoRoot ret ExitStrategyOkay: xor ax,ax ExitStrategy: mov di,[si].RqStatusPtr mov word ptr [di],ax cmp ax,PendingErr je JustExit IoSignal JustExit: xor ax,ax ret ProcEnd noret ProcBegin@ TmpltClose,far ; ========================= ; Close a channel ; DI CS control block ; BX DS control block ; SI points to aurguments on stack ; DX Argument one pointer mov ah,DevHoldPowerDown call StopTheChannel call FreeHardware mov cs:[di].TmpltChannelStarted,0 push bx mov bx,[bx].Tmpltblk.ChanLibHandle mov cx,di IoRequestResetCancel pop bx HeapFreeCell mov bx,cs:[di].TmpltTckHandle IoClose mov cs:[di].TmpltEntOpen,0 jmp short ExitStrategyOkay ProcEnd noret ProcBegin@ StartTheChannel ; ========================== ; Start the Channel Running ; Assume channel set up and interrupts off cmp cs:[di].TmpltChannelRunning,0 jne ChannelAlreadyRunning if Asic5Type and NeedClocking if Asic9 in ax, A9WControlExtraRW ; Start the S3s clock or ah, [bx].TmpltA5Clocking ; Generator out A9WControlExtraRW, ax else mov al, [bx].TmpltA5Clocking HwSetA2Control2Bits endif endif if NeedTheInterrupt mov al, cs:[di].TmpltInterruptNumber ; Load the address of mov cx, cs ; the appropriate mov bx, cs:[di].TmpltInterruptVector ; interrupt routine GenSetRevector ; into the correct vector if Asic9 in al,A9BInterruptMaskRW ; Set the mask or al,cs:[di].TmpltInterruptMask ; to enable Interrupts out A9BInterruptMaskRW,al else in al, A1InterruptMask or al,cs:[di].TmpltInterruptMask out A1InterruptMask, al endif endif mov cs:[di].TmpltChannelRunning,1 ChannelAlreadyRunning: ret ProcEnd noret ProcBegin@ StopTheChannel ; ========================= ; Stop the Channel Running ; Assume channel set up and interrupts off ; Stop reason in AH cmp byte ptr cs:[di].TmpltChannelRunning,0 je ChannelAlreadyStopped if NeedTheInterrupt mov ah,cs:[di].TmpltInterruptMask not ah if Asic9 in al,A9BInterruptMaskRW ; Stop Interrupts and al,ah ; By clearing the out A9BInterruptMaskRW,al ; Mask and resetting else ; The Vector in al, A1InterruptMask and al,ah out A1InterruptMask, al endif mov al, cs:[di].TmpltInterruptNumber GenResetRevector endif if Asic5Type and NeedClocking if Asic9 mov cl, [bx].TmpltA5Clocking ; Turn off baud rate not cl ; clocking from the in ax, A9WControlExtraRW ; S3/3a and ah, cl out A9WControlExtraRW, ax else mov al, [bx].TmpltA5Clocking HwClearA2Control2Bits endif endif mov cs:[di].TmpltChannelRunning,0 ChannelAlreadyStopped: ret ProcEnd noret if StartChannelInOpen ProcBegin@ StartChannelFromOpen ; =============================== pushf cli mov cs:[di].TmpltChannelStarted,1 mov al,cs:[di].TmpltChannel HwSelectChannel push ax call StartTheChannel pop ax HwSelectChannel popf ret ProcEnd noret endif ProcBegin@ GetHardware ; ====================== mov al, cs:[di].TmpltInterruptMask HwGetChannel jc ChannelNotAvailable pushf cli mov al,cs:[di].TmpltChannel HwSelectChannel push ax call CheckForHardware pop ax jc NoHardwareFreeTheChannel HwSelectChannel popf clc ret NoHardwareFreeTheChannel: HwSelectChannel popf mov al, cs:[di].TmpltInterruptMask HwFreeChannel ChannelNotAvailable: stc ret ProcEnd noret ProcBegin@ FreeHardware ; ======================= mov al, cs:[di].TmpltInterruptMask HwFreeChannel ret ProcEnd noret ProcBegin@ FindFreeChannel ; ========================== mov si,[si].OpenNamePtr mov al,[si+1] CharToFoldedChar cmp al,'A' jb CantGetThatChannel sub al,'A' cmp al,NumberOfChannels jae CantGetThatChannel xor ah,ah push dx mov dx,size TmpltEnt mul dx pop dx mov di,ax add di,offset Channel0 cmp cs:[di].TmpltEntOpen,0 je FoundAFreeChannel CantGetThatChannel: stc ret FoundAFreeChannel: clc ret ProcEnd noret ProcBegin@ CheckForHardware ; =========================== ; Assume Interrupts are off ; Correct channel should be selected ; Out: clc - got correct hardware ; stc - wrong or no hardware if Asic5Type HwNullFrame ; Check that the mov al,(SerialSelect or Asic5NormalId) ; Harware is there SBUSY ; And that it is what SCONTOUT ; It should be XNOP ; First look for An SBUSY ; ASIC5 at the other SDATAIN ; End of the link test al,al je ConnectionFailed GotConnection: popf clc ret ConnectionFailed: mov al, SerialSelect or Asic4Id ; Asic4 Id SBUSY SCONTOUT XNOP SBUSY SDATAIN test al, al jne ConnectionFailedExit else HwNullFrame mov al,(SerialSelect or Asic4Id) SBUSY ; First look for An SCONTOUT ; ASIC4 at the other XNOP ; End of the link SBUSY SDATAIN test al, al je ConnectionFailed mov al,SerialReadSingle or A4InfoR ; Now see if we have SBUSY ; The right card SCONTOUT XNOP ; Allows the busy signal to come through for the wait SBUSY SDATAIN and al,A4PERIPH_MASK cmp al,TheInfoByteThatWeWant jne ConnectionFailedExit clc ret ConnectionFailed: mov al,(SerialSelect or Asic5NormalId) ; Select as an SBUSY ; Asic5 peripheral SCONTOUT XNOP SDATAIN test al,al jne ConnectionFailedExit endif mov al, SerialSelect or Asic8Id ; Modem chip Id SBUSY SCONTOUT XNOP SBUSY SDATAIN test al, al jne ConnectionFailedExit mov al, SerialSelect or Asic5PackId ; Asic5pack Id SBUSY SCONTOUT XNOP SBUSY SDATAIN ConnectionFailedExit: stc ret ProcEnd noret ProcBegin@ MonitorInt,far ; ========================= ; Called on every tick ; Issues pack door hold and resumes ; In: Door state in SI cmp si,DoorOpen je TheDoorIsOpenSoCantDoAnything cmp CsHeldFlag,2 je NeedToDoTheResume ret NeedToDoTheResume: mov CsHeldFlag,0 jmp DoResume TheDoorIsOpenSoCantDoAnything: cmp CsHeldFlag,0 jne DontNeedToHold mov CsHeldFlag,2 mov ah,DevHoldPowerFail jmp DoHold DontNeedToHold: ret ProcEnd noret if NeedTheInterrupt ife Consumer ProcBegin@ Interrupt2,far ; ========================= mov di,offset Channel2 mov ax,PortCActive jmp ComInt ProcEnd noret ProcBegin@ Interrupt1,far ; ========================= mov di,offset Channel1 mov ax,PortBActive jmp ComInt ProcEnd noret endif ProcBegin@ Interrupt0,far ; ========================= mov di,offset Channel0 mov ax,PortAActive ; FALLTHROUGH to ComInt ProcEnd noret ProcBegin@ ComInt,far ; ===================== if Asic9 out A9BNonSpecificEoiW,al else out A1NonSpecificEoi, al endif clc ret ProcEnd noret endif EndCodeSeg stack segment stack para 'data' stack ends end TmpltLDD