Accessing I/O Ports, Part 2

Descriptors vs. Direct Access

The technique presented last week for accessing I/O ports is portable

and safe but too slow for certain applications. Instead of using a

descriptor, Linux allows a process to write to an I/O port directly,

thereby avoiding the overhead associated with write() and read().

The outb() Syscall

A process can call the function outb() to write directly to an I/O

port. outb() takes two arguments: the data to be written to the I/O

port and the I/O port number. For example, to write the character 0x01

to our remote control, call outb() as follows:

outb(0x01, 0x378+2); /*turn the lights on*/

The use of symbolic constants can make the code more readable:

const char ON=0x01;

const char OFF=0x00;

const int PORT=0x378+2;

outb(OFF, PORT); /*turn the lights off*/

Obtaining Permissions

This is all well and good; however, by default Linux terminates a

process that attempts to access an I/O port directly (with good

reason!). A process that accesses I/O ports directly must get the

necessary permissions beforehand using one of two methods. The first

(and safer) way is to call ioperm(). ioperm() allows a process with

super-user privileges access to each I/O port in the range 0-0x3ff.

Thus, if you wish to access the ports 0x378, 0x379, and 0x380 (the

ports that access /dev/lp1), call ioperm() as follows:

ioperm(0x378, 3, 1);

The first argument is the first port in the range. The second argument

is the number of ports in the range. The last argument is either 1 or

0. The value 1 allows access to the ports in the range and 0 denies

access to them. ioperm() returns 0 on success and -1 on error.

Alternatively, a process with super-user privileges can enable access

to all the I/O ports at once by calling the iopl() function as follows:

iopl(3);

The above call causes a process to switch to what is known as "I/O

protection level 3", which grants a process full access to the I/O bus.

As a rule, you should use ioperm() to obtain permission to access I/O

ports; use iopl() only if your process needs to access ports higher

than 0x3ff.

A note on last week's tip:

The device names "dev/port" and "dev/lp1" should read "/dev/port"

and "/dev/lp1", respectively.

Insider: How the basic tech behind the Internet works
Join the discussion
Be the first to comment on this article. Our Commenting Policies