Determine IO port addresses via /proc/ioports
Since I picked up programming again (pSam and Parilux) I needed to know how to get to the IO address ranges of
hardware ports. Under DOS you simply inspected part of System RAM at 0000:0400h. In Linux it is even more
easy: just do a 'cat /proc/ioports' and you have all info in reach.
This section describes how to get to that information and shows a first example of how it's done. This is an
evolving page, so check back once in a while since the content is liable to change in time. Do not rely on
Google: they censor my pages since I put the word 't e r r ror ist' (no spaces) 32 times on one webpage and
that makes ME a T-thingy as well.
The /proc filesystem
The /proc filesystems is special. It has a list of files in it, which are built up by the Linux system at boot time and when major changes have taken place. Below is the list of files in my /proc FS:
jan@beryllium:~$ ls /proc 295 3231 3315 3347 3550 3574 3591 cmdline filesystems kmsg partitions tty 3 3235 3316 3348 3552 3576 3598 cpuinfo fs loadavg scsi uptime 3125 3256 3317 3349 3555 3577 3603 crypto ide locks self version 3128 3263 3318 3427 3563 3579 3667 devices interrupts meminfo slabinfo vmstat 3139 3287 3319 3470 3565 3583 3686 diskstats iomem misc stat 3144 3291 3330 348 3566 3584 3690 acpi dma ioports modules swaps 3162 3304 3343 3498 3568 3586 37 asound driver irq mounts sys 3221 3307 3345 3526 3569 3587 4 buddyinfo execdomains kallsyms mtrr sysrq-trigger 3226 3314 3346 3547 3572 3588 47 bus fb kcore net sysvipc jan@beryllium:~$To prevent horizontal scroll bars I removed some of the more obscure devices.
You can inspect the data in the /proc filesystem with your cat:
jan@beryllium:~$ cat /proc/uptime
1576.52 1539.09
jan@beryllium:~$ cat /proc/filesystems
nodev sysfs
nodev rootfs
nodev bdev
nodev proc
nodev sockfs
nodev futexfs
nodev tmpfs
nodev pipefs
nodev eventpollfs
nodev devpts
cramfs
nodev ramfs
nodev devfs
nodev mqueue
ext3
ext2
reiserfs
nodev usbfs
nodev usbdevfs
jan@beryllium:~$
I can recommend to try some of these devices just to satisfy your curiosity. Especially /proc/cpuinfo can tell
you if your salesguy cheated with the CPU of your new machine.
procs.mod : the source
Below is the source of the first attempt to process the /proc/ioports device. It specifically looks for the IO addresses for the LPT ports (called 'parport' in Linux). I had to make GetHex since this is not part of the 'TextIO' library. I had to make GetString since I needed to read until end of line instead of the first whitespace token.
MODULE procs;
IMPORT Strings, InOut, TextIO;
VAR InFile : TextIO.File;
name : ARRAY [0..63] OF CHAR;
port0, port9 : CARDINAL;
ch : CHAR;
PROCEDURE GetHex (VAR num : CARDINAL);
VAR chr : CHAR;
pos : CARDINAL;
BEGIN
num := 0;
LOOP
TextIO.GetChar (InFile, chr);
chr := CAP (chr);
IF (chr < '0') OR (chr > 'F') OR ( (chr > '9') AND (chr < 'A') ) THEN EXIT END;
IF chr > '9' THEN
pos := ORD (chr) - ORD ('A') + 10
ELSE
pos := ORD (chr) - ORD ('0')
END;
num := num * 16 + pos
END;
TextIO.UndoGetChar (InFile)
END GetHex;
PROCEDURE GetString ( VAR str : ARRAY OF CHAR);
VAR i : CARDINAL;
chr : CHAR;
BEGIN
i := 0;
REPEAT
TextIO.GetChar (InFile, chr)
UNTIL chr > ' ';
LOOP
IF chr = 12C THEN EXIT END;
IF i <= HIGH (str) THEN str [i] := chr END;
INC (i);
TextIO.GetChar (InFile, chr)
END;
IF i <= HIGH (str) THEN str [i] := 0C END
END GetString;
BEGIN
TextIO.OpenInput (InFile, "/proc/ioports");
IF TextIO.Done () = FALSE THEN
InOut.WriteString ("Cannot access '/proc/ioports'. Aborting.");
InOut.WriteLn
ELSE
InOut.WriteString ("Opened '/proc/ioports' for reading'. Commencing.");
InOut.WriteLn
END;
LOOP
IF TextIO.EOF (InFile) = TRUE THEN EXIT END;
GetHex (port0);
TextIO.GetChar (InFile, ch);
GetHex (port9);
REPEAT
TextIO.GetChar (InFile, ch)
UNTIL ch = ':';
GetString (name);
IF Strings.pos ('parport', name) = 0 THEN
InOut.WriteString ("Parport device found. Ports assigned from ");
InOut.WriteHex (port0, 4);
InOut.WriteString (' - ');
InOut.WriteHex (port9, 4);
InOut.WriteString (" for device ");
InOut.WriteString (name);
InOut.WriteLn
END
END;
InOut.WriteLn
END procs.
Houston, we have an error.
Although the program ran flwalessly for some time, today it malfunctioned. I put a new PCI LPT port in Beryllium. And when I ran the procs executable, the parport1 device was found, but it was assigned IO address range [0..0] which of course is not very sensible.
The error had to be in the GetHex function. Inspection of the /procs/ioports file gave a clue: there was whitespace in front of the hex numbers. And my GetHex did not remove the whitespace. So I changed the routine as below and now it runs fine. My new parport1 device is assigned the range [EFF0 .. EFF2] by Linux.
PROCEDURE GetHex (VAR num : CARDINAL);
VAR chr : CHAR;
pos : CARDINAL;
BEGIN
num := 0;
LOOP
TextIO.GetChar (InFile, chr);
IF chr > ' ' THEN EXIT END
END;
LOOP
chr := CAP (chr);
IF (chr < '0') OR (chr > 'F') OR ( (chr > '9') AND (chr < 'A') ) THEN EXIT END;
IF chr > '9' THEN
pos := ORD (chr) - ORD ('A') + 10
ELSE
pos := ORD (chr) - ORD ('0')
END;
num := num * 16 + pos;
TextIO.GetChar (InFile, chr)
END;
TextIO.UndoGetChar (InFile)
END GetHex;
The whitespace skipper should have been there from the beginning but I was too self assured. Now it is in and
now it runs fine.
Page created 15 June 2007,
Page equipped with FroogleBuster technology