A device file is a special type of file found on UNIX(-like) systems. It is often just called "device", for short.

The device files commonly live in /dev, but this is purely for aesthetics. There is no special reason a device file couldn't live in /home, /usr, or even /tmp.

Device files are the link between programs and the kernel. A "read" operation on a device file (e.g. /dev/ttyS0, a communications port on Linux) will request information from the kernel about what data is incoming on that port (like a mouse movement). A write operation will tell the kernel to send information to the port (like write to a serial terminal).

To the application programmer a device file will appear much like a regular file, with maybe some extra options (ioctl). In reality, the kernel will handle all communication with the hardware.

Besides hardware (communication ports, harddrives, etc.) the OS's internals are often represented as device files too. Linux has the ability to use several "virtual terminals". I.e. one monitor can handle lots of different login sessions, by making it appear that several terminals are "connected" to Alt F1-... Each virtual terminal is represented by /dev/ttyx, where x is the number of that virtual terminal. A "real" , serial, terminal would be represented by /dev/ttySx. To avoid reinventing the wheel, /dev/ttyx is used to make them seem like real terminals. Same goes for software RAIDs.

There are two types of device files (at least, on Linux, my knowledge of other UNIXen is quite limited) called "block" and "character" devices.

The first one is used for blocked I/O. That is, several (kilo-)bytes (a block) are read into memory, and processed afterwards. This is most commonly used for hard drives, where reading 1 byte, processing it, and reading the next, would require too much seek time on the drive and thus making it slow.

The "character" devices are the most common. Communication ports, sound cards, etc. are all "character" devices. These devices are unbuffered, i.e. a byte (character) is read, processed, the next is read, etc. Of course, the user application can choose to block data by itself.

Oof. I hope this makes any sense at all. I don't hack kernels, so relying on me for something important would be silly.
The device files interface with the kernel through the use of major and minor device numbers. The kernel first looks up the major number to discover which device or device type is being refered to, and the minor numbers determine a sub-selection within that category. For an example, lets look at the serial ports:

legba:/proc# ls -l /dev/ttyS*
crw-r-----    1 root     dialout    4,  64 Dec 26 11:46 /dev/ttyS0
crw-rw----    1 root     dialout    4,  65 Jul  6 03:44 /dev/ttyS1
crw-rw----    1 root     dialout    4,  66 Jul  6 03:44 /dev/ttyS2
crw-rw----    1 root     dialout    4,  67 Jul  6 03:44 /dev/ttyS3
                                    ^   ^                    ^
                                    |   |                    |
Major number -----------------------+   |                    |
                                        |                    |
Minor Number ---------------------------+                    |
Device Name -------------------------------------------------+
(Note that ttyS0 == COM1, ttyS1 == COM2 etc)

Here we can see that all the serial ports have a major number of 4, which indicates a terminal of some type, and minor numbers of 64 to 67, which determine which com port you are trying to access. So a program sending data to a modem connected to the first serial port would write the data to /dev/ttyS0, this would cause the kernel to intercept the data, see it was addressed to 4,64, find the module that controls the serial port, and push the data to the module's input subroutine. The module will then interface with the hardware, and give the serial port controller the data to output over the serial port.

Log in or register to write something here or to contact authors.