The tty Layer, Part II

In the first part of this column
(LJ, August 2002) we covered the basics of the
tty layer and how to create a minimal tty driver. Now we move on
and cover more of the tty layer, trying to explain some of the
advanced portions.

Remember from Part I the big struct tty_driver structure that
all tty drivers need to implement? Let's focus on a few of its
functions that were not fully covered last time.

101 ioctls

The ioctl function callback in the struct tty_driver is
called by the tty layer when ioctl(2) is called on the device node.
If your driver does not know how to handle the ioctl value passed
to it, it should return -ENOIOCTLCMD to try to let the tty layer
implement a generic version of the call, if possible. But what
ioctl values will your driver be expected to handle?

The 2.4.19 kernel defines around 60 different possible tty
ioctls. Your tty driver doesn't have to implement all of them, but
it is a good idea to try to handle the following common
ones.

TIOCMGET: called when the
user wants to find the status of control lines of the serial port,
such as the DTR or RTS lines. If you can directly read the MSR or
MCR registers of your serial port, or if you keep a copy of them
locally (like some USB to serial type devices need to do), here is
how this ioctl can be implemented:

TIOCMBIS, TIOCMBIC and
TIOCMSET: used to set different modem control registers
on your tty device. The TIOCMBIS call can turn on the RTS, DTR or
loopback registers, while the TIOCMBIC call can turn them off. The
TIOCMSET call turns all three values off, and then it sets only the
specific values it wants. Here's an example of how this can be
handled:

Note, the loopback request (TIOCM_LOOP) is not present in the 2.2
kernel, but it is in the 2.4 and newer kernels.

If your tty driver can handle these four ioctls, it will work
with the majority of existing user-space programs. However, there
is always an odd program that asks for one of the other ioctls. So
you may want to consider handling some of these other common ioctl
functions as well.

TIOCSERGETLSR: called to
retrieve the line status register (LSR) value of your tty
device.

TIOCGSERIAL: called to get a
bunch of serial line information from your device all at once. A
pointer to a struct serial_struct is passed to this call, which
your driver should fill up with the proper values. Some programs
(like setserial and dip) call this function to make sure that the
baud rate was set properly and to get general information on what
type of device your tty is. Here's an example of how this can be
implemented:

TIOCSSERIAL: the opposite of
TIOCGSERIAL; with this one the user can set the serial line status
of your device all at once. A pointer to a struct serial_struct is
passed to this call, full of the data to which your device should
now be set. If your device does not implement this call, almost all
programs still will work properly.

TIOCMIWAIT: an interesting
call. If the user makes this ioctl call, they want to sleep within
the kernel until something happens to the MSR register of the tty
device. The “arg” parameter will contain the type of event for
which the user is waiting. This ioctl is commonly used to wait for
status line changes, signaling that more data is ready to be sent
to the device.

Be careful in implementing the TIOCMIWAIT ioctl, however.
Almost all of the existing kernel drivers that use it also use the
interruptible_sleep_on() call, which is unsafe. (A lot of nasty
race conditions are involved.) Instead, a wait_queue should be used
in order to avoid these problems. Here's an example of a correct
way to implement TIOCMIWAIT:

Somewhere in the portion of the code that recognizes that the
MSR register changes, the line:

wake_up_interruptible(&tp->wait);

must be called for this code to work properly.

TIOCGICOUNT: called when the
user wants to know the number of serial line interrupts that have
occurred. The kernel is passed a pointer to a struct
serial_icounter_struct, which needs to be filled up. This call is
often made in conjunction with the previous TIOCMIWAIT ioctl call.
If you keep track of all of these interrupts while your driver is
operating, the code to implement this call can be quite simple. See
drivers/usb/serial/io_edgeport.c for an example.

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.