Not everything UNIX classifies as a file can neatly be described by a stream of bytes. In addition to providing a read-only, read-write, or write-only stream of data, most hardware devices have many settings that a user program may wish to access. While it may be possible to multiplex data and control in a single data stream, it would be extremely cumbersome and would negatively affect performance and interoperability. Therefore UNIX has what are known as ioctls (input/output controls) for reading and setting any hardware-specific configuration options. Unfortunately, the ioctl system can be a disorganized catch-all facility, with no standardized access semantics and conventions, leaving all the details up to the programmer of each specific device implementing them. Furthermore, the standard UNIX file commands (cat, grep, tail, and so on) have no knowledge of ioctls, so specialized programs must be written for each different type of hardware device in order to provide user access to their ioctls. As far as I know, no means exists to query a device about what ioctls it supports, what each one does, what parameters it takes, what values it returns, and so on. Alas, according to the conventional UNIX mindset, ioctls are a necessary evil. To a small extent, Linux corrects this by its extensions to the /proc directory tree, traditionally used only to describe processes. Specifically, the sysctl (/proc/sys) interface exports device tuning parameters to the filesystem, available for inspection and modification using tools such as cat and echo, making it easy for a system administrator to write a boot script to set system options. The upcoming Linux 2.6 has a special device filesystem hosting this sort of information. However, sysctl isn't a replacement for ioctls because sysctl is for system-wide configuration without special tools whereas ioctls are generally for application-specific configuration with special tools. User programs are often shielded from all this by means of libraries of functions for accessing special device files. The user program calls a function to, say, initialize the sound card, and the library function opens /dev/dsp and uses ioctls to set the number of channels, the number of bits per sample, the number of samples per second, etc. But for simple devices, the complexity of ioctls is such that the average programmer can make use of them with a minimum of fuss. ioctls are invoked by calling the ioctl function. For detailed specifics, see ioctl(2) (use "man 2 ioctl" to read). The ioctl function call takes two or three parameters. The first is the file descriptor, obtained using the open(2) call, of the device to be accessed. The second is the ioctl command number, usually enumerated in a system header file corresponding to the device in question (for example, this file you are reading now). The third parameter is optional; if the ioctl involves reading or writing a value, it points to a memory buffer used for carrying out the transaction. ioctls nearly always return a signed integer value indicate success (zero) or failure (any negative value). Linux 2.4 and up attempts to make ioctl command numbers globally unique to bring some sort of standardization to the world of ioctls and to aid debug utilities such as strace. It provides four macros, _IO, _IOR, _IOW, and _IORW, which evaluate to valid ioctl command numbers. _IO takes two parameters. The first is a single-byte value used to identify the device. p8253 uses 'u'. Obviously these values aren't unique from driver to driver, but they help. The second is another single-byte value used to identifying the command. The combination of the device id and command id is hopefully globally unique. _IOR, _IOW, and _IORW take the same first two parameters but additionally take a third, the data type of the value to be read or written using the ioctl. Please note that the third parameter of ioctl is a *pointer*. _IOR is used for ioctls that move data from the kernel driver to the user program. _IOW is for ioctls that move data from the user program to the kernel driver. Supposedly, _IORW ioctls work either way, but it doesn't appear to be currently in use anywhere in the kernel. It's acceptable to use the same second parameter ("sequence number") for different types (_IO, _IOR, _IOW, _IORW) of ioctls because the type is encoded in the final ioctl command number and therefore are differentiated from each other. See linux/Documentation/ioctl-number.txt and linux/Documentation/sysctl/README for more information.