Mac OS X Serial Port Architecture Overview

On Mac OS X, serial ports have an interesting architecture. In the kernel, a serial driver is implemented using the object-oriented I/O Kit framework, but in user space it is accessed through the BSD layer, and the serial port is presented as a traditional UNIX device file. For each serial driver that is loaded in the kernel, the I/O Kit's serial family creates a corresponding device object in the /dev directory of the file system. To interact with a serial port, applications open the device file and read and write to it as if it were an ordinary file. This is an alternative to communicating with a driver through a user client; in fact, serial drivers don't have a user client. The advantage of this architecture is that it allows traditional UNIX applications that have been written using the POSIX APIs to access a serial port on Mac OS X without any changes to their code.

Although serial port drivers are not accessed through the I/O Kit framework from user space, they are still implemented in the kernel as a full I/O Kit driver. This means that a serial driver can take advantage of all of the features that the I/O Kit brings, including object-oriented design and dynamic driver loading and matching. The I/O Kit includes a family that is specific to serial devices, known as the IOSerialFamily. The IOSerialFamily, which is available through the Darwin open source project, contains the header files for the base classes that a serial port driver is derived from, as well as the implementation of the serial port subsystem of Mac OS X.

Figure 11-1 shows the various entities that are involved in handling communications over a serial port on Mac OS X. For this example, we have assumed that the serial port is implemented by a USB device (such as a USB to RS-232 adapter), which is why the leftmost provider object in the diagram is an IOUSBDevice.

images

Figure 11-1. The objects involved in communicating with a serial port from a user space application

Starting in user space, an application connects to a serial port driver by opening a character device file from the /dev directory that corresponds to the serial port driver. Each serial driver has two entries in the /dev directory, one whose name begins with the prefix “tty.” and another whose name begins with the prefix “cu.”. The reason for this is largely historical and comes from a time when the serial port was the means by which a modem or a fax was connected to a computer. In this situation, the “tty” device was the dial-in device that was used to receive a call, and the “cu” was the callout device that was used to make a call.

A process that wished to receive a call would open the dial-in device; the open function would block until the carrier detect line was signaled, meaning that the modem had established a connection. However, to make an outgoing call, a process needed to be able to open the serial port without waiting for the carrier detect line, so it would open the callout device, which doesn't block on the carrier detect signal. When communicating with modern serial devices, given that most devices will not be connected to a phone line, Apple recommends opening the callout device.

The two device files in /dev are created by an I/O Kit class known as IOSerialBSDClient. This is a class that is provided by the IOSerialFamily and handles the kernel-side of operations that are made by a user space process on the device file. The IOSerialBSDClient handles any system call made by a user space process to operate on a serial port, including any of the following the functions: open(), close(), read(), write(), ioctl(), and select(). In this way, the IOSerialBSDClient can be thought of as playing the role of the user client for a serial driver (although it isn't derived from the IOUserClient class). Like a user client, the IOSerialBSDClient class is simply a conduit between a user space process and the kernel driver object. The class is responsible for handling the differences between blocking and non-blocking calls, but its main role is to translate function calls received from user space into method calls to the IOSerialStreamSync object.

The IOSerialStreamSync class is another class that is provided by the I/O Kit in the IOSerialFamily package. Its role is nothing more than a conduit between the IOSerialBSDClient and the implementation of the actual serial driver. In fact, for each method of the IOSerialStreamSync class, it calls a method of the same name in the IOSerialDriverSync class.

The IOSerialDriverSync class is a pure abstract interface that provides the base class for any serial driver on Mac OS X. It provides methods for reading and writing data, and for reporting changes in the state of the serial port, such as whether a carrier signal has been detected, the arrival of data on the serial port for reading, and whether the serial port can accept more bytes for transmission.

Finally, the last object that is involved in the serial driver stack is the provider class of the serial driver. In this example, we are assuming that the serial port is implemented by a USB-to-serial adapter, which is why the provider class has the type IOUSBDevice. Whenever the serial port driver needs to read data from the serial port or write data over the serial port, it will access the underlying hardware device through the IOUSBDevice instance.

The role of each class that plays a part in implementing a serial port driver is as follows:

  • The serial port driver's provider class, IOUSBDevice in our example, performs the data transfer into and out of the computer to the serial port adapter.
  • The main driver, which is a subclass of IOSerialDriverSync, manages the serial port's receive and transmit buffers, reading data from the hardware as it arrives, and writing data to the hardware when it is provided by user space.
  • The IOSerialBSDClient manages interaction with user space applications.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.206.43