home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / lp.zoo / lp.c next >
Encoding:
C/C++ Source or Header  |  1991-03-18  |  8.1 KB  |  304 lines

  1.  
  2. #ifdef SCCSID
  3. static sccsid[] = "@(#) lp.c 1.1 91/03/18  19:50:09";  
  4. #endif
  5. /*****************************************************************************
  6. *    Hardware line printer driver.
  7.  
  8.     This module implements the functionality needed to drive a PC-style
  9.     parallel port.  All function calls are non-blocking.  The function 
  10.     passed to lpt_io() determine what action is taken.  The actions
  11.     are defined in lp.h and again for reference below.  In general, to 
  12.     use a port, the following procedure is used:
  13.  
  14.     Test for port presence  (lpt_io(IS_PRESENT))
  15.     if so, then (lpt_io(INIT) to initialize the port
  16.  
  17.     For each character, test lpt_io(IS_BUSY)
  18.     When port is not busy, lpt_io(OUT) with the character
  19.  
  20.     Optionally, one may retrieve the status of the printer port with
  21.     lpt_io(STAT).
  22.  
  23.     Finally, if one desires to select or deselect a printer (assert or
  24.     deassert the SELECT line on the interface), call lpt_io(SELECT) with
  25.     the appropriate argument.
  26.  
  27.  
  28.     Two test routines are provided in this module.  Defining TEST_1 
  29.     includes a main() and creates a program that outputs 50,000 "*"
  30.     characters to the port and displays transmission statistics.
  31.  
  32.     Defining TEST_2 creates a program that will output a file specified
  33.     on the command line or redirected into it.
  34.  
  35.  
  36.     Following is a table of function calls vs arguments vs returned value:
  37.  
  38.  
  39. Function             Port             Byte             Mode        Returned value
  40. ------------------------------------------------------------------------------
  41. IN                    LPT base port    N/A             IN            Byte Read
  42. OUT                    LPT base port    byte to print     OUT            Port Status
  43. INIT                LPT base port     N/A                INIT        Port Status
  44. STAT                LPT base port     N/A                STAT        Port Status
  45. SELECT ASSERT        LPT base port    ASSERT            SELECT        Port Status
  46. SELECT DEASSERT        LPT base port    DEASSERT        SELECT        Port Status
  47. IS_BUSY                LPT base port     N/A                IS_BUSY        0 if not busy
  48. IS_ACK                LPT base port     N/A                IS_ACK        0 if not ACK
  49. IS_PRESENT            LPT base port     N/A                IS_PRESENT    0 if not present
  50.  
  51. ***************************************************************************/
  52.  
  53. /**************************************************************************/
  54. /*&&&&&&&&&&&&&&&&&&&&&&*/
  55. #define TEST_2
  56. /*&&&&&&&&&&&&&&&&&&&&&&*/
  57. /**************************************************************************/
  58.  
  59. #if defined(TEST_1) || defined(TEST_2)
  60. #include <stdio.h>
  61. #include <time.h>
  62. #endif
  63.  
  64. #include <bios.h>
  65. #include "lp.h"
  66.  
  67. /* function codes */
  68. /********************************************************/
  69. /* these are defined in lp.h and are here for reference 
  70. #define IN 1
  71. #define OUT 2
  72. #define INIT 3
  73. #define STAT 4
  74. #define SELECT 5
  75. #define IS_BUSY 6
  76. #define IS_ACK 7
  77. #define IS_PRESENT 8
  78. ***********************************************************/
  79.  
  80. /********************************************************/
  81. /* subfunction codes for function SELECT
  82.     Again, these are defined in lp.h
  83. #define ASSERT    100
  84. #define DEASSERT 101
  85. ****************************************************/
  86.  
  87. /***************************************************************************
  88.  
  89.  port architecture.
  90.  
  91. Each lpt port starts at a base address as defined below.  Status and 
  92. control ports are defined off that base.
  93.  
  94.                   write                                    read
  95. =============================================================================
  96. Base    data to the printer is latched.            Read latched data
  97.  
  98. base+1    not defined                             Read printer status lines
  99.                                                 Bits are as follows:
  100.                                                 bit 7    busy        0x80
  101.                                                 bit 6     ack            0x40
  102.                                                 bit 5    paper out    0x20
  103.                                                 bit 4    select in    0x10
  104.                                                 bit 3    error        0x08
  105.                                                 2,1,0    Not used
  106.  
  107. base+2    write control bits                        read the same control bits
  108.         Bits are defined as follows:            Normally reads the latched
  109.         bit 0    *strobe            0x01            bits written to same port
  110.         bit 1    *auto feed        0x02
  111.         bit 2    init printer    0x04
  112.         bit 3    *select out        0x08
  113.         bit 4    turn on irq7 on ACK hi-2-lo toggle    0x10
  114.         5,6,7    not used
  115.  
  116. ******************************************************************************/
  117. /********************************************/
  118. /* defined in lp.h and are here for ref only
  119. #define LPT1 0x3bc
  120. #define LPT2 0x378
  121. #define LPT3 0x278
  122. **********************************************/
  123.  
  124. #ifdef TEST_1
  125. main()
  126. {
  127.     unsigned status;
  128.     unsigned lpt_io();
  129.     unsigned int i;
  130.     time_t start_time, end_time;
  131.  
  132.     status = lpt_io(LPT1, 0, INIT);
  133.     printf("sending 50,000 chars\n");
  134.     start_time = time(NULL);
  135.  
  136.     for (i=0;i<50000;i++) {
  137.         while ( status=lpt_io(LPT1,0,IS_BUSY) ) /* spin while busy */
  138.             ;
  139.         status = lpt_io(LPT1, '*', OUT);
  140.         if (!(i%1000))
  141.             printf("*");
  142.     }
  143.     end_time = time(NULL);
  144.     printf("\n50,000 chars in %ld seconds or %ld chars/sec\n",
  145.         end_time-start_time,
  146.         50000L / (end_time-start_time) );
  147.  
  148.     exit(0);
  149.  
  150. }
  151.  
  152. #endif
  153.  
  154. #ifdef TEST_2
  155. /* this version outputs a file to lpt1 */
  156. main(argc, argv)
  157. int argc;
  158. char **argv;
  159. {
  160.     unsigned status;
  161.     unsigned lpt_io();
  162.     long int i=0L;
  163.     time_t start_time, end_time;
  164.     int character;
  165.     int busy_flag=0;
  166.  
  167.     status = lpt_io(LPT1, 0, INIT);
  168.     start_time = time(NULL);
  169.  
  170.     if (argc > 1) {
  171.         if (freopen(argv[1], "rb", stdin) == (FILE *) NULL) {
  172.             cprintf("Error, file %s open failed\n", argv[1]);
  173.             exit(1);
  174.         }
  175.     }
  176.  
  177.     while ( (character = fgetchar()) != EOF) {
  178.  
  179.         while ( status=lpt_io(LPT1,0,IS_BUSY) ){ /* spin while busy */
  180.             if (!busy_flag) {
  181.                 gotoxy(70,25);
  182.                 cputs("BUSY    ");
  183.                 busy_flag=1;
  184.             }
  185.         }
  186.         if (busy_flag) {
  187.             gotoxy(70,25);
  188.             cputs("PRINTING");
  189.             busy_flag=0;
  190.         }
  191.         status = lpt_io(LPT1, character, OUT);
  192.         i++;
  193.     }
  194.     end_time = time(NULL);
  195.  
  196.     gotoxy(70,25);cputs("        ");
  197.     gotoxy(1,24);
  198.     cprintf("%ld chars in %ld seconds or %ld chars/sec",
  199.         i,
  200.         end_time-start_time,
  201.         i / (end_time-start_time) );
  202.  
  203.     exit(0);
  204.  
  205. }
  206.  
  207. #endif
  208.  
  209. /*
  210. *    The meaning of life and the bits returned in the status byte
  211. *    NOTE:  Important - the sense of all bits are flipped such that
  212. *    if the bit is set, the condition is asserted.
  213. *
  214. *Bits----------------------------
  215. *   7   6   5   4   3   2   1   0
  216. *   |   |   |   |   |   |   |   +-- unused
  217. *   |   |   |   |   |   |   +------ unused
  218. *   |   |   |   |   |   +---------- unused
  219. *   |   |   |   |   +-------------- 1 = i/o error
  220. *   |   |   |   +------------------ 1 = selected
  221. *   |   |   +---------------------- 1 = out of paper
  222. *   |   +-------------------------- 1 = acknowledge
  223. *   +------------------------------ 1 = not busy
  224. *
  225. */
  226.  
  227.  
  228. unsigned int
  229. lpt_io(port,byte,mode)
  230.     unsigned port;
  231.     unsigned byte;
  232.     int mode;
  233. {
  234.     unsigned i,j,status;
  235.     long unsigned otime;
  236.  
  237.  
  238.     switch (mode) {  /* test for valid commands */
  239.  
  240.     case OUT:
  241.         outportb(port,byte);    /* send the character to the port latch */
  242.  
  243.         outportb(port+2, 0x0d); /* set strobe high */
  244.         outportb(port+2, 0x0d); /* do it again to kill some time */
  245.         outportb(port+2, 0x0c); /* set strobe low */
  246.         inportb(port+1);  /* pre-charge the line if +busy is floating*/
  247.         status = (inportb(port+1) & 0x00f8) ^ 0x48;
  248.         return(status);
  249.  
  250.     case  IN:
  251.         return(inportb(port));
  252.  
  253.     case IS_BUSY:    /* this checks the busy line */
  254.         return ( (inportb(port+1) & 0x80) ^ 0x80 );    /* zero if not busy */
  255.         /* note that we flip the sense of this bit because it is inverted
  256.             on the port */
  257.  
  258.     case IS_ACK:    /* this checks the ack line */
  259.         return ( inportb(port+1) & 0x60 );    /* zero if ACK not asserted */
  260.  
  261.     case SELECT:
  262.  
  263.         switch (byte) {
  264.  
  265.         case ASSERT:
  266.             i = inportb(port+2);         /* get the control bits */
  267.             outportb(port+2, i | 0x8);    /* mask bit 3 ON and output */
  268.             return ( (inportb(port+1) & 0xf8) ^ 0x48 );
  269.  
  270.         case DEASSERT:
  271.             i = inportb(port+2);         /* get the control bits */
  272.             outportb(port+2, i & ~0x8);    /* mask bit 3 OFF and output */
  273.             return ( (inportb(port+1) & 0xf8) ^ 0x48 );
  274.  
  275.         default:
  276.             return(~0);     /* error */
  277.         }
  278.  
  279.     case INIT:
  280.         otime = biostime(0,0L);     /* get the timer ticks */
  281.         outport(port+2, 0x08);         /* set init line low */
  282.  
  283.         /* wait for the next timer transition */
  284.         while ( otime + 1 > biostime(0,0L)) ;
  285.         outportb(port+2, 0x0c);     /* set init line high */
  286.                                     /* and select printer */
  287.         /* fall thru */
  288.     case STAT:
  289.         return( ((inportb(port+1) & 0xf8) ^ 0x48) );
  290.  
  291.     case IS_PRESENT:    /* test to see if the port is present */
  292.     outportb(port,0x55);
  293.         if (inportb(port) == 0x55) {
  294.             return(~0);
  295.         }
  296.         return(0);
  297.  
  298.     default:
  299.         return(~0);        /* error, all bits set */
  300.     }
  301. }
  302.  
  303. /************** end of file ******************/
  304.