/* Copyright (C) Magna Carta Software, Inc. 1990. All Rights Reserved AST832.C -- Use the AST CC-832 "Async Cluster Adapter" with C Communications Toolkit. This code supports the use of one AST card in the PC bus. Call if you need to use two cards. To run the example "#define CCT_TEST 1" Usage Notes: 1) The card can be configured to either of its supported I/O addresses (0X1A0 or 0X2A0); 2) The card can be configured to any IRQ line supported by the card (2-7); 3) Call ast832_init() prior to calling u8250_init(); 4) Then treat the card as four separate ports. Call u8250_init() once for each port that you wish to initialize; 5) You must call u8250_init() for AST port 0, even if you do not use it (it is used to contain the interrupt information); 6) Call install_ipr() for each IPR that you wish to install. The default CCT IPRs may be used (or you may write your own). All 4 types of interrupts generated by the 8250 UART family are supported; 7) Call install_isr() to install ast832_isr() (THE DEFAULT ISRs WILL NOT WORK!); 8) The ISR (ast832_isr()) does implement 16550 FIFO support if you a) Use the CCT IPRs; b) Unplug the AST CC-832 NS16440s and plug in 16550As; 9) This module must be compiled with stack checking OFF; */ #include #include #include #include #if defined(__POWERC) #pragma warning -220 /* turn off POWERC pragma warning */ #pragma stackchk- /* turn off POWERC stack checking */ #elif defined(MSC) #pragma check_stack(off) /* turn off MSC stack checking */ #pragma loop_opt(off) /* turn off MSC intrinsics */ #elif defined(__WATCOMC__) #pragma off (check_stack); /* turn off WATCOM stack checking */ #endif /* MANIFEST CONSTANTS AND MACROS */ #define AST_BASE 0X2A0 /* base address of AST (0X1A0 or 0X2A0) */ /* FUNCTION PROTOTYPES */ short ast832_init(WORD base, WORD irq); /* AST INIT FUNCTION */ void INTERRUPT_ ast832_isr(void); /* AST ISR */ #if defined(CCT_TEST) void term(COMM_PORT *p); /* GLOBAL VARIABLES */ COMM_PORT aport[4]; BYTE rxbuf[2048]; /* RECEIVE BUFFER (ONE PER PORT IN USE) */ short ourport = 0; /* For the example, port to use (0-3) */ /* ------------------------ PROGRAM BEGINS HERE --------------------------- */ int main(void) { short ret, vers = 0; /* INITIALIZE THE AST CC-832 CARD. */ ret = ast832_init(AST_BASE, 2); if (ret) { printf("\nCannot initialize card!"); return (-1); } /* INITIALIZE ONE OR MORE OF THE PORTS ON THE CARD, JUST AS IF THEY ARE STANDARD PC SERIAL PORTS. */ u8250_init(&aport[0], AST_BASE, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); u8250_init(&aport[1], AST_BASE+8, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); u8250_init(&aport[2], AST_BASE+16, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); u8250_init(&aport[3], AST_BASE+24, 2400L, DATABITS8, PARITY_NONE, STOPBITS1); /* NEXT, CALL install_ipr() TO INSTALL THE DESIRED INTERRUPT PROCESSING ROUTINE(S) */ install_ipr(&aport[0], RECEIVE, NULL, rxbuf, sizeof(rxbuf)); /* FINALLY, INSTALL THE INTERRUPT SERVICE ROUTINE THAT IS CALLED WHEN AN INTERRUPT OCCURS AT THE AST CARD. THIS, IN TURN, CALLS THE "IPR" INSTALLED ABOVE. NOTE: THE SECOND PARAMETER IS THE IRQ LINE. USE IRQ2 THROUGH IRQ7. NOTE: THE ISR MUST BE INSTALLED ON PORT 0. */ install_isr(&aport[0], 2, ast832_isr); #if 0 printf("\nRBR=%#X", inp(base)); printf("\nIER=%#X", inp(base+1)); printf("\nIIR=%#X", inp(base+2)); printf("\nLCR=%#X", inp(base+3)); printf("\nMCR=%#X", inp(base+4)); printf("\nLSR=%#X", inp(base+5)); printf("\nMSR=%#X", inp(base+6)); printf("\nSCR=%#X\n", inp(base+7)); #endif printf("CCT-AST Version %d: Press Alt-M for a list of commands\n", vers); printf("Using AST CC-832 Port Number %d\n", ourport); term(&aport[ourport]); printf("\nEnd of CCT-AST %d\n", vers); #if 0 printf("\nRBR=%#X", inp(base)); printf("\nIER=%#X", inp(base+1)); printf("\nIIR=%#X", inp(base+2)); printf("\nLCR=%#X", inp(base+3)); printf("\nMCR=%#X", inp(base+4)); printf("\nLSR=%#X", inp(base+5)); printf("\nMSR=%#X", inp(base+6)); printf("\nSCR=%#X\n", inp(base+7)); #endif return (0); } #endif /* AST832_INIT -- Initialize the AST CC-832 "Async Cluster Adapter". Parameters: WORD base -- base address of ports (must be 0X1A0 or 0X2A0); WORD irq -- IRQ line (must be >=2 and <= 7); Return Value: EOF -- invalid base address; -2 -- invalid IRQ line; */ short ast832_init(WORD base, WORD irq) { short temp; if (base != 0X1A0 && base != 0X2A0) return (EOF); if (irq < 2 || irq > 7) return (-2); outp(0X2F0+irq, 0XFF); /* clear IRQ channel */ outp(base+0X1F, 0X80); /* enable interrupts on channels 3&4 */ /* CLEAR PENDING UART INTERRUPTS */ for (temp = base; temp < base + 32; temp += 8) { do { inp(temp+5); /* clear LS INT */ inp(temp); /* clear RX INT */ inp(temp+6); /* clear MS INT */ } while (!(inp(temp+2) & 1)); /* clear pending */ } outp(0X2F0+irq, 0XFF); /* clear IRQ channel */ outp(base+0X1F, 0X80); /* enable interrupts on channels 3&4 */ return (0); } #define RX_ONLY 0 /* AST832_ISR -- AST CC-832 "Async Cluster Adapter" interrupt handler. */ void INTERRUPT_ ast832_isr(void) { /* DECLARE VARIABLES AS STATIC TO AVOID USING THE ISR STACK */ #if RX_ONLY static BYTE c; static volatile BYTE FAR_ *b_ptr; #endif static BYTE status, iir; static COMM_PORT FAR_ *p; static WORD i; enable(); status = inp(AST_BASE+0X1F) & 0XF; /* read AST status port (0X1BF or 0X2BF) */ /* SERVICE EACH TYPE OF INTERRUPT ON EACH PORT */ for (i=0; i < 4; i++) { if (!(status & (1 << i))) { if ((p = mcport[i]) == NULL) continue; iir = inp(p->uart.u8250.iir_addr); #if !RX_ONLY if (!(iir & 1)) (* (void ((FAR_ *)(COMM_PORT FAR_ *))) p->a_ipr[(iir &= 7) >> 1])(p); #else c = (BYTE) inp(p->ubase_addr); b_ptr = p->rxbufhead + 1; if (b_ptr == &rxbuf[2048]) b_ptr = p->rxbuf; if (!(b_ptr == p->rxbuftail)) { /* buffer is full */ *p->rxbufhead = c; p->rxbufhead = b_ptr; } #endif } } outp(0X2F7, 1); /* clear IRQ channel */ /* CALL THE OLD INTERRUPT */ (* (void (INTERRUPT_ *)(void)) mcport[0]->old_rx_int)(); disable(); outp(EOINT, 0X20); /* Send EOI to 8259 */ } /* ================== FAMILIAR STUFF BELOW THIS LINE ===================== */ #define MENU ALT_M /* key for menu */ short menu(void); /* TERM -- The terminal emulation routine. Simply polls the COM port and the keyboard alternately for characters. */ void term(COMM_PORT *p) { short c; /* must be signed to detect a -1 return */ for (;;) { /* CHECK SERIAL PORT FOR BYTE */ if ( (c = c_inchar(p)) != EOF) { putchar(c); fflush(stdout); } /* CHECK KEYBOARD FOR A KEY PRESS */ if ( (c = inkey()) != EOF) { if (c == MENU) { if (menu()) break; } else c_putc(p, c); } } } #define EXIT 'Q' /* key to exit from main */ short menu(void) { int c, retval = 0; static char *menus[] = { "\tQ. EXIT from TERM.", NULL /* null string terminates list */ }; char **p_menu; c = !EXIT; while (c != EXIT && c != LF) { puts("\n\n"); for (p_menu = menus; *p_menu != NULL; p_menu++) printf("%s\n", *p_menu); printf("\n\t\t Enter selection (CR to quit menu) : "); c = getchar(); c = toupper(c); switch (c) { case EXIT: retval = 1; break; default: break; } } puts("\nExiting menu"); return (retval); /* will be zero except if EXIT */ }