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,