LIBRARY.TXT Advanced Communication Board Developer's Toolkit 1995 ---------------------------------------------------------------------- ---------------------------------------------------------------------- This document is organized with the following conventions: Section 1.0 Introduction Section 2.0 Advanced Communication Board I/O Routines 2.1 SCCin 2.2 SCCout 2.3 SCCInit 2.4 SCCInitEx Section 3.0 Interrupt Driven Programming Routines 3.1 SaveIRQMask 3.2 ReturnIRQMask 3.3 IRQSetup 3.4 IRQSetupEx 3.5 IRQUnsetup Section 4.0 Direct Memory Access (DMA) Routines 4.1 MaskDMA 4.2 SingleMaskDMA 4.3 SetTC 4.4 GetTC 4.5 SetDMAMode 4.6 SetPageRegister 4.7 SetPageRegisterEx 4.8 CheckDMAPage 4.8 CheckDMAPageEx Section 5.0 Buffer(BUFFER) Routines 5.1 AddBuffer 5.2 StartBuffer 5.3 AssignBuffer 5.4 ReleaseBuffer 5.5 SwapBuffer 5.6 EraseBuffer Section 6.0 Misc. Header Files ---------------------------------------------------------------------- ---------------------------------------------------------------------- Section 1.0 Introduction This file contains information regarding the library files that are used throughout the ACB Developers Toolkit. The following is a description and example of each routine. Please refer to the sample code for working demos. All routines can be compiled using Microsoft C v1 (or higher) or Borland Turbo C v1 (or higher). Object files are not provided. All routines are callable from C, C++, or MASM. When using the INVOKE directive in MASM, avoid passing arguments with AL or AX. INVOKE uses AX and AL to push values on the stack. Failing to do this may cause parameters to be overwritten. ---------------------------------------------------------------------- ---------------------------------------------------------------------- Section 2.0 Advanced Communication Board I/O Routines This section is devoted to I/O routines that read and write to the 85x30 on all Advanced Communication Boards. The source file is ACB.C. These routines are not required to program the ACB cards. These routines are provided to aid the programmer in building quick and reliable applications and device drivers. NOTE: See Zilog 8530 Technical Manual for details on register bit definitions. ---------------------------------------------------------------------- Section 2.1 SCCin SYNTAX: void SCCin(unsigned short wDATAPORT, unsigned char bREG); PURPOSE: Reads value from selected 85x30 register PASSES: wDATAPORT - ACB Data Port Address bREG - 85x30 register to be programmed RETURNS: Value read from register - unsigned char (AL) C EXAMPLE: #include "acb.h" #define PORT 0x300 /*data port on ACB card unsigned char x; . . x=SCCin(PORT,2); /* x=value read from register 2 */ ---------------------------------------------------------------------- Section 2.2 SCCout SYNTAX: void SCCout( unsigned short wDATAPORT, unsigned char bREG, unsigned char bVALUE); PURPOSE: Writes value to selected 8530 register PASSES: wDATAPORT - ACB Data Port Address bREG - 8530 register to be programmed bVALUE - Value to be written to register RETURNS: Nothing C EXAMPLE: #include "acb.h" #define PORT 0x300 /* data port on ACB card */ . . SCCout(PORT,02,0x55); /* write 55 hex to register 2 */ ---------------------------------------------------------------------- Section 2.3 SCCInit SYNTAX: void SCCInit( unsigned short wDATAPORT, unsigned char *wOFFSET1, unsigned char *wOFFSET2); PURPOSE: Initialize 8530 with values in initialization array PASSES: wDATAPORT - ACB Data Port Address wOFFSET1 - Starting address of init array wOFFSET2 - Ending address of init array RETURNS: Nothing C EXAMPLE: #include "acb.h" #define PORT 0x300 /*data port on ACB card */ unsigned char init_array[10]={1,2, /* write register 1=2 */ 3,4, /* write register 3=4 */ 5,6, /* write register 5=6 */ 7,8 /* write register 7=8 */ 9,10};/* write register 9=10 */ . . SCCInit(PORT,&init_array[0],&init_array[9]); ---------------------------------------------------------------------- Section 2.4 SCCInitEx SYNTAX: void SCCInitEx( unsigned short wDATAPORT, unsigned char __far *fpARRAY, unsigned short wLENGTH); PURPOSE: Initialize 8530 with values in initialization array PASSES: wDATAPORT - ACB Data Port Address fpARRAY - Far pointer to initialization array. wLENGTH - Length of init array. RETURNS: Nothing C EXAMPLE: #include "acb.h" #define PORT 0x300 /*data port on ACB card */ void __far *pointer unsigned char init_array[10]={1,2, /* write register 1=2 */ 3,4, /* write register 3=4 */ 5,6, /* write register 5=6 */ 7,8 /* write register 7=8 */ 9,10};/* write register 9=10 */ . . pointer= init_array[]; SCCInitEx(PORT,pointer,10); ---------------------------------------------------------------------- ---------------------------------------------------------------------- Section 3.0 Interrupt Driven Programming Routines This section is devoted to I/O routines that simplify the process of interrupt driven programming initialization. These routines are not required to program the ACB cards, but are provided to encapsulate the bit manipulation involved in programming the two 8259 Programmable Interrupt Controllers (PIC) on the AT system board. These routines rely on only two variables, the IRQ selected on the ACB card and the address of the Interrupt Service Routine. This will allow only one variable to be changed, when the IRQ on the ACB card is changed (i.e. now you do not have to keep up with the vector number, PIC bit mask and which PIC you are programming). The source file is INT.C. Again, these routines are not required to program the ACB cards. These routines are provided to aid the programmer in creating flexible applications and device drivers that can be used on a variety of system resources. ---------------------------------------------------------------------- Section 3.1 SaveIRQMask SYNTAX: void SaveIRQMask(void); PURPOSE: Saves current 8259 interrupt controllers mask PASSES: Nothing RETURNS: Nothing C EXAMPLE: #include "irq.h" . SaveIRQMask(); NOTE: This routine saves the current mask that is programmed to the interrupt controller (8259). This routine should be called before any other interrupt specific function is called. ---------------------------------------------------------------------- Section 3.2 ReturnIRQMask SYNTAX: void ReturnIRQMask(void); PURPOSE: Restores 8259 interrupt controller mask that was saved in the SaveIRQMask routine. PASSES: Nothing RETURNS: Nothing C EXAMPLE: #include "irq.h" . ReturnIRQMask(); NOTE: This routine is the compliment to SaveIRQMask and should be the last interrupt specific function called. ReturnIRQMask, when used with SaveIRQMask, will return the interrupt controller to its original programmed state. ---------------------------------------------------------------------- Section 3.3 IRQSetup SYNTAX: void IRQSetup( unsigned char bIRQ, unsigned short wSEGMENT, unsigned short wOFFSET); PURPOSE: Replaces unused interrupt vector with new Interrupt Service Routine address, saves old vector for replacement at a later time. Removes IRQ mask on 8259 interrupt controllers for corresponding interrupt. PASSES: bIRQ - IRQ-unsigned char [2-15] wSEGMENT - Segment of new Interrupt Service Routine (unsigned short) wOFFSET - Offset of new Interrupt Service Routine (unsigned short) RETURNS: Nothing C EXAMPLE: #include "irq.h" #define IRQ 15 /* any IRQ 2-15 */ void __far *pointer unsigned short seg1, off1; . . pointer=isr; seg1=_FP_SEG(pointer); /* get segment */ off1=_FP_OFF(pointer); /* get offset */ IRQSetup(IRQ,seg1,off1); . . void __cdecl __interrupt __far isr(void) { if (IRQ>7) /* XT or AT interrupts? */ outp(0xA0,0x20) /* EOI to AT 8259 controller */ outp(0x20,0x20) /* EOI to XT 8259 controller */ } NOTE: This routine will program the interrupt controller for the desired interrupt and set/save the appropriate interrupt vectors. This routine is used with IRQUnsetup. IRQSetup should be called only once before IRQUnsetup is called. ---------------------------------------------------------------------- Section 3.4 IRQSetupEx SYNTAX: void IRQSetupEx(unsigned char bIRQ, void __far *fpISR); PURPOSE: Replaces unused interrupt vector with new Interrupt Service Routine address, saves old vector for replacement at a later time. Removes IRQ mask on 8259 interrupt controllers for corresponding interrupt. PASSES: bIRQ - IRQ-unsigned char [2-15] fpBUFFER - Far pointer to Interrupt Service Routine (ISR) RETURNS: Nothing C EXAMPLE: #include "irq.h" #define IRQ 15 /* any IRQ 2-15 */ void __far *pointer . . pointer=isr; IRQSetup(IRQ,pointer); . . void __cdecl __interrupt __far isr(void) { if (IRQ>7) /*XT or AT interrupts? */ outp(0xA0,0x20) /* EOI to AT 8259 controller */ outp(0x20,0x20) /* EOI to XT 8259 controller */ } NOTE: See note for IRQSetup. ---------------------------------------------------------------------- Section 3.5 IRQUnsetup SYNTAX: void IRQUnsetup(unsigned char bIRQ); PURPOSE: Replaces vector that was saved in IRQSetup. Masks IRQ on 8259 interrupt controller. PASSES: bIRQ - selected Interrupt Request (IRQ) Valid IRQ are 2-15. RETURNS: Nothing C EXAMPLE: #include "irq.h" #define IRQ 15 /* IRQ 15 */ . . IRQUnsetup(IRQ); /* remove mask and vector */ NOTE: This routine is used with IRQSetup. ---------------------------------------------------------------------- ---------------------------------------------------------------------- Section 4.0 Direct Memory Access (DMA) Routines This section is devoted to I/O routines that simplify the process of DMA initialization. These routines are not required to program the ACB cards but are provided to encapsulate the bit manipulation involved in programming the 8237 Programmable Direct Memory Access Controllers (DMA) on the system board. Again, these routines are not required to program the ACB cards. These routines are provided to aid the programmer in creating flexible applications and device drivers that can be used on a variety of system resources. ---------------------------------------------------------------------- Section 4.1 MaskDMA SYNTAX: void MaskDMA(unsigned char bDMAMASK); PURPOSE: Masks / unmasks selected DMA channels PASSES: Value to be written to DMA mask register (unsigned char) RETURNS: Nothing C EXAMPLE: #include "dma.h" . /* set bit D1 */ MaskDMA(0x02); /* mask DMA channel 1 */ . MaskDMA(0x00); /* unmask all DMA channels */ NOTE: Bits D0-D3 in the value written to the Mask Register correspond to DMA channels 0 - 3. When a bit is set (1), the corresponding DMA channel is off. A zero will turn the DMA channel on. It is possible to mask two channels at the same time (HEX 0A will turn channel 1 and 3 off). Use caution when programming to insure that DMA channels that you are not using do not get masked. DMA channels should be masked (turned off) before the terminal count or page/address registers are programmed. Once the DMA transfer is properly programmed, the DMA channel is unmasked (on) and the DMA transfer will begin. ---------------------------------------------------------------------- Section 4.2 SingleMaskDMA SYNTAX: void SingleMaskDMA(unsigned char bVALUE); PURPOSE: Selectively mask or unmask a DMA channel. PASSES: bVALUE - DMA Single Mask Commands. Valid commands are: SETDMA0 CLEARDMA0 SETDMA1 CLEARDMA1 SETDMA2 CLEARDMA2 SETDMA3 CLEARDMA3 RETURNS: Nothing C EXAMPLE: #include "dma.h" . SingleMaskDMA(SETDMA1); /* disable DMA channel 1 */ . . SingleMaskDMA(CLEARDMA1); /* enable DMA channel 1 */ NOTE: ---------------------------------------------------------------------- Section 4.3 SetTC SYNTAX: void SetTC(unsigned short wDMASEL, unsigned short wTC); PURPOSE: Sets terminal count register for selected DMA channel. this value determines the number of bytes to be transferred PASSES: wDMASEL - DMA channel selection. Valid DMA channel selectors: DMA0 - selects DMA channel 0 DMA1 - selects DMA channel 1 DMA2 - selects DMA channel 2 DMA3 - selects DMA channel 3 wTC - Number of bytes to transfer - 1 RETURNS: Nothing C EXAMPLE: #include "dma.h" . /* DMA channel 3 */ SetTC(DMA3,45); /* set transfer for 46 bytes */ NOTE: The value that is programmed to the terminal count register is one less than the number of bytes transferred. Terminal count is reached when the value read in GetTC is FFFF HEX. ---------------------------------------------------------------------- Section 4.4 GetTC SYNTAX: unsigned short GetTC(unsigned short wDMASEL); PURPOSE: Reads terminal count register for selected DMA channel PASSES: wDMASEL - DMA channel selection. Valid DMA channel selectors: DMA0 - selects DMA channel 0 DMA1 - selects DMA channel 1 DMA2 - selects DMA channel 2 DMA3 - selects DMA channel 3 RETURNS: Number Of Bytes Remaining In DMA transfer -1 (unsigned short) C EXAMPLE: #include "dma.h" unsigned short a; . a=GetTC(DMA1); /* get terminal count for DMA 1 */ NOTE: The DMA transfer is completed when the terminal count equals 65535 (FFFF HEX). The terminal count will count down to zero from the value that was programmed using SetTC and roll over to FFFF HEX when the last byte was transferred. ---------------------------------------------------------------------- Section 4.5 SetDMAMode SYNTAX: void SetDMAMode(unsigned char bDMAMODE); PURPOSE: Sets DMA transfer mode PASSES: bDMAMODE - DMA mode selector. Valid DMA Mode Selectors: TX0 - Transmit on DMA channel 0 RX0 - Receive on DMA channel 0 TX1 - Transmit on DMA channel 1 RX1 - Receive on DMA channel 1 TX2 - Transmit on DMA channel 2 RX2 - Receive on DMA channel 2 TX3 - Transmit on DMA channel 3 RX3 - Receive on DMA channel 3 RETURNS: Nothing C EXAMPLE: #include "dma.h" . SetDMAMode(TX1); NOTE: This function is used with SetPageRegister to program the DMA controller (8237). ---------------------------------------------------------------------- Section 4.6 SetPageRegister SYNTAX: void SetPageRegister( unsigned short wDMASEL , unsigned short wSEGMENT, unsigned short wOFFSET); PURPOSE: Sets address and page register for DMA transfer using segment/offset. PASSES: wDMASEL - DMA channel selection. Valid DMA channel selectors: DMA0 - selects DMA channel 0 DMA1 - selects DMA channel 1 DMA2 - selects DMA channel 2 DMA3 - selects DMA channel 3 wSEGMENT - DMA Buffer Segment wOFFSET - DMA Buffer Offset RETURNS: Nothing C EXAMPLE: #include "dma.h" void __far *pointer unsigned short seg1, off1; unsigned char buffer[45]; /* buffer is 45 bytes long */ . . pointer=buffer[]; seg1=_FP_SEG(pointer); /* get segment */ off1=_FP_OFF(pointer); /* get offset */ SetPageRegister(DMA1,seg1,off1); . /* sets address and page . register for DMA channel 1 */ NOTE: This function is used with SetDMAMode. The transmit or receive buffer adders is written to the DMA controller. The type of transfer (transmit or receive) is determined using SetDMAMode. See SetPageRegisterEx. ---------------------------------------------------------------------- Section 4.7 SetPageRegisterEx SYNTAX: void SetPageRegisterEx( unsigned short wDMASEL, unsigned char __far *fpBUFFER); PURPOSE: Sets address and page register for DMA transfer using a far pointer. PASSES: wDMASEL - DMA channel selection. Valid DMA channel selectors: DMA0 - selects DMA channel 0 DMA1 - selects DMA channel 1 DMA2 - selects DMA channel 2 DMA3 - selects DMA channel 3 fpBUFFER - Far pointer to DMA buffer RETURNS: Nothing C EXAMPLE: #include "dma.h" void __far *pointer unsigned char buffer[45]; /* buffer is 45 bytes long */ . . pointer=buffer[]; SetPageRegisterEx(DMA1, pointer); . /* sets address and page . register for DMA channel 1 */ NOTE: See SetPageRegister ---------------------------------------------------------------------- Section 4.8 CheckDMAPage SYNTAX: int CheckDMAPage( unsigned short wTC, unsigned short wSEGMENT, unsigned short wOFFSET); PURPOSE: Check for valid DMA buffer address (i.e. not residing on a 64K boundary). This routine is passed the Segment and Offset. PASSES: wTC - Terminal Count (Buffer Size + 1) wSEGMENT - Segment of Buffer wOFFSET - Offset of Buffer RETURNS: Zero if DMA Buffer OK, otherwise non Zero C EXAMPLE: #include "dma.h" void __far *pointer unsigned short seg1, off1; unsigned char buffer[45]; /* buffer is 45 bytes long */ . . pointer=buffer[]; seg1=_FP_SEG(pointer); /* get segment */ off1=_FP_OFF(pointer); /* get offset */ CheckDMAPage(45,seg1, off1); . /* sets address and page . register for DMA channel 1 */ NOTE: See CheckDMAPageEx ---------------------------------------------------------------------- Section 4.9 CheckDMAPageEx SYNTAX: int CheckDMAPageEx( unsigned short wTC, unsigned char __far *fpBUFFER); PURPOSE: Check for valid DMA buffer address (i.e. not residing on a 64K boundary). This routine is passed a far buffer pointer. PASSES: wTC - Terminal Count (Buffer Size + 1) fpBUFFER - Far pointer to DMA buffer. RETURNS: Zero if DMA Buffer OK, otherwise non Zero C EXAMPLE: #include "dma.h" void __far *pointer unsigned char buffer[45]; /* buffer is 45 bytes long */ . . pointer=buffer[]; CheckDMAPage(45 ,pointer); . /* checks address and page . register for DMA channel 1 */ NOTE: See CheckDMAPage ---------------------------------------------------------------------- ---------------------------------------------------------------------- Section 5.0 Buffer (BUFFER) Routines This section is devoted to the routines that simplify the process of setting up chained buffers. These routines are not required to program the ACB cards but are provided to encapsulate the buffer manipulation. Again, these routines are not required to program the ACB cards. These routines are provided to aid the programmer in creating flexible applications and device drivers that can be used on a variety of system resources. ---------------------------------------------------------------------- Section 5.1 AddBuffer SYNTAX: void AddBuffer( fpDEVICE_INFO fpDeviceInfo, npBUFFER_INFO npBufferInfo, unsigned char __far * fpBuffer) PURPOSE: If the buffer is the first in the chain, save the near pointer to the first BUFFER_INFO struct, set npNext_RED, npNext_GREEN, npNextBuffer and npCurrent to the first buffer address. If the BUFFER_INFO struct is NOT the first, npNextBuffer is set to the last buffer added and npCurrent is set to the current buffer. PASSES: fpDeviceInfo - far pointer to the device info structure npBufferInfo - near pointer to the buffer info structure fpBuffer - far pointer to the buffer RETURNS: Nothing C EXAMPLE: #include "buffer.h" . fpMemoryBlock = _fmalloc(MEMORY_REQUESTED); . fpMemory = fpMemoryBlock; TxDevice.wTotal = 0; TxDevPtr = &TxDevice; for (i = 0; i < MAX_BUFFERS; i++) { AddBuffer( TxDevPtr, &TxBuffer[i] ,fpMemory); fpMemory = (unsigned char __far* ) (fpMemory + BUFFER_LENGTH); } NOTE: ---------------------------------------------------------------------- Section 5.2 StartBuffer SYNTAX: unsigned short StartBuffer( fpDEVICE_INFO fpDeviceInfo, unsigned char bDeviceType) PURPOSE: Set up the device info dependent upon type. PASSES: fpDeviceInfo - far pointer to the device info structure bDeviceType - device type; valid types are: INPUT_DEVICE OUTPUT_DEVICE RETURNS: Status of device as stopped. C EXAMPLE: #include "buffer.h" . fpMemoryBlock = _fmalloc(MEMORY_REQUESTED); . fpMemory = fpMemoryBlock; TxDevice.wTotal = 0; TxDevPtr = &TxDevice; for (i = 0; i < MAX_BUFFERS; i++) { AddBuffer( TxDevPtr, &TxBuffer[i] ,fpMemory); fpMemory = (unsigned char __far* ) (fpMemory + BUFFER_LENGTH); } . StartBuffer( TxDevPtr, OUTPUT_DEVICE); NOTE: ---------------------------------------------------------------------- Section 5.3 AssignBuffer SYNTAX: unsigned char __far * AssignBuffer( fpDEVICE_INFO fpDeviceInfo) PURPOSE: This routine will wait for a GREEN buffer to become available (until time out), then makes the current buffer pointer point to the next GREEN buffer, then the next GREEN pointer is advanced to the next buffer in the ring. IF wNumRed < wTotalBuffers THEN npCurrent = npNext_GREEN npNext_GREEN = Next Buffer in the Ring ELSE Repeat IF unitl Time-Out PASSES: fpDeviceInfo - far pointer to device info structure RETURNS: Address of Next Available Buffer to process C EXAMPLE: #include "buffer.h" . unsigned char __far * fpTemp; fpTemp = AssignBuffer(TxDevPtr); if(fpTemp == NULL) { return(0); /* queue is full*/ } else { < perform processing> } NOTE: ---------------------------------------------------------------------- Section 5.4 ReleaseBuffer SYNTAX: unsigned short ReleaseBuffer( fpDEVICE_INFO fpDeviceInfo) PURPOSE: This routine will increment the number of red buffers. Then check to see if I/O is busy. If yes, device is OK, else device needs to be restarted. PASSES: fpDeviceInfo - far pointer to device info structure RETURNS: Status of device (Stopped or OK). C EXAMPLE: #include "buffer.h" . unsigned char __far * fpTemp; . _fmemmove(fpTemp, TxFrame, wLength); /*move the frame into our queue*/ TxDevPtr->npCurrent->wByteCount = wLength; if (BM_DEVICE_STOPPED == ReleaseBuffer(TxDevPtr)) /*if Tx is idle,*/ { RestartTx++; /*restart the transmitter*/ } NOTE: ---------------------------------------------------------------------- Section 5.5 SwapBuffer SYNTAX: unsigned short SwapBuffer( fpDEVICE_INFO fpDeviceInfo) PURPOSE: This routine will wait for a RED buffer to become available (until time out), then updates the pointer for the buffer. PASSES: fpDeviceInfo - far pointer to device info structure RETURNS: Status of device (Stopped or OK). C EXAMPLE: #include "buffer.h" . if (SwapBuffer(TxDevPtr)== BM_STOP_IO) { return; } else { } NOTE: This routine is called from Interrupt Service Routine (ISR). ---------------------------------------------------------------------- Section 5.6 EraseBuffer SYNTAX: void EraseBuffers( fpDEVICE_INFO fpDeviceInfo) PURPOSE: Clears the device info structure. PASSES: fpDeviceInfo - far pointer to device info structure RETURNS: Nothing C EXAMPLE: #include "buffer.h" . . EraseBuffer(TxDevPtr); . NOTE: ---------------------------------------------------------------------- Section 6.0 Misc. Header Files Z8530.H Defines all Z8530 SCC bit definitions including Z85C30 and Z85230 Note: Text definitions "Z85C30" and "Z85230" must be defined to used CMOS SCC and ESCC defines. ASCII.H Control Character #defines for BISYNC mode communications. EBCDIC.H Control Character #defines for BISYNC mode communications. ---------------------------------------------------------------------- ----------------------------------------------------------------------