home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / datafiles / text / c_manual / devices / paralleldevice / paralleldevice.doc < prev    next >
Text File  |  1995-02-27  |  48KB  |  1,448 lines

  1. 8    PARALLEL DEVICE
  2.  
  3. 8.1  INTRODUCTION
  4.  
  5. All Amiga models have a parallel port to which you can connect
  6. external devices like a printer, a video digitizer or a sound
  7. sampler. The most common external device for the parallel port
  8. is undoubtedly a printer, although some printers are connected
  9. to the serial device.
  10.  
  11. The parallel port can send and receive eight bits
  12. simultaneously. This can be compared with the serial port which
  13. only can send/receive a stream of bits. The parallel port
  14. is because of this much faster and is therefore often used for
  15. video digitizers or sound samplers.
  16.  
  17. The parallel device helps you to work with the printer at a
  18. very low level, but is still easy to handle. The parallel
  19. device can as the serial device be locked for exclusive access
  20. or you can allow other programs to use the device
  21. simultaneously.
  22.  
  23. It is important to note that the parallel device should only be
  24. used when you want to handle the port directly at a low level.
  25. This can be useful when you want to collect data from a video
  26. digitizer, or send untranslated printer codes. However, if you
  27. simply want to use the printer you should use the printer
  28. device instead. The printer device will automatically take care
  29. of all printer handling, and is using the preference settings.
  30. See next chapter (29) "Printer Device".
  31.  
  32.  
  33.  
  34. 8.2  PARALLEL PORT
  35.  
  36. A parallel port sends a whole byte each time as explained above,
  37. and is therefore very fast. Data that is sent to or received
  38. from the parallel port does not need to be translated in any
  39. way, it is immediately usable.
  40.  
  41. The Amiga's parallel (Centronics) port is a 25-pin D-female-
  42. type connector. (On the old A1000s the parallel port have a
  43. male connector.) Below is an almost complete list of the pin
  44. assignment, together with a short description. (See
  45. illustration "Centronics".)
  46.  
  47.  
  48.   Pin  Name    Direction  Description
  49.   -----------------------------------------------------
  50.     1  STROBE  Out        Used to coordinate the events
  51.     2  Data 0  In/Out     Bit 0
  52.     3  Data 1  In/Out     Bit 1
  53.     4  Data 2  In/Out     Bit 2
  54.     5  Data 3  In/Out     Bit 3
  55.     6  Data 4  In/Out     Bit 4
  56.     7  Data 5  In/Out     Bit 5
  57.     8  Data 6  In/Out     Bit 6
  58.     9  Data 7  In/Out     Bit 7
  59.    10  ACK     In         Data acknowledge
  60.    11  BUSY    In/Out     General Input/Output pin
  61.    12  POUT    In/Out     General Input/Output pin
  62.    13  SEL     In/Out     General Input/Output pin
  63.    14  +5V     -          +5 Volt
  64.    15  NC      In/Out     No connection pin
  65.    16  RESET   Out        The system resets
  66.    17  GND     -          Signal ground
  67.    18  GND     -          Signal ground
  68.    19  GND     -          Signal ground
  69.    20  GND     -          Signal ground
  70.    21  GND     -          Signal ground
  71.    22  GND     -          Signal ground
  72.    23  GND     -          Signal ground
  73.    24  GND     -          Signal ground
  74.    25  GND     -          Signal ground
  75.  
  76.  
  77.  
  78. 8.3  PARALLEL DEVICE
  79.  
  80. The parallel device is very similar to the serial device. It
  81. can either be used in exclusive mode, or several programs may
  82. use the port simultaneously, shared access. When you want that
  83. the parallel device to do something you simply send an already
  84. initialized request block (struct IOExtPar), and the device
  85. will send a message to the reply port when the request has been
  86. done. Exactly as all other devices.
  87.  
  88.  
  89.  
  90. 8.3.1  THE PARALLEL REQUESTBLOCK
  91.  
  92. The request block you should use with the parallel device look
  93. like this: (defined in header file "devices/parallel.h")
  94.  
  95. struct IOExtPar
  96. {
  97.   struct IOStdReq IOPar;
  98.   ULONG io_PExtFlags;
  99.   UBYTE io_Status;
  100.   UBYTE io_ParFlags;
  101.   struct IOPArray io_PTermArray;
  102. };
  103.  
  104. IOPar:         This is the standard request block. The IOStdReq
  105.                structure is defined in header file "exec/io.h",
  106.                and is fully documented in chapter 17 "Devices". 
  107.  
  108. io_PExtFlags:  This is currently not used, but will maybe be
  109.                used in the future when more parallel flags are
  110.                needed. 
  111.  
  112. io_Status:     The status of the parallel port and parallel
  113.                device. There exist for the moment four
  114.                status flags:
  115.                
  116.                  IOPTF_RWDIR    If this flag is set the device
  117.                                 is currently writing to the
  118.                                 parallel device. On the other
  119.                                 hand, if the flag is not set
  120.                                 the device is collecting data
  121.                                 at the parallel port. 
  122.  
  123.                  IOPTF_PARSEL   Printer selected.
  124.  
  125.                  IOPTF_PAPEROUT The printer ran out of paper.
  126.                                 Inform the user!
  127.  
  128.                  IOPTF_PARBUSY  The parallel port is currently
  129.                                 busy.
  130.                                 
  131.                Use the command "PDCMD_QUERY" before you look at
  132.                these fields to make sure everything is up to
  133.                date. 
  134.  
  135. io_ParFlags:   This field contains all special parallel flags.
  136.                There exist only three flags for the moment, and
  137.                one of these is still not usable. Here is the
  138.                complete list:
  139.  
  140.                  PARF_SHARED     Set this flag if you want to
  141.                                  share the parallel port with
  142.                                  other programs. Note that this
  143.                                  flag should only be altered
  144.                                  before you have opened the
  145.                                  parallel device, and should
  146.                                  NOT be changed later on.
  147.                                 
  148.                                  If you want to change status
  149.                                  you should close the parallel
  150.                                  device, alter the status and
  151.                                  then try to open the device
  152.                                  again.
  153.  
  154.                  PARF_RAD_BOOGIE This flag is currently not
  155.                                  used. It is supposed to be
  156.                                  set when you want to send/
  157.                                  receive data at a very high
  158.                                  speed.
  159.  
  160.                  PARF_EOFMODE    This is actually the only
  161.                                  flag you may alter after you
  162.                                  have opened the device. If
  163.                                  the flag is set the parallel
  164.                                  device will immediately
  165.                                  stop the transmission of data
  166.                                  when it finds one of the
  167.                                  specified end-of-file
  168.                                  characters.
  169.  
  170. io_PTermArray: This field contains eight characters which will
  171.                be treated as the end-of-file characters if the 
  172.                PARF_EOFMODE flag is set.
  173.  
  174.  
  175.  
  176. 8.3.2  OPEN THE PARALLEL DEVICE
  177.  
  178. As with all devices you have to open a message port through
  179. which the parallel device can communicate with you, and
  180. allocate a request block (a IOExtPar structure), before you
  181. may open the device itself.
  182.  
  183.   1. Open a message port: (Since it is only our task and the
  184.      device that will use the message port, we do not need
  185.      to make it "public", hence no name. Priority should as
  186.      usual be set to 0, normal priority.)
  187.  
  188.      struct MsgPort *replymp;
  189.  
  190.      replymp = (struct MsgPort *)
  191.        CreatePort( NULL, 0 );
  192.  
  193.      if( !replymp )
  194.        clean_up( "Could not create the reply port!" );
  195.  
  196.  
  197.   2. Allocate a request block of type IOExtPar structure.
  198.      (The IOExtPar structure is an extended version of the
  199.      normal request block, and should therefore be allocated
  200.      with help of the CreateExtIO() function with the size
  201.      set to sizeof( struct IOExtPar ).
  202.  
  203.      struct IOExtPar *parallel_req;
  204.  
  205.      parallel_req = (struct IOExtPar *)
  206.        CreateExtIO( replymp, sizeof( struct IOExtPar ) );
  207.  
  208.      if( !parallel_req )
  209.        clean_up( "Not enough memory!" );
  210.  
  211.  
  212. Once the message port and the request block have successfully
  213. been created, you need to decide if you want exclusive or
  214. shared access. If you want shared access, other programs may
  215. also use the parallel port, should you set the flag
  216. "PARF_SHARED" in the io_ParFlags" field. If you want exclusive
  217. access you do not need to set any flags, since it is the
  218. default mode.
  219.  
  220.   3. Either set shared or exclusive access, and open the
  221.      device.
  222.  
  223.      UBYTE error;
  224.  
  225.      /* We want shared access: */
  226.      parallel_req->io_ParFlags = PARF_SHARED;
  227.  
  228.      /* Open the parallel device: */
  229.      error = OpenDevice( PARALLELNAME, 0, parallel_req, 0 );
  230.  
  231.      if( error )
  232.        clean_up( "Could not open the Parallel Device!" );
  233.  
  234.  
  235.  
  236. 8.3.3  SET PARALLEL PARAMETERS
  237.  
  238. Once you have successfully opened the parallel device you
  239. may set some parameters that tells the device how it should
  240. work. Luckily, the parallel device is much simpler than the
  241. serial device.
  242.  
  243. For the moment there exist only one parallel flag you may use,
  244. and that is PARF_EOFMODE. It should be set if you want the
  245. device to immediately stop the current communication if one of
  246. the eight specified end-of-file characters appears. To set the
  247. flag do like this:
  248.  
  249.   /* Look for end-of-file characters: */
  250.   parallel_req->io_ParFlags += PARF_EOFMODE;
  251.  
  252. Note that we used the sign "+=". This is very useful if you
  253. want to set one flag (bit), but keep all others unchanged. If
  254. we simply used the sign "=" the "PARF_SHARED" flag we
  255. previously had set would be erased. We could of course have
  256. written it like this:
  257.  
  258.   /* Set both the end-of-file and shared mode: */
  259.   parallel_req->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
  260.  
  261. This is however not equally good, since it is easy to forget
  262. one flag, and then it would be erased. So if you want to
  263. add flags use the command "+=". To erase one flag you only
  264. have to do the opposite and subtract it ("-=").
  265.  
  266. If you want to use the end-of-file mode, and have set the
  267. "PARF_EOFMODE" flag, you must also tell the device which
  268. characters should be treated as end-of-file characters. The
  269. list of these characters is stored in the "IOPArra" array
  270. which is placed at the bottom of the request structure, and
  271. looks like this:
  272.  
  273.   struct IOPArray
  274.   {
  275.     ULONG PTermArray0;
  276.     ULONG PTermArray1;
  277.   };
  278.  
  279. Each ULONG data consists of four bytes, and in total you can
  280. store eight bytes (end-of-file characters) in the array. To
  281. make the checking routine efficient you must store the
  282. characters in descending order! To copy the desired
  283. characters into the array do like this:
  284.      
  285.   /* Here is an array with all EOF characters: */
  286.   /* NOTE! They MUST be in descending order!   */
  287.   UBYTE eof_char[8]={ 0x54, 0x32, 0x16, 0x15, 0x12, 0x03, 0x00, 0x00 };
  288.  
  289.   /* Declare a unsigned byte pointer: */
  290.   UBYTE *ptr;
  291.  
  292.   /* Simple loop variable: */
  293.   int loop;
  294.  
  295.   ...
  296.  
  297.   /* Get the address of the IOTArray: */
  298.   ptr = (UBYTE *) &(ioreq->io_PTermArray);
  299.  
  300.   /* Set all eight end of file characters: */
  301.   for( loop=0; loop < 8; loop++ )
  302.   {
  303.     /* Copy character after character: */
  304.     *ptr = eof_chars[ loop ];
  305.  
  306.     /* Step one byte forward: */
  307.     ptr++;
  308.   }
  309.  
  310.  
  311. Once you have set all desired parameters in the request block
  312. (IOExtPar structure) you set the IO command to PDCMD_SETPARAMS
  313. and tell the parallel device to do your request by calling the
  314. DoIO() function. If something went wrong DoIO() will return
  315. with an error number, else 0 is returned which means that your
  316. request have successfully been executed. (See below for a
  317. complete list of error messages.) Here is an example:
  318.  
  319.   /* We want to set the parallel device's parameters: */
  320.   ioreq->IOPar.io_Command = PDCMD_SETPARAMS;
  321.  
  322.   /* Do our request, and return when done: */
  323.   error = DoIO( ioreq );
  324.  
  325.  
  326.  
  327. 8.3.4  WRITE DATA
  328.  
  329. To send data to the parallel device you have to:
  330.  
  331.   1. Set the command flag "CMD_WRITE" in the "io_Command"
  332.      field.
  333.  
  334.   2. Tell the parallel device how many bytes you want to send
  335.      by setting the "io_Length" field as desired. If you set it
  336.      to -1 the device will continuously send data and stop
  337.      first when an end-of-file character is found. (The end-of-
  338.      file character will also be sent.) Note that the parallel
  339.      flag "PARF_EOFMODE" must have been set, or the device will
  340.      never stop sending data.
  341.  
  342.   3. Give the field "io_Data" the address of the first byte of
  343.      data that should be sent.
  344.  
  345.   4. Finally you send the request to the parallel device. If
  346.      you want to wait for the request to be completed
  347.      (synchronous) you should use the DoIO() function. On the
  348.      other hand, if you want that your program continues to
  349.      work while your request is completed, you should use the
  350.      SendIO() function.
  351.  
  352. Here is an example on how to write data to the parallel port:
  353. (In this example the program will be put to sleep while the data
  354. is sent to the parallel port.)
  355.  
  356.   error: (UBYTE) is a simple unsigned byte variable.
  357.  
  358.   ioreq: (struct IOExtPar *) is a pointer to an IOExtPar
  359.          structure.
  360.  
  361.   data:  (BYTE) is a pointer to a block of memory where all
  362.          data you want to send is located.
  363.  
  364.  
  365.   /* We want to send (write) some data: */
  366.   ioreq->IOPar.io_Command = CMD_WRITE;
  367.  
  368.   /* Give the start address of our data buffer: */
  369.   ioreq->IOPar.io_Data = data;
  370.  
  371.   /* We want to send 150 bytes/characters: */
  372.   ioreq->IOPar.io_Length = 150;
  373.  
  374.   /* Do our request: */
  375.   error = DoIO( ioreq );
  376.  
  377.   /* Everything OK? */
  378.   if( error )
  379.     printf( "Problems while writing!\n" );
  380.  
  381.  
  382. If you do not want to wait for the request to be completed you
  383. should use the SendIO() function instead. To check later if the
  384. request have been completed or not you can either use the
  385. function CheckIO(), or wait for a message to arrive at the
  386. request block's reply port. (Since other request may also send
  387. messages to this port, it is usually easiest to use CheckIO().)
  388.  
  389. Once the request have been completed you can look at the
  390. io_Error field of the request block to check if everything
  391. was OK. If the field is zero everything was executed without
  392. any problems, but if it is non zero the request failed.
  393.  
  394. Here is an example:
  395.  
  396.   /* Declare a pointer and set it to NULL: */
  397.   struct IOExtPar *ptr = NULL;
  398.  
  399.   ...
  400.   
  401.  
  402.   /* We want to send (write) some data: */
  403.   ioreq->IOPar.io_Command = CMD_WRITE;
  404.  
  405.   /* Give the start address of our data buffer: */
  406.   ioreq->IOPar.io_Data = data;
  407.  
  408.   /* We want to send 280 bytes/characters: */
  409.   ioreq->IOPar.io_Length = 280;
  410.  
  411.   /* Do our request and return immediately: */
  412.   SendIO( ioreq );
  413.  
  414.  
  415.   /* As long as the pointer is not pointing to */
  416.   /* the request we should stay in the loop:   */
  417.   while( ptr == NULL )
  418.   {
  419.     ... do something ...
  420.  
  421.   
  422.     /* Check if the request has been completed: (If the  */
  423.     /* request has been completed CheckIO() will return  */
  424.     /* a pointer to the request, else NULL is returned.) */
  425.     ptr = CheckIO( ioreq );
  426.   }
  427.  
  428.   /* Remove the requst block's message. (The ptr and ioreq */
  429.   /* are in this example identical, so it does not matter  */
  430.   /* whichever you will use. The parenthesis around the    */
  431.   /* expression is actually unnecessary, but this looks    */
  432.   /* better.)                                              */
  433.   Remove( &(ptr->IOPar.io_Message.mn_Node) );
  434.  
  435.   /* Everything OK? Check the io_Error filed: */
  436.   if( ioreq->IOPar.io_Error )
  437.     printf( "Problems while writing!\n" );
  438.  
  439.  
  440.  
  441. 8.3.5  READ DATA
  442.  
  443. Although most people use the parallel port to send data to their
  444. printer, more and more users connect other external devices
  445. like video digitzers and sound samplers. With these devices
  446. you do not only need to send data, you also have to collect
  447. data from the parallel port.
  448.  
  449. The process of collecting (reading) is very similar to reading.
  450. Here is what you have to do:
  451.  
  452.   1. Set the command flag "CMD_READ" in the "io_Command"
  453.      field.
  454.  
  455.   2. Tell the parallel device how many bytes you want to read
  456.      by setting the "io_Length" field as desired. If you set it
  457.      to -1 the device will continuously read data and stop
  458.      first when an end-of-file character is received. (The end-
  459.      of-file character will also be collected.) Note that the
  460.      parallel flag "PARF_EOFMODE" must have been set, or the
  461.      device will never stop collecting data.
  462.  
  463.   3. Give the field "io_Data" a pointer to your data buffer
  464.      where all collected data should be placed. Note that the
  465.      buffer must be big enough so all data will fit! 
  466.  
  467.   4. Finally you send the request to the parallel device. If
  468.      you want to wait for the request to be completed
  469.      (synchronous) you should as usual use the DoIO() function.
  470.      On the other hand, if you want that your program
  471.      continues to work while your request is completed, you
  472.      should use the SendIO() function.
  473.  
  474. Here is an example on how to read data: (Your program will be
  475. put to sleep while the data is collected.)
  476.  
  477.   error: (UBYTE) is a simple unsigned byte variable.
  478.  
  479.   ioreq: (struct IOExtPar *) is a pointer to an IOExtPar
  480.          structure.
  481.  
  482.   data:  (BYTE) is a pointer to a block of memory where all
  483.          data which is collected will be stored. Note that the
  484.          data buffer must be big enough so all data will fit.
  485.  
  486.  
  487.   /* We want to read some data: */
  488.   ioreq->IOPar.io_Command = CMD_READ;
  489.  
  490.   /* Give the start address of our data buffer: */
  491.   ioreq->IOPar.io_Data = data;
  492.  
  493.   /* We want to read 400 bytes/characters: (The buffer must */
  494.   /* then be at least 400 bytes.)                           */
  495.   ioreq->IOPar.io_Length = 400;
  496.  
  497.   /* Do our request: */
  498.   error = DoIO( ioreq );
  499.  
  500.   /* Everything OK? */
  501.   if( error )
  502.     printf( "Problems while reading!\n" );
  503.  
  504.  
  505. The program above will go to sleep while the data is collected
  506. from the parallel port. If you want to do something while the
  507. data is fetched and not go to sleep you should use the
  508. asynchronous function SendIO() function as explained above.
  509. Here is an example:
  510.  
  511.   /* Declare a pointer and set it to NULL: */
  512.   struct IOExtPar *ptr = NULL;
  513.  
  514.   ...
  515.   
  516.  
  517.   /* We want to read some data: */
  518.   ioreq->IOPar.io_Command = CMD_READ;
  519.  
  520.   /* Give the start address of our data buffer: */
  521.   ioreq->IOPar.io_Data = data;
  522.  
  523.   /* We want to read 400 bytes/characters: (The buffer must */
  524.   /* then be at least 400 bytes.)                           */
  525.   ioreq->IOPar.io_Length = 400;
  526.  
  527.   /* Do our request and return immediately: */
  528.   SendIO( ioreq );
  529.  
  530.  
  531.   /* As long as the pointer is not pointing to */
  532.   /* the request we should stay in the loop:   */
  533.   while( ptr == NULL )
  534.   {
  535.     ... do something ...
  536.  
  537.   
  538.     /* Check if the request has been completed: (If the  */
  539.     /* request has been completed CheckIO() will return  */
  540.     /* a pointer to the request, else NULL is returned.) */
  541.     ptr = CheckIO( ioreq );
  542.   }
  543.  
  544.   /* Remove the requst block's message. (The ptr and ioreq */
  545.   /* are in this example identical, so it does not matter  */
  546.   /* whichever you will use. The parenthesis around the    */
  547.   /* expression is actually unnecessary, but this looks    */
  548.   /* better.)                                              */
  549.   Remove( &(ptr->IOPar.io_Message.mn_Node) );
  550.  
  551.   /* Everything OK? Check the io_Error filed: */
  552.   if( ioreq->IOPar.io_Error )
  553.     printf( "Problems while reading!\n" );
  554.  
  555.  
  556.  
  557. 8.3.6  HOW TO HANDLE SEVERAL REQUESTS SIMULTANIOUSLY
  558.  
  559. Since you usually will want to read and write data at the same
  560. time, you have to use two separate request blocks. If you are
  561. using shared access mode you simply create two request blocks
  562. and open the parallel device twice. (Do not forget to close
  563. both requests later on.) Here is an example:
  564.  
  565.   struct MsgPort *replymp;
  566.   struct IOExtPar *parallel_req_read;
  567.   struct IOExtPar *parallel_req_write;
  568.   UBYTE error;
  569.  
  570.      
  571.   /* We use only one reply message port: */
  572.   replymp = (struct MsgPort *)
  573.     CreatePort( NULL, 0 );
  574.   if( !replymp )
  575.     clean_up( "Could not create the reply port!" );
  576.  
  577.  
  578.   /* Create the request block "read": */
  579.   parallel_req_read = (struct IOExtPar *)
  580.     CreateExtIO( replymp, sizeof( struct IOExtPar ) );
  581.   if( !parallel_req_read )
  582.     clean_up( "Not enough memory!" );
  583.   parallel_req_read->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
  584.  
  585.   /* Create the request block "write": */
  586.   parallel_req_write = (struct IOExtPar *)
  587.     CreateExtIO( replymp, sizeof( struct IOExtPar ) );
  588.   if( !parallel_req_write )
  589.     clean_up( "Not enough memory!" );
  590.   parallel_req_write->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
  591.  
  592.  
  593.   /* Open the parallel device for the read request: */
  594.   error = OpenDevice( PARALLELNAME, 0, parallel_req_read, 0 );
  595.   if( error )
  596.     clean_up( "Could not open the parallel device (Read)!" );
  597.  
  598.   /* Open the parallel device for the write request: */
  599.   error = OpenDevice( PARALLELNAME, 0, parallel_req_write, 0 );
  600.   if( error )
  601.     clean_up( "Could not open the parallel device (Write)!" );
  602.  
  603.  
  604.  
  605. If you are using exclusive access mode you can of course not
  606. open the parallel device twice. Instead we have to copy the
  607. first request block to the other request block, byte for byte.
  608. Here is an example:
  609.  
  610.   struct MsgPort *replymp;
  611.   struct IOExtPar *parallel_req_read;
  612.   struct IOExtPar *parallel_req_write;
  613.   BYTE *r_ptr;
  614.   BYTE *w_ptr;
  615.   UBYTE error;
  616.   int loop;
  617.  
  618.      
  619.   /* We use only one reply message port: */
  620.   replymp = (struct MsgPort *)
  621.     CreatePort( NULL, 0 );
  622.   if( !replymp )
  623.     clean_up( "Could not create the reply port!" );
  624.  
  625.  
  626.   /* Create the request block "read": */
  627.   parallel_req_read = (struct IOExtPar *)
  628.     CreateExtIO( replymp, sizeof( struct IOExtPar ) );
  629.   if( !parallel_req_read )
  630.     clean_up( "Not enough memory!" );
  631.   parallel_req_read->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
  632.  
  633.   /* Create the request block "write": */
  634.   parallel_req_write = (struct IOExtPar *)
  635.     CreateExtIO( replymp, sizeof( struct IOExtPar ) );
  636.   if( !parallel_req_write )
  637.     clean_up( "Not enough memory!" );
  638.   parallel_req_write->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
  639.  
  640.  
  641.   /* Open the parallel device for the read request: */
  642.   error = OpenDevice( PARALLELNAME, 0, parallel_req_read, 0 );
  643.   if( error )
  644.     clean_up( "Could not open the Parallel Device (Read)!" );
  645.  
  646.  
  647.   /* Since we can not open the parallel device once again */
  648.   /* for the write request, we have to copy the whole     */
  649.   /* read request block into the write request block.     */
  650.  
  651.   /* Get the start address of both request blocks: */
  652.   r_ptr = (BYTE *) parallel_req_read;
  653.   w_ptr = (BYTE *) parallel_req_write;
  654.  
  655.   /* Copy the request block, byte by byte: */
  656.   for( loop=0; loop < sizeof( struct IOExtPar ); loop++ )
  657.   {
  658.     /* Copy one byte: */
  659.     *w_ptr = *r_ptr;
  660.     
  661.     /* Step one byte forward: */
  662.     w_ptr++;
  663.     r_ptr++;
  664.   }
  665.  
  666.  
  667. Now we have two request blocks, and can therefore use both
  668. read and write requests at the same time. If you also want to
  669. use the special extra functions described further down, you
  670. may want to create even one more request block (or maybe
  671. even more...). The procedure is the same as described above.
  672.  
  673.  
  674.  
  675. 8.3.7  ERRORS
  676.  
  677. While you are using the parallel device you may sometimes
  678. encounter an error message. Usually it is easy to guess what
  679. went wrong, but it is always good to check what really happened.
  680. There exit for the moment seven different types of parallel
  681. port errors, all defined in the header file "devices/
  682. parallel.h".
  683.  
  684. You will either receive the error message from the function you
  685. just called (for example, DoIO() returns 0 or an error number),
  686. or you can check the request block to see if there were any
  687. problems. (The io_Error filed of the request block either
  688. contains 0, which means everything is OK, or an error number.)
  689.  
  690. Here is a complete list of the parallel error messages:
  691.  
  692.   ParErr_DevBusy        Some other task/request is already using
  693.                         the parallel device.
  694.  
  695.   ParErr_BufTooBig:     Buffer too big. Hey, what is this?
  696.  
  697.   ParErr_InvParam:      The request block's parameters were not
  698.                         properly initialized.
  699.  
  700.   ParErr_LineErr:       There were some problems with the
  701.                         communication. The parallel cable is
  702.                         faulty or the other device is not
  703.                         properly initialized or not connected.
  704.                         Tell the user to check the cables!
  705.  
  706.   ParErr_NotOpen:       The parallel device was not open!
  707.  
  708.   ParErr_PortReset:     The parallel device have just been
  709.                         resetted. Someone just sent a CMD_Reset
  710.                         request. Default parameters are
  711.                         set.
  712.  
  713.   ParErr_InitErr:       The parallel device could not be
  714.                         initialized with your requirements.
  715.                         (Probably forgot to clear all unused
  716.                         flags.)
  717.  
  718.  
  719. While you are using the parallel device it may happen that you
  720. also receive error messages from Exec. (Exec is handling all
  721. stuff like messages, requests, tasks and so on.) Here is
  722. a complete list of exec error messages: (defined in the header
  723. file "exec/errors.h")
  724.  
  725. IOERR_OPENFAIL  The device (unit) could not be opened. (If you
  726.                 are denied access to the parallel device you
  727.                 should receive the ParErr_DevBusy flag instead
  728.                 of this exec message, but internally this flag
  729.                 is used.) 
  730.  
  731. IOERR_ABORTED   When you abort a previously started request by
  732.                 calling the AbortIO() function, the io_Error
  733.                 filed of that request is set to IOERR_ABORTED.
  734.                 If you find a request block with this flag set,
  735.                 you know that it has been aborted.
  736.  
  737. IOERR_NOCMD     You tried to use a command that is not
  738.                 supported by the parallel device.
  739.  
  740. IOERR_BADLENGTH The length of the request was not valid.
  741.  
  742.  
  743.  
  744. 8.3.8  CLEAN UP
  745.  
  746. As usual on the Amiga you must remember to close and return
  747. everything you have opened or allocated. If you do not close
  748. the parallel device after you, other programs will then not
  749. be able to use the it. PLEASE be very careful about this!
  750.  
  751. The routine is very similar to how you close the serial device
  752. which was described in the previous chapter. However this is
  753. so important that it can not be said too often.
  754.  
  755. Here is a list of what you have to do:
  756.  
  757.   1. All requests you have started with SendIO() or BeginIO()
  758.      (asynchronous commands) must either have been completed
  759.      or aborted before you may close the device. It is a very
  760.      common error to forget this, and it can be hard to find
  761.      this bug. Usually the program will work fine (the command
  762.      was completed in time), but now and then your program will
  763.      crash (the command was completed after the device have
  764.      been closed).
  765.  
  766.      A simple way is to abort all commands that have not
  767.      reported that they have been completed, but this is not
  768.      always good way to do it. (The last commands may be
  769.      important and should therefore not be aborted.)
  770.      
  771.      If you do not want to abort the command, you should
  772.      instead wait for it to be completed. The WaitIO()
  773.      function is simple to use, and will put your program
  774.      to sleep while waiting, so no computer time is wasted.
  775.      If the request has already been completed, the function
  776.      will return immediately. WaitIO() will also remove the
  777.      message from the reply port. It is a very useful and
  778.      simple function to use, but do NOT try to wait for
  779.      a request that has not been started!
  780.  
  781.      Here is an example on how to wait for a request to be
  782.      completed: (If the request already has been completed
  783.      it does not matter, WaitIO() will then simply return
  784.      immediately. Note that we do not have to remove any
  785.      messages from the reply port if we use WaitIO().)
  786.  
  787.        /* Store possible error numbers here: */
  788.        UBYTE error;
  789.      
  790.        /* ... */
  791.      
  792.        /* Wait for the request to be completed: */
  793.        error = WaitIO( ioreq );
  794.      
  795.        /* Everything OK? */
  796.        if( error )
  797.          printf( "Something went wrong!" );
  798.  
  799.        /* Well, successful or not, we may now */
  800.        /* close the device!                   */
  801.  
  802.  
  803.      To abort a request, simply use the AbortIO() function:
  804.  
  805.        /* Try to abort a previously started request:  */
  806.        /* (Do not try to abort a request that has not */
  807.        /* been started.)                              */
  808.        AbortIO( ioreq );
  809.  
  810.  
  811.   2. When all requests have been completed or aborted you may
  812.      close the parallel device. (Requests that have been
  813.      executed by calling the DoIO() function have already been
  814.      completed before your program wakes up, and thus you do
  815.      not need to wait for these.)
  816.      
  817.      The parallel device is closed as all other devices, by
  818.      calling the CloseDevice() function. Here is an example:
  819.  
  820.        /* Close the Parallel Device: */ 
  821.        if( !parallel_dever )
  822.          CloseDevice( ioreq );
  823.  
  824.  
  825.   3. You should now return all request blocks you have
  826.      allocated. If you allocated a standard sized request block
  827.      by calling the CreateStdIO() function, you should free
  828.      it by calling the DeleteStdIO() function. However, if
  829.      you have allocated an extended request block (like the
  830.      parallel device's request blocks) by calling the
  831.      CreateExtIO() function, you MUST call the DeleteExtIO(),
  832.      and of course remove the same amount of data as you
  833.      allocated.
  834.      
  835.      How to delete a standard request block: (Since it is of
  836.      the standard size, you do not need to specify any size.)
  837.      
  838.        /* Deallocate a standard sized request block: */
  839.        DeleteStdIO( ioreq );
  840.  
  841.      With extended request block you have to specify the size
  842.      as you did when you allocated it:
  843.  
  844.        /* Deallocate an extended request block: */
  845.        /* (The size may vary depending on what  */
  846.        /* device it was used for.)              */
  847.        DeleteExtIO( ioreq, sizeof( struct IOExtSer ) );
  848.  
  849.      Note that ALL request blocks that have been allocated,
  850.      must be removed!
  851.  
  852.  
  853.   4. Finally you should close all message ports you have
  854.      previously opened. Simply use the DeletePort() function
  855.      as this example demonstrates:
  856.  
  857.        /* Remove the replyport: */
  858.        DeletePort( replymp);
  859.  
  860.  
  861. Please be careful with how your program terminates! Your
  862. program should not only run fine, but it should also allow
  863. other programs to run after and simultaneously. Remember that
  864. your program must also be able to quit nice and neatly even if
  865. it had to terminate too early because of some fatal error. The
  866. cleaning up should only be done where it is needed, and if you
  867. have not allocated the memory or opened the device before your
  868. program quits, you should of course NOT try to free these
  869. resources! If you do the Amiga will most certainly crash! Too
  870. many programs contain this very annoying error. Make sure yours
  871. will not be the same.
  872.  
  873. The best way to manage this cleaning up routine is to write a
  874. separate function which checks each thing before it frees it.
  875. The idea is that you may call this routine at any time, and it
  876. will still manage to clear everything properly. Here is an
  877. example: (Note how we check each thing to see if it should be
  878. removed!)
  879.  
  880.   /* Close and return everything that has been */
  881.   /* opened and allocated before we quit:      */
  882.   void clean_up()
  883.   {
  884.     /* 1. Close the Parallel Device: */ 
  885.     if( !parallel_dever )
  886.       CloseDevice( parallel_req );
  887.   
  888.     /* 2. Deallocate the parallel request block: */
  889.     if( parallel_req )
  890.       DeleteExtIO( parallel_req, sizeof( struct IOExtPar ) );
  891.   
  892.     /* 3. Remove the replyport: */
  893.     if( replymp )
  894.       DeletePort( replymp);
  895.   
  896.     /* 4. Quit: */
  897.     exit( 0 );
  898.   }
  899.  
  900. Comments: 1. The parallel_dever is a variable that we have
  901.              declared ourself, and is used only to determine
  902.              if the device has been opened or not. (The
  903.              variable is set to TRUE before the program
  904.              starts, and is only changed to FALSE after
  905.              a successful opening of the device. See the
  906.              included examples for more information.) We
  907.              should of course only close the device if
  908.              the parallel_dever is FALSE. ("parallel_dever"
  909.              stands for "parallel device error".)
  910.  
  911.           2. The parallel_req is a pointer which is either
  912.              pointing to a request block, or NULL if no
  913.              request block has been allocated. We should
  914.              of course only free the request block if there
  915.              exist one.
  916.  
  917.           3. The replymp is a pointer which is either
  918.              pointing to a message port, or NULL if no message
  919.              port has been opened. And of course, we should
  920.              only close the message port if it has been
  921.              opened.
  922.  
  923.           4. Finally our program may terminate. The exit()
  924.              function is placed here so we are sure the 
  925.              program will quit. (If we did not have this
  926.              exit(), our function would then return the
  927.              control to our program again, and then we would
  928.              be in deep s*#^%.)
  929.  
  930.  
  931.  
  932. 8.4  A COMPLETE EXAMPLE
  933.  
  934. Here is a complete example that opens the parallel device, sets
  935. all necessary parameters, sends some data, collects some data
  936. (well actually only 0 bytes) and finally cleans up and quits.
  937. Since we send the read and write requests after each other (the
  938. first is completed before the other is started) we only need to
  939. use one request block.
  940.  
  941.  
  942. #include <exec/types.h>
  943. #include <devices/parallel.h>
  944.  
  945.  
  946. /* Declare a pointer to our reply port: */
  947. struct MsgPort *replymp = NULL;
  948.  
  949. /* Declare a pointer to our parallel request block: */
  950. struct IOExtPar *parallel_req = NULL;
  951.  
  952. /* Store the parallel device error here: */
  953. UWORD parallel_dever = TRUE;
  954.  
  955. /* Declare our own data buffer: */
  956. /* (Last byte is a NULL sign.)  */
  957. BYTE buffer[] = "Anders Bjerin was here...";
  958.  
  959.  
  960. /* Declare our functions: */
  961. void main();
  962. void clean_up( STRPTR text );
  963.  
  964. void main()
  965. {
  966.   int loop;
  967.   UBYTE *ptr;
  968.   UBYTE error;
  969.  
  970.   /* The eight end-of-file characters: */
  971.   UBYTE eof_char[8]={ 0x00, 0x00, 0x00, 0x00,
  972.                       0x00, 0x00, 0x00, 0x00 };
  973.  
  974.  
  975.   
  976.   /* OPEN THE PARALLEL DEVICE: */
  977.  
  978.   /* Get a reply port: (No name, priority 0) */
  979.   replymp = (struct MsgPort *)
  980.     CreatePort( NULL, 0 );
  981.   if( !replymp )
  982.     clean_up( "Could not create the reply port!" );
  983.  
  984.   /* Create a parallel request block: */
  985.   parallel_req = (struct IOExtPar *)
  986.     CreateExtIO( replymp, sizeof( struct IOExtPar ) );
  987.   if( !parallel_req )
  988.     clean_up( "Not enough memory for the parallel request block!" );
  989.  
  990.  
  991.   /* Since we want exclusive access mode, we do not set the */
  992.   /* parallel flag "PARF_SHARED", which otherwise must have */
  993.   /* been set before the device is opened. To make sure the */
  994.   /* field is empty we set it to 0:                         */
  995.   parallel_req->io_ParFlags = 0;
  996.  
  997.  
  998.   /* Open the Parallel Device: */
  999.   parallel_dever = OpenDevice( PARALLELNAME, 0, parallel_req, 0 );
  1000.   if( parallel_dever )
  1001.     clean_up( "Could not open the Parallel Device!" );
  1002.  
  1003.  
  1004.  
  1005.   
  1006.   /* SET THE REST OF THE PARALLEL PARAMETERS (not many): */
  1007.   
  1008.   /* Check for end-of-file characters: */
  1009.   parallel_req->io_ParFlags = PARF_EOFMODE;
  1010.  
  1011.   /* No additional flags: */
  1012.   parallel_req->io_PExtFlags = NULL;
  1013.   
  1014.   /* Set all eight end of file characters: */
  1015.   ptr = (UBYTE *) &(parallel_req->io_PTermArray);
  1016.   for( loop=0; loop < 8; loop++ )
  1017.   {
  1018.     /* Copy character after character: */
  1019.     *ptr = eof_char[ loop ];
  1020.  
  1021.     /* Step one byte forward: */
  1022.     ptr++;
  1023.   }
  1024.   
  1025.   /* All values have now been set, lets */
  1026.   /* do a PDCMD_SETPARAMS request:      */
  1027.   parallel_req->IOPar.io_Command = PDCMD_SETPARAMS;
  1028.   
  1029.   /* Do our request: */
  1030.   error = DoIO( parallel_req );
  1031.   if( error )
  1032.     clean_up( "Could not set the parallel parameters!" );
  1033.  
  1034.  
  1035.  
  1036.   /* SEND DATA TO THE PARALLEL PORT: */
  1037.  
  1038.   /* We want to send (write) some data: */
  1039.   parallel_req->IOPar.io_Command = CMD_WRITE;
  1040.  
  1041.   /* Give the start address of our data: */
  1042.   parallel_req->IOPar.io_Data = (APTR) buffer;
  1043.  
  1044.   /* We want to send data until we find a NULL sign: */
  1045.   /* (The NULL sign was specified in the EOF-char.)  */
  1046.   parallel_req->IOPar.io_Length = -1;
  1047.  
  1048.   /* Do our request: */
  1049.   error = DoIO( parallel_req );
  1050.   if( error )
  1051.     clean_up( "Could not send data to the parallel port!" );
  1052.  
  1053.  
  1054.  
  1055.   /* READ DATA FROM THE PARALLEL DEVICE: */
  1056.   
  1057.   /* We want to read some data: */
  1058.   parallel_req->IOPar.io_Command = CMD_READ;
  1059.  
  1060.   /* Give the start address of our buffer: */
  1061.   parallel_req->IOPar.io_Data = (APTR) buffer;
  1062.  
  1063.   /* We want to read 0 bytes: */
  1064.   /* (Since most of you do not have anything which sends data */
  1065.   /* to the parallel device, I do not want to wait for more   */
  1066.   /* than 0 bytes to arrive.)                                 */
  1067.   parallel_req->IOPar.io_Length = 0;
  1068.  
  1069.   /* Do our request: */
  1070.   error = DoIO( parallel_req );
  1071.   if( error )
  1072.     clean_up( "Could not read data from the parallel port!" );
  1073.  
  1074.  
  1075.  
  1076.   /* THE END: */
  1077.   clean_up( "The End" );
  1078. }
  1079.  
  1080.  
  1081. /* Close and return everything that has been */
  1082. /* opened and allocated before we quit:      */
  1083. void clean_up( STRPTR text )
  1084. {
  1085.   /* Close the Parallel Device: */
  1086.   if( !parallel_dever )
  1087.     CloseDevice( parallel_req );
  1088.  
  1089.   /* Deallocate the parallel request block: */
  1090.   if( parallel_req )
  1091.     DeleteExtIO( parallel_req, sizeof( struct IOExtPar ) );
  1092.  
  1093.   /* Remove the replyport: */
  1094.   if( replymp )
  1095.     DeletePort( replymp);
  1096.  
  1097.   /* Print the message: */
  1098.   printf( "\n%s\n", text );
  1099.  
  1100.   /* Quit: */
  1101.   exit( 0 );
  1102. }
  1103.  
  1104.  
  1105. 8.5  OTHER USEFUL COMMANDS
  1106.  
  1107. Although reading and writing are most commonly used commands,
  1108. there exist some other functions that can sometimes be needed.
  1109. Here is a complete list of commands that can be sent with help
  1110. of a request block:
  1111.  
  1112.   1. Flush, removes all queued requests.
  1113.   2. Query, get some information from the parallel device.
  1114.   3. Reset, reinitializes the parallel device.
  1115.   4. Start, restarts the parallel communication.
  1116.   5. Stop, temporary stops the parallel communication.
  1117.  
  1118.  
  1119.  
  1120. 8.5.1  FLUSH
  1121.  
  1122. If several requests are sent to the parallel device they are
  1123. all queued on a FIFO (First In First Out) basis. The command
  1124. "CMD_FLUSH" can then be used to remove all these queued
  1125. commands. Here is an example:
  1126.  
  1127.   /* We want to remove all queued requests: */
  1128.   ioreq->IOPar.io_Command = CMD_FLUSH;
  1129.  
  1130.   /* Do our request: */
  1131.   error = DoIO( ioreq );
  1132.  
  1133.   /* OK? */
  1134.   if( error )
  1135.     printf( "Could not remove the queued requests!\n" );
  1136.  
  1137.  
  1138.  
  1139. 8.5.2  QUERY
  1140.  
  1141. The command "PDCMD_QUERY" can be used to get some information
  1142. from the parallel device. It is useful if you want to see if
  1143. the paper is out, printer is busy or if it is currently writing
  1144. or reading. All this can be found in the "io_Status" field of
  1145. the request structure, as this table shows:
  1146.  
  1147.   Name           Bit  Hex   Active  Description
  1148.   ------------------------------------------------------------
  1149.   IOPTF_PARBUSY    0  0x01  Low     Printer is selected
  1150.   IOPTF_PAPEROUT   1  0x02  Low     Paper out
  1151.   IOPTF_PARSEL     2  0x04  Low     Printer is busy
  1152.   IOPTF_RWDIR      3  0x08  -       Reading (0) or Writing (1) 
  1153.   -                4  0x10  -       Reserved
  1154.   -                5  0x20  -       Reserved
  1155.   -                6  0x40  -       Reserved
  1156.   -                7  0x80  -       Reserved
  1157.   ------------------------------------------------------------
  1158.  
  1159. Here is an example:
  1160.  
  1161.   /* Check the parallel device: */
  1162.   ioreq->IOPar.io_Command = PDCMD_QUERY;
  1163.  
  1164.   /* Do our request: */
  1165.   error = DoIO( ioreq );
  1166.  
  1167.   /* OK? */
  1168.   if( error )
  1169.     printf( "Could not get any information from the device!\n" );
  1170.   else
  1171.   {
  1172.     /* Check the "io_Status" field: */
  1173.     if( ioreq->io_Status & IOPTF_PARBUSY )
  1174.       printf( "Printer is busy.\n" );
  1175.  
  1176.     if( ioreq->io_Status & IOPTF_PAPEROUT )
  1177.       printf( "Paper out!\n" );
  1178.  
  1179.     if( ioreq->io_Status & IOPTF_PARSEL )
  1180.       printf( "Printer selected!\n" );
  1181.  
  1182.     printf( "Device is %s\n",
  1183.       ioreq->io_Status & IOPTF_RWDIR ? "Writing" : "Reading" ); 
  1184.   }
  1185.  
  1186.  
  1187.  
  1188. 8.5.3  RESET
  1189.  
  1190. Send the command "CMD_RESET" to reset the parallel device. All
  1191. commands that are queued to the device will be removed, commands
  1192. that are currently executed will be aborted all parallel flags
  1193. are resetted. Here is an example:
  1194.  
  1195.   /* We want to reset the parallel device: */
  1196.   ioreq->IOPar.io_Command = CMD_RESET;
  1197.  
  1198.   /* Do our request: */
  1199.   error = DoIO( ioreq );
  1200.  
  1201.   /* OK? */
  1202.   if( error )
  1203.     printf( "Could not reset the parallel device!\n" );
  1204.  
  1205.  
  1206.  
  1207. 8.5.4  START
  1208.  
  1209. After you have stopped the parallel communication by sending an
  1210. CMD_STOP command, you may want to start the communication again.
  1211. It is done by sending a CMD_START command. Here is an example:
  1212.  
  1213.   /* We want to start parallel communication again: */
  1214.   ioreq->IOPar.io_Command = CMD_START;
  1215.  
  1216.   /* Do our request: */
  1217.   error = DoIO( ioreq );
  1218.  
  1219.   /* OK? */
  1220.   if( error )
  1221.     printf( "Could not start the parallel communication!\n" );
  1222.  
  1223.  
  1224.  
  1225. 8.5.5  STOP
  1226.  
  1227. To temporary stop all parallel communication you send a CMD_STOP
  1228. command. The communication will then first start again when a
  1229. CMD_START command is broadcasted. Here is an example:
  1230.  
  1231.   /* We want to temporary stop all parallel communication: */
  1232.   ioreq->IOPar.io_Command = CMD_STOP;
  1233.  
  1234.   /* Do our request: */
  1235.   error = DoIO( ioreq );
  1236.  
  1237.   /* OK? */
  1238.   if( error )
  1239.     printf( "Could not stop the parallel communication!\n" );
  1240.  
  1241.  
  1242.  
  1243. 8.6  FUNCTIONS
  1244.  
  1245.  
  1246. DoIO()
  1247.  
  1248.   DoIO() is used to send requests to a device, and waits for it
  1249.   to be completed. While the program is waiting it is put to
  1250.   sleep so it will not waste any computer time. DoIO() will
  1251.   return first when the request have been completed or failed,
  1252.   and no message is therefore sent to the reply port.
  1253.  
  1254.   Synopsis: error = DoIO( req );
  1255.  
  1256.   error:    (long) DoIO() will return first when the request has
  1257.             been completed or something has failed. If the
  1258.             request was successfully completed zero is returned,
  1259.             else an error number is returned. What error number
  1260.             depends on which device was used.
  1261.  
  1262.   req:      (struct IORequest *) Pointer to the request you
  1263.             want to have executed.
  1264.  
  1265.  
  1266. SendIO()
  1267.  
  1268.   SendIO() is used to send requests to a device, but will
  1269.   return immediately without any delay. To check if the request
  1270.   have been completed use the CheckIO() function, or look
  1271.   at the request's reply port for any messages. Once the
  1272.   request has been completed you must remove the message at
  1273.   the reply port. (CheckIO() will not do it.) To remove a
  1274.   message use the function Remove(). Note that you may NOT
  1275.   close the device before all requests have been completed or
  1276.   aborted!
  1277.  
  1278.   Synopsis: SendIO( req )
  1279.  
  1280.   req:      (struct IORequest *) Pointer to the request you
  1281.             want to have executed.
  1282.  
  1283.  
  1284. CheckIO()
  1285.  
  1286.   CheckIO() is used to check if a previously started request
  1287.   has been completed. Note that this function will not remove
  1288.   the message at the reply port. This must be done with the
  1289.   Remove() function.
  1290.  
  1291.   Synopsis: ptr = CheckIO( req );
  1292.  
  1293.   ptr:      (long) CheckIO() will either return NULL if the
  1294.             request have not been completed or it will return a
  1295.             pointer to the request block.
  1296.  
  1297.   req:      (struct IORequest *) Pointer to the request you
  1298.             want to check.
  1299.  
  1300.  
  1301. WaitIO()
  1302.  
  1303.   WaitIO() will wait for the request to be completed, and while
  1304.   the program is waiting it is put to sleep so no computer time
  1305.   is wasted.
  1306.  
  1307.   Synopsis: error = WaitIO( req );
  1308.  
  1309.   error:    (long) WaitIO() will return first when the request,
  1310.             that has previously been sent, has been completed or
  1311.             something has failed. If the request was successfully
  1312.             completed zero is returned, else an error number is
  1313.             returned. What error number depends on which device
  1314.             was used.
  1315.  
  1316.   req:      (struct IORequest *) Pointer to the request you
  1317.             want to wait for to be completed. Note that the
  1318.             request must have already been sent to the device
  1319.             by either a SendIO() or BeginIO() function call.
  1320.  
  1321.  
  1322. BeginIO()
  1323.  
  1324.   BeginIO() is a low level form of the SendIO() function. The
  1325.   advantage with BeginIO() is that no fields of the request
  1326.   block will be altered as which is the case with SendIO().
  1327.   With the parallel device you should only use SendIO().
  1328.  
  1329.   Synopsis: BeginIO( req )
  1330.  
  1331.   req:      (struct IORequest *) Pointer to the request you
  1332.             want to have executed.
  1333.  
  1334.  
  1335. AbortIO()
  1336.  
  1337.   AbortIO() will try to abort a previously started request. This
  1338.   function should be used sparsely since it does not look so
  1339.   good if you start a request and the try to stop it. (Better
  1340.   not start it at all.) However, it is easy, and can sometimes
  1341.   be very useful.
  1342.  
  1343.   A request that is aborted will have its io_Error field set
  1344.   to IOERR_ABORTED (defined in header file "exec/errors.h").
  1345.  
  1346.   Synopsis: AbortIO( req )
  1347.  
  1348.   req:      (struct IORequest *) Pointer to the request you
  1349.             want to abort.
  1350.  
  1351.  
  1352. CloseDevice()
  1353.  
  1354.   CloseDevice() will (surprise!) close a device. Note that you
  1355.   should NOT close the device before all started asynchronous
  1356.   requests have either been completed or aborted.
  1357.   
  1358.   Synopsis: CloseDevice( ioreq );
  1359.  
  1360.   ioreg:    (struct IORequest *) Pointer to the device's
  1361.             request block.
  1362.  
  1363.  
  1364. OpenDevice()
  1365.  
  1366.   OpenDevice() will try to open the specified device.
  1367.   
  1368.   Synopsis: error = OpenDevice( name, unit, req, flags );
  1369.  
  1370.   error:    (long) If OpenDevice() managed to open the device
  1371.             it returns 0, else an error number is returned.
  1372.             If you try to open the parallel device, and there is
  1373.             already a program that is using it, the error
  1374.             message "ParErr_DevBusy" is returned.
  1375.  
  1376.   name:     (char *) Name of the device you want to open.
  1377.             The name of the parallel device is defined as
  1378.             PARALLELNAME in header file "devices/parallel.h".
  1379.  
  1380.   unit:     (long) Which unit you want to open. Since there
  1381.             exist only one parallel port, this field is ignored.
  1382.  
  1383.   req:      (struct IORequest *) Pointer to a request block.
  1384.             For the parallel device it must be a pointer to an
  1385.             extender parallel request block (struct IOExtPar).
  1386.  
  1387.   flags:    (long) Any special mode is set here. Ignored by
  1388.             the parallel device.
  1389.  
  1390.  
  1391.  
  1392. 8.7  COMMANDS
  1393.  
  1394. Here is a complete list of commands you may send to the
  1395. parallel device. For full documentation se examples above.
  1396.  
  1397. The special parallel device commands: (Defined in header file
  1398. "devices/parallel.h")
  1399.  
  1400.   PDCMD_QUERY      Check the status of the parallel device.
  1401.   PDCMD_SETPARAMS  Set the parameters of the parallel device.
  1402.  
  1403.  
  1404. The rest of the commands you may use are normal exec commands,
  1405. and are defined in header file "exec/io.h".
  1406.  
  1407.   CMD_RESET  Resets all parameters of the parallel device.
  1408.   CMD_READ   Read data from the parallel port.
  1409.   CMD_WRITE  Write data to the parallel port.
  1410.   CMD_STOP   Temporary stops all parallel communication.
  1411.   CMD_START  Restarts parallel communication.
  1412.   CMD_FLUSH  Removes all queued requests.
  1413.  
  1414.  
  1415.  
  1416. 8.8  EXAMPLES
  1417.  
  1418. Example 1
  1419.   This program demonstrates how you can use the Parallel Device.
  1420.   It does not do very much since I do not know what you have
  1421.   connected to your parallel port, but with small modifications
  1422.   you should be able to write your own parallel communication
  1423.   packages.
  1424.  
  1425. Example 2
  1426.   This example is rather similar to Example 1, but this time
  1427.   we do not wait for the parallel port to complete our request.
  1428.   Instead we do somethings (well not very much) and now and
  1429.   then checks if the request has been completed.
  1430.  
  1431. Example 3
  1432.   This example is rather similar to Example 1, but this time
  1433.   we do not wait for the parallel port to complete our request.
  1434.   We are also trying to read and write at the same time. To be
  1435.   able to do several requests simultaneously we need one request
  1436.   block for each command. In this example we use three separate
  1437.   request blocks.
  1438.  
  1439. Example4
  1440.   This example does not do anything, but it consists of
  1441.   several useful functions that you can use yourself after
  1442.   small modifications. The functions demonstrates all
  1443.   commands there exist for the parallel device, so if you
  1444.   had problems in understanding how a command was used you
  1445.   can look here.
  1446.  
  1447.  
  1448.