home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************/
- /* FILE JMODEM_E.C */
- /* Created 11-JAN-1990 Richard B. Johnson */
- /* 405 Broughton Drive */
- /* Beverly, Massachusetts 01915 */
- /* BBS (508) 922-3166 */
- /* open_chan(); */
- /* close_chan(); */
- /* read_chan(); */
- /* write_chan(); */
- /* Communications I/O procedures */
- /* These procedures will have to be replaced for JMODEM to execute on */
- /* a system other than a MS_DOS computer. They are VERY hardware-specific. */
- /* These procedures are grouped so that they can be replaced as a unit. */
- /* You must replace the following: */
- /* (1) OPEN a communications channel. */
- /* (2) CLOSE the opened channel. */
- /* (3) READ [variable] bytes from the channel. */
- /* (4) WRITE [variable] bytes to the channel. */
- /* */
- /* When attempting to READ bytes, some sort of time-out must be provided */
- /* within the routine to prevent a "wait-forever" syndrome. */
- /* */
- /* VAX/VMS, QIO routines are ideal! */
- /* */
- /****************************************************************************/
- #include <stdio.h> /* For FILE structure */
- #include <conio.h> /* For _inp() and _outp() */
- #include <dos.h> /* For _enable() and _disable() */
- #include "jmodem.h" /* JMODEM equates */
- #include "uart.h" /* 8250 UART equates */
- #if defined (TURBOC)
- #include <mem.h>
- #define _enable enable
- #define _disable disable
- #define _dos_setvect setvect
- #define _dos_getvect getvect
- #else
- #include <memory.h> /* _memcpy(); */
- #endif
- /****************************************************************************/
- /* Structures and templates */
- /****************************************************************************/
- typedef struct {
- word base; /* Base port address */
- word mask; /* Interrupt controller mask */
- word int_num; /* Interrupt number */
- } PORTS;
-
- PORTS port_pars[] = {
- {
- 0x3F8 , /* Base port address COM1 */
- 0xEF , /* IRQ4 11101111B COM1 */
- 0x0C , /* Interrupt number */
- } ,
- {
- 0x2F8 , /* Base port address COM2 */
- 0xF7 , /* IRQ3 11110111B COM2 */
- 0x0B , /* Interrupt number */
- } ,
- {
- 0x3E8 , /* Base port address COM3 */
- 0xEF , /* IRQ4 11101111B COM3 */
- 0x0C , /* Interrupt number */
- } ,
- {
- 0x2E8 , /* Base port address COM4 */
- 0xF7 , /* IRQ3 11110111B COM4 */
- 0x0B , /* Interrupt number */
- }
- };
- /****************************************************************************/
- /* Global allocation */
- /****************************************************************************/
- byte *write_ptr; /* Interrupt buffer */
- byte *read_ptr; /* Interrupt buffer */
- byte *buff_limit; /* End of interrupt buffer */
- word port; /* Port number */
- word old_mask; /* Old interrupt control mask */
- word old_ier; /* Old interrupt enable regis */
- word old_stat; /* Modem status for flow-contr */
- word carrier; /* Carrier detect */
- word timer; /* Global timer */
- word hardware_port; /* Physical port */
- /****************************************************************************/
- /* Function prototypes */
- /****************************************************************************/
- void interrupt far fatal_abort(void); /* Abort vector */
- void interrupt far com_int(void); /* Interrupt service routine */
- void interrupt far tim_int(void); /* Timer interrupt */
- void (interrupt far *old_tim)(); /* Pointer to old timer intr. */
- void (interrupt far *old_com)(); /* Pointer to old commu intr. */
- void (interrupt far *old_brk)(); /* Pointer to old break key. */
- /****************************************************************************/
- /* Open the communications channel */
- /* */
- /* Under MS-DOS this involves saving the com-port vector, interrupt */
- /* controller mask, and the user-tick timer vector. */
- /* New vectors and masks and patched for the communications interrupt */
- /* service routine and the local timer. These vectors will be restored */
- /* within the CLOSE channel routine. */
- /* */
- /****************************************************************************/
- word open_chan (word user_port) /* Port offset ( 1-4 ) */
- {
- short i;
- buff_limit = int_buffer + DAT_LEN-1; /* Set up buffer end pointer */
- flush(); /* Initialize the interrupt buffer */
- if (user_port > 4) /* If absolute port and IRQ */
- {
- port_pars[0].base =
- (user_port & 0x0FFF); /* Extract absolute port */
- port_pars[0].int_num = /* Use as a temporary variable */
- (user_port >> 12); /* Extract the IRQ number */
- port_pars[0].mask = /* Create the controller mask */
- ((~(0x01 << port_pars[0].int_num)) & 0xFF);
- port_pars[0].int_num += 0x08; /* IRQ number to ABS interrupt */
- user_port = 1; /* For following instruction */
- }
- user_port--; /* Convert to an offset */
- hardware_port =
- port_pars[user_port].base; /* Set hardware port */
- old_ier = inp(hardware_port +IER); /* Get interrupt enable regis */
- old_brk = _dos_getvect(0x1B); /* Get old break key vector */
- old_mask = inp(0x21); /* Save old interrupt mask */
- old_tim = _dos_getvect(0x1C); /* Get old DOS timer-tick vector */
- old_com = _dos_getvect(
- port_pars[user_port].int_num); /* Get old communications vector */
- _dos_setvect(0x1B,fatal_abort); /* Set fatal abort vector (1) */
- _dos_setvect(0x23,fatal_abort); /* Set fatal abort vector (2) */
- _dos_setvect(0x1C,tim_int); /* Set new timer interrupt */
- _dos_setvect(
- port_pars[user_port].int_num, /* Set new communications vector */
- com_int);
- outp(0x21,old_mask &
- port_pars[user_port].mask); /* Set interrupt enable mask */
- outp(hardware_port+MCR, MOD_ENA); /* Turn on DTR, RTS, IRQ enable */
- outp(hardware_port+IER, IER_ERBFI); /* Enable received data available */
- for (i=0; i<8; i++) /* Edge-triggering, read the ports */
- inp(hardware_port + i); /* Port to clear */
- outp(0x20,0x20); /* Reset the hardware controller */
- timer=9; /* 1/2 second wait */
- while (timer); /* Wait 1/2 second */
- flush(); /* Clear interrupt buffer again */
- i = inp(hardware_port+MSR); /* Get current modem status */
- old_stat = i & MSR_CHK; /* Get current modem control */
- carrier = i & MSR_RLSD; /* Get any modem carrier */
- return JM_NRM;
- }
- /****************************************************************************/
- /* Close the communications channel */
- /* */
- /* Under MS-DOS this involves restoring the interrupt vectors and */
- /* controller mask that was saved during the OPEN routine. */
- /* */
- /****************************************************************************/
- word close_chan (word user_port)
- {
- if (user_port > 4) user_port = 1; /* Absolute port address */
- user_port--; /* Convert to an offset */
- outp(hardware_port+IER,old_ier); /* Set old interrupt enable */
- outp(0x21,old_mask); /* Restore old interrupt mask */
- _dos_setvect(
- port_pars[user_port].int_num, /* Set old communications vector */
- old_com);
- _dos_setvect(0x1C,old_tim); /* Set old timer interrupt */
- _dos_setvect(0x1B,old_brk); /* Set old break interrupt */
- return JM_NRM;
- }
- /****************************************************************************/
- /* Read from the communications channel */
- /* */
- /* This involves transferring data from the interrupt buffer and */
- /* maintaining the interrupt buffer pointers. A timeout is established. */
- /* */
- /****************************************************************************/
- word read_chan (word bytes, /* Bytes requested */
- register byte *buffer) /* Pointer to user's buffer */
- {
- word count; /* Byte count */
- word avail; /* Bytes available */
- timer = TIMOUT; /* Set initial timeout value */
- count = bytes; /* Set byte-count */
-
- while (count && timer) /* If byte request or no timeout */
- {
- avail = write_ptr - read_ptr; /* Bytes available */
- if (avail) /* If bytes available */
- {
- if (avail > count) /* If more bytes than we need */
- avail = count; /* Take only what we need */
- memcpy (buffer , /* User's buffer */
- read_ptr , /* Interrupt buffer pointer */
- avail) ; /* Copy to user's buffer */
- count -= avail; /* Update count */
- read_ptr +=avail; /* Update read pointer */
- buffer +=avail; /* Update write pointer */
- timer = TIMOUT; /* Set new timer value */
- }
- _disable(); /* Clear interrupts */
- if (read_ptr == write_ptr) /* If no bytes available */
- read_ptr = write_ptr /* Initialize the interrupt buffer */
- = int_buffer;
- _enable(); /* Enable interrupts */
- }
- return(bytes - count); /* Actual characters received */
- }
- /****************************************************************************/
- /* Flush the interrupt buffer */
- /****************************************************************************/
- void flush()
- {
- _disable();
- read_ptr = write_ptr = int_buffer; /* Initialize the interrupt buffer */
- _enable();
- }
- /****************************************************************************/
- /* Communications transmit routine */
- /* Write 'bytes' bytes from buffer to the UART. Don't return until done */
- /* unless the carrier failed or the hardware broke. */
- /****************************************************************************/
- word write_chan (word bytes, /* Bytes to send */
- register byte *buffer) /* Pointer to the buffer */
- {
- word status;
- byte *sav_sta;
- byte *old_sta;
-
- sav_sta = old_sta = syst.s_sta; /* Save current status */
- timer = TIMOUT;
- while ((bytes && timer) && !user_abort ) /* Bytes, no abort, no timout */
- {
- while (
- ( status = /* Get modem status */
- ( inp (hardware_port+MSR) /* from modem status register */
- & MSR_CHK ) /* Check CTS and DSR only */
- ) != old_stat) /* If not the same as before */
- { /* Flow control loop */
- if ( (status & MSR_RLSD ) /* ...check modem carrier */
- != carrier) /* ... if not same as before */
- {
- user_abort = 0x0FFFF; /* Set the abort flag */
- return JM_ABT; /* ... and get out */
- }
- syst.s_sta = flow; /* Set flow-control status */
- if ( syst.s_sta != old_sta ) /* If we haven't already */
- {
- screen (SCR_FLG,&syst); /* Show flow-control status */
- old_sta = syst.s_sta; /* Flag that we did it */
- }
- }
- syst.s_sta = sav_sta; /* Set previous status */
- if ( syst.s_sta != old_sta )
- {
- screen (SCR_FLG,&syst); /* Show previous status */
- old_sta = syst.s_sta; /* Flag that we did it */
- }
- status = inp(hardware_port+LSR); /* Get line-status */
- if (status & LSR_THRE) /* If TX holding reg empty */
- {
- outp(hardware_port, *buffer++); /* Send the byte */
- bytes--; /* Bump the byte-count */
- timer = TIMOUT; /* Set new timer-value */
- }
- }
- return JM_NRM;
- }
-
- /******* The following interrupt service routines are in JMODEM_G.ASM *******/
- #ifdef DOIT_IN_C
- /****************************************************************************/
- /* Communications adapter hardware interrupt */
- /* This is very simple because we interrupt on receive only. Since we */
- /* must wait until the entire block has been received and checked be- */
- /* for doing anything else, the transmitter is polled. */
- /* */
- /****************************************************************************/
- void interrupt far com_int()
- {
- *write_ptr = (byte)
- inp(hardware_port); /* Put byte in buffer */
- outp(0x20,0x20); /* Reset hardware controller */
- if (write_ptr < buff_limit) /* Check buffer for overflow */
- write_ptr++; /* Bump pointer if room */
- }
- /****************************************************************************/
- /* Timer interrupt */
- /* A WORD (timer) gets decremented every timer-tick if it is not already */
- /* zero. This is used to set time-out values in the communication pro- */
- /* cedures so that a "wait-forever" can't occur. */
- /* */
- /****************************************************************************/
- void interrupt far tim_int()
- {
- if (timer) /* If NZ */
- timer--; /* Bump the timer */
- outp(0x20,0x20); /* Reset the hardware controller */
- _enable(); /* Allow network interrupts */
- #if !defined (TURBOC)
- _chain_intr(old_tim); /* Go to old timer-tick routine */
- #endif
- }
- #endif
- /****************************************************************************/
-
- /****************************************************************************/
- /* A B O R T trap */
- /* Control-C and control-break vectors are set to point here so that */
- /* a user-break harmlessly sets a flag so that interrupt vectors may */
- /* properly restored upon program exit. */
- /* */
- /****************************************************************************/
- void interrupt far fatal_abort()
- {
- user_abort = 0xFFFF; /* Set abort flag */
- timer = 0; /* Provoke timout */
- }
- /****************************************************************************/
- /******************** E N D O F M O D U L E *****************************/