Once a device has been opened, you use it by passing the I/O request to it. When the device processes the I/O request, it acts on the information the I/O request contains and returns a reply message, i.e., the I/O request, to the message port when it is finished. The I/O request is passed to a device using one of three functions, DoIO(), SendIO() and BeginIO(). They take only one argument: the I/O request you wish to pass to the device. * DoIO() is a synchronous function. It will not return until the device has finished with the I/O request. DoIO() will wait, if necessary, for the request to complete, and will remove (GetMsg()) any reply message from the message port. * SendIO() is an asynchronous function. It can return immediately, but the I/O operation it initiates may take a short or long time. SendIO is normally used when your application has other work to do while the I/O request is being acted upon, or if your application wishes to allow the user to cancel the I/O. Using SendIO() requires that you wait on or check for completion of the request, and remove the completed request from the message port with GetMsg(). * BeginIO() is commonly used to control the QuickIO bit when sending an I/O request to a device. When the QuickIO flag (IOF_QUICK) is set in the I/O request, a device is allowed to take certain shortcuts in performing and completing a request. If the request can complete immediately, the device will not return a reply message and the QuickIO flag will remain set. If the request cannot be completed immediately, the QUICK_IO flag will be clear. DoIO() normally requests QuickIO; SendIO() does not. An I/O request typically has three fields set for every command sent to a device. You set the command itself in the io_Command field, a pointer to the data for the command in the io_Data field, and the length of the data in the io_Length field. SerialIO->IOSer.io_Length = sizeof(ReadBuffer); SerialIO->IOSer.io_Data = ReadBuffer; SerialIO->IOSer.io_Command = CMD_READ; SendIO((struct IORequest *)SerialIO); Commands consist of two parts (separated by an underscore, all in upper case): a prefix and the command word. The prefix indicates whether the command is an Exec or device specific command. All Exec standard commands have "CMD" as the prefix. They are defined in the include file <exec/io.h>. Table 19-2: Standard Exec Device Commands CMD_READ CMD_START CMD_UPDATE CMD_CLEAR CMD_WRITE CMD_STOP CMD_FLUSH CMD_RESET You should not assume that a device supports all standard Exec device commands. Always check the documentation before attempting to use one of them. Device-specific command prefixes vary with the device. Table 19-3: System Device Command Prefixes Device Prefix Example ------ ------ ------- Audio ADCMD ADCMD_ALLOCATE Clipboard CBD CBD_POST Console CD CD_ASKKEYMAP Gameport GPD GPD_SETCTYPE Input IND IND_SETMPORT Keyboard KBD KBD_READMATRIX Narrator no device specific commands - Parallel PDCMD PDCMD_QUERY Printer PRD PRD_PRTCOMMAND SCSI HD HD_SCSICMD Serial SDCMD SDCMD_BREAK Timer TR TR_ADDREQUEST Trackdisk TD and ETD TD_MOTOR/ETD_MOTOR Each device maintains its own I/O request queue. When a device receives an I/O request, it either processes the request immediately or puts it in the queue because one is already being processed. After an I/O request is completely processed, the device checks its queue and if it finds another I/O request, begins to process that request. Synchronous Vs. Asynchronous Requests I/O Request Completion