# I/O Architecture

Portfolio provides services to access hardware devices in a hardware-independant manner. This allows applications to remain compatible across a wide range of hardware products. The Portfolio I/O model is a central component that enables a wide range of exotic devices to coexist and evolve for many years.

The Portfolio I/O model is inherently asynchronous. Lengthy requests made by a task to a hardware device are handled in the background. The client task receives a notification when the request has been satisfied. This architecture allows a single task to have multiple outstanding requests pending on different hardware devices, which tends to maximize the use of the system bandwidth by keeping all subsystems working.

Imagine a task that needs to read a block of data from a CD-ROM. It sends a request to the CD-ROM device driver. The driver does the setup necessary to initiate a hardware transfer. The CD-ROM mechanism is then activated and the needed block of data is transferred to memory. When the transfer is complete, an interrupt occurs that wakes up the driver. The driver then notifies the client task that the data it needs has arrived. While the hardware is servicing the request from the task, the task is free to do other activities, such as playing music.

The Portfolio I/O model relies on three basic abstractions: the device, the driver, and the I/O request.

## Devices

A software device may or may not correspond to a hardware device. Technically, a software device is anything that responds to I/O requests and lives in supervisor space. A software device might correspond directly to a hardware device such as a timer, a CD-ROM player, or a controller pad; it might correspond to a port or bus that controls many different devices; or it might correspond to a more abstract entity such as an open file on a CD-ROM disk. Portfolio treats a software device as a single I/O mechanism, no matter what the device's correspondence to actual hardware.

Note: Whenever you read the term "device" by itself, it refers to a software device. A hardware device is always referred to as "hardware device."

Portfolio maintains a list of all devices resident or active on the 3DO unit. This list changes as devices are added to or taken from the system. Each device in the list has an item number; a task that requests I/O with a device must refer to the device by its item number. To find a device's item number, a task uses the call `OpenNamedDevice(),` where the task names the device it wants and the kernel returns the device's item number.

## Drivers

Every device maintained by the kernel must have a corresponding driver before any task can use the device. The driver accepts and acts on every task request for I/O. The driver must be able to recognize at least three I/O commands-`CMD_READ, CMD_WRITE`, and `CMD_STATUS`-and may recognize more device-specific I/O commands as well. Not all devices are writable, so not all devices can perform the `CMD_WRITE` command. For example, a CD-ROM drive will respond to the command without writing data. All devices can execute `CMD_STATUS` commands and tell an enquiring task their current status.

A single driver can control several identical or very similar components. Each of these components is called a unit. Each unit may respond to slightly different commands or may respond in slightly different ways. Even so, the units are similar enough that a single driver can control them. When a task requests I/O through such a driver, it specifies not only the device item number, but the unit number. For example, the kernel provides a timer device that supports two timer units: the microsecond timer and the vertical blank timer. Both timer units respond to the same commands, but one unit returns elapsed microseconds, while the other returns elapsed vertical blanks. To read the timer, a task specifies the timer item number, and then asks for either the microsecond or vertical blank unit.

Drivers are all privileged code. The 3DO Company provides them for 3DO-approved hardware devices such as controller pads and for more abstract system software devices such as open files.

## I/O Requests (IOReqs)

An I/O request (IOReq for short) is a data structure that the kernel passes back and forth between a task and a device. Think of the IOReq as a messenger that goes from task to device, passing along an I/O command and other I/O information. When an I/O operation is finished, the device returns the IOReq to the task, passing along any reports it has to make on the I/O operation.

Before a task can communicate with a device, the task must create an IOReq using the `CreateIOReq()` call. An IOReq is a system item that must be used to communicate with a device.

Within an IOReq lies information necessary for executing an I/O command. Part of that information is the IOInfo data structure, which contains an I/O command, a unit specification, pointers to read and write buffers, and other I/O parameters provided by the task requesting I/O.

To initiate an I/O operation, a task must give the IOReq to a device by calling `SendIO()` or `DoIO()`. When the device completes the operation, it notifies the calling task that the operation is complete. The calling task is then free to use the IOReq to initiate further I/O operations.

A task gets notified that an I/O operation is complete by either receiving a signal or receiving a message. The notification mechanism is determined when the IOReq is created.