CPGuide - Device I/O: Difference between revisions
mNo edit summary |
mNo edit summary |
||
Line 60: | Line 60: | ||
Before using DosDevIOCtl, the application or subsystem must first obtain the device handle by calling DosOpen for the device name. The opened device handle is used to specify the device the command is to go to. | Before using DosDevIOCtl, the application or subsystem must first obtain the device handle by calling DosOpen for the device name. The opened device handle is used to specify the device the command is to go to. | ||
Refer to the Control Program Programming Reference for details of DosDevIOCtl. | Refer to the [[Control Program Programming Reference]] for details of DosDevIOCtl. | ||
===IOCtl Commands=== | ===IOCtl Commands=== |
Revision as of 14:11, 7 April 2020
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
Devices used with computers include the keyboard, video display, mouse, floppy and fixed disk drives, and external systems, such as modems and printers. This chapter describes the OS/2 functions used to access and control such devices.
The following topics are related to the information in this chapter:
- File systems
- File names
- File management
- Semaphores
About Device I/O
OS/2 uses devices to communicate with the real world. A device is a piece of hardware used for input and output. The keyboard and screen are devices, as are serial and parallel ports. The computer's speaker, which can be made to beep using DosBeep, is a device.
Accessing Devices
OS/2 applications usually communicate with devices through OS/2. Some devices, like the screen, have their own set of supporting functions. Most other devices can be accessed by using the standard OS/2 file system functions- DosOpen, DosRead, DosWrite, and DosClose. Using the file system functions, an application can open and access the device just as it would a disk file. Using the file system also enables applications to redirect the device's I/O stream.
Sometimes however, these higher-level approaches do not suffice. For these situations, OS/2 provides several functions that interface with devices at a lower level. DosDevConfig is used to retrieve information about the devices available. DosPhysicalDisk can be used to retrieve information about a partitionable hard disk. DosDevIOCtl is used to send device-specific commands directly to a particular device driver.
Device Names
To open a device using DosOpen, the application must supply the reserved name for that device. For example, to open the console (both keyboard and screen), you must specify the name CON.
The following table shows some of the common reserved device names:
Device Name | Description |
---|---|
CON | The system console. This device consists of both the keyboard and the screen. You can open CON for reading (from the keyboard), writing (to the screen), or both. |
COM1 | Serial port 1. You can open this device for reading, writing, or both. Other serial ports will have names in ascending sequence-COM2, COM3, and so on. |
PRN | The default printer port. This device corresponds to one of the system's parallel ports, usually LPT1. You can open it for writing but not for reading. |
LPT1 | Parallel port 1. You can open this device for writing but not for reading. Other parallel ports will have names in ascending sequence-LPT2, LPT3, and so on. |
NUL | The null device. This device provides a method of discarding output. If you open this device for writing, any data written to the file is discarded. If you open the device for reading, any attempt to read from the file returns an end-of-file mark. |
SCREEN$ | The screen. This device can be written to but not read from. Writing to the screen is similar to writing to the system console. Bytes are displayed as characters (unless the ANSI screen driver is loaded and the character represents an ANSI escape sequence). |
KBD$ | The keyboard. This device can be read from but not written to. Reading from the keyboard is similar to reading from the system console. |
After an application uses a device, it should close it by using DosClose.
Device Drivers
OS/2 communicates with devices through special programs called device drivers. A device driver acts as an interface between OS/2, together with its applications, and a physical device such as the keyboard, mouse, or printer. The device driver sends data to and receives data from a device, resolving device-independent requests from applications with the device-specific attributes of the device.
The primary method of communication between OS/2 and a device driver is request packets. OS/2 receives I/O requests from applications and sends data in the form of request packets to the device driver. The device driver communicates with the device either directly or through the BIOS and ABIOS interfaces. (Applications can communicate with device drivers also, by using DosDevIOCtl. See IOCtl Interface)
Devices work differently depending on the device driver installed. For example, if an application writes to the system console, each byte is interpreted as a character and is displayed on the screen. If, however, the ANSI display driver is loaded, some byte sequences direct the system to carry out certain actions on the screen, such as moving the cursor or clearing the screen. These byte sequences are called ANSI escape sequences.
Some devices are available to applications only if the appropriate device driver is installed. For example, an application cannot open a serial port unless a communications device driver, such as COM.SYS, has been loaded by using a DEVICE= command in CONFIG.SYS.
IOCtl Interface
Many devices have more than one operating mode. For example, a serial port typically can operate at a variety of bit rates (sometimes called baud rates). Because the modes are unique to each device, OS/2 does not include specific functions to set or retrieve these modes. Instead OS/2 provides an I/O Control (IOCtl) interface to enable applications to control devices by communicating directly with the device driver.
The IOCtl interface is a method that an application or subsystem can use to send device-specific control commands to a device driver. The IOCtl interface function for OS/2 applications is DosDevIOCtl.
DosDevIOCtl provides a generic, expandable IOCtl facility. Applications send commands and data to the device driver with DosDevIOCtl. The OS/2 kernel reformats the generic IOCtl packets into request packets then calls the device driver. The device driver then carries out the specified action. IOCtl commands can be sent to both block and character device drivers.
Before using DosDevIOCtl, the application or subsystem must first obtain the device handle by calling DosOpen for the device name. The opened device handle is used to specify the device the command is to go to.
Refer to the Control Program Programming Reference for details of DosDevIOCtl.
IOCtl Commands
DosDevIOCtl has many subfunctions. These are called generic IOCtl commands and typically are used to retrieve data from a device driver that is not available through standard OS/2 functions. For example, an application can use these functions to set the bit rate of a serial port or read input directly from a sector on a disk.
Category and Function Codes
Each IOCtl function has a category and a function code. The category defines the type of device to be accessed. OS/2 has several predefined categories. In general, all codes in the range 0x0000 through 0x007F are reserved for predefined categories. A device driver can use additional categories, but they must be explicitly defined by the device and be in the range 0x0080 through 0x00FF.
In each category, a function code defines the action to carry out, such as reading from or writing to the device and retrieving or setting the device modes. The number and meaning of each function code depend on the device driver and the specified category.
Parameter and Data Packets=
DosDevIOCtl uses a parameter packet and a data packet to pass information to and from the device driver. The packets can vary in format and length, depending on the IOCtl function. Simple functions might use only a single variable, while more complex functions might require a more complex data structure for the parameter packet, the data packet, or both.
Using the File Systems to Access Devices
An application can use the OS/2 file system functions-DosOpen, DosRead, DosWrite, and DosClose-with the standard (predefined) devices. The application simply specifies the name of the device in the call to DosOpen, then uses the returned handle to read from and write to the device. When the application has finished using the device, the application should close the device handle by using DosClose.
The following code fragment shows how an application can open the COM1 device (serial port 1) and write the contents of a disk file to the communications port:
#define INCL_DOSFILEMGR /* File System values */ #define INCL_DOSDEVIOCTL /* DosDevIOCtl values */ #include <os2.h> BYTE abBuf[512]; HFILE hfCom, hfFile; ULONG ulAction, cbRead, cbWritten; DosOpen("COM1", &hfCom, &ulAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); DosOpen("testfile", &hfFile, &ulAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE, (PEAOP2) NULL); do { DosRead(hfFile, abBuf, sizeof(abBuf), &cbRead); DosWrite(hfCom, abBuf, cbRead, &cbWritten); } while(cbRead); DosClose(hfCom); DosClose(hfFile);
- Note
- In this example code fragment and the ones that follow, error checking was left out to conserve space. Applications should always check the return code that the functions return. Control Program functions return an APIRET value. A return code of 0 indicates success. If a non-zero value is returned, an error occurred.
Using IOCtl Functions to Access Devices
Many OS/2 functions communicate with devices. Usually, this communication is transparent to the application (the application has no knowledge of how the communication actually occurs). At times, however, an application requires more direct access to a device. To accommodate this need, OS/2 furnishes DosDevIOCtl. Applications can use DosDevIOCtl to send commands and data to a device driver; the device driver interprets these commands and sends the appropriate instructions to the physical device.
As an example, some devices have several operating modes. A communications port can operate at one of a number of bit rates and have several data-word formats. The actual commands to set these parameters might vary, depending on the communications hardware.
Named constants have been defined for the categories, functions, and commands that are passed to a device driver, to make it easier for application programmers to use DosDevIOCtl. These named constants are defined in the file BSEDEV.H. This file must be included in your application when you use the constants. This file also contains data structure definitions for the parameter and data packets commonly used with DosDevIOCtl. The following examples use the communications port to demonstrate how DosDevIOCtl works.
Setting Communications-Port Parameters
You can use DosDevIOCtl to control the data parameters (bit rate, stop bits, parity, and data bits) of a communications port and to get the status of the COM port. The IOCTL_ASYNC category is used for communications-port control. The ASYNC_SETBAUDRATE function sets the COM port transmission rate. The ASYNC_GETCOMMSTATUS returns the COM port status-byte.
Setting the Data Rate
The ASYNC_SETBAUDRATE function sets the bit rate of a communications port.
The following code fragment sets the bit rate of COM1 to 9600 bits per second:
#define INCL_DOSFILEMGR /* File System values */ #define INCL_DOSDEVIOCTL /* DosDevIOCtl values */ #include <os2.h> HFILE hf; /* File handle for the device */ USHORT usBPS = 9600; /* Bit rate to set the COM port to */ ULONG ulParmLen = 2; /* Maximum size of the parameter packet */ ULONG ulAction; /* Action taken by DosOpen */ APIRET ulrc; /* Return code */ ulrc = DosOpen("COM1", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); ulrc = DosDevIOCtl(hf, /* Device handle */ IOCTL_ASYNC, /* Serial-device control */ ASYNC_SETBAUDRATE, /* Sets bit rate */ (PULONG) &usBPS, /* Points at bit rate */ sizeof(usBPS), /* Maximum size of parameter list */ &ulParmLen, /* Size of parameter packet */ NULL, /* No data packet */ 0, /* Maximum size of data packet */ NULL); /* Size of data packet */ . . /* Use the COM port here. */ . ulrc = DosClose(hf);
Getting teh COM Port Transmission Status
The ASYNC_GETCOMMSTATUS function get the transmission status of the specified COM port. This function has no parameter packet.
The following code fragment uses the ASYNC_GETCOMMSTATUS function to get the transmission status of COM1:
#define INCL_DOSFILEMGR /* File System values */ #define INCL_DOSDEVIOCTL /* DosDevIOCtl values */ #include <os2.h> HFILE hf; /* File handle for the device */ UCHAR ucStatus; /* The COM port status byte */ ULONG ulStatusLen; /* Length of status (the data packet) */ ULONG ulAction; /* Action taken by DosOpen */ APIRET rc; /* Return code */ rc = DosOpen("COM1", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); rc = DosDevIOCtl(hf, /* Device handle */ IOCTL_ASYNC, /* Serial-device control */ ASYNC_GETCOMMSTATUS, /* Get the COM status byte */ NULL, /* No parameter packet */ 0, /* Maximum size of parameter packet */ NULL, /* Length of parameter packet */ (PULONG) &ucStatus, /* Data packet */ sizeof(ucStatus), /* Maximum size of data packet */ &ulStatusLen); /* Length of data packet */ . . /* Use the COM port here. */ . rc = DosClose(hf);