|
|
A frequent question is how to port a DOS application that calls the inb and outb instructions to read and/or write the registers of an application-specific device.
The solution is to break the original DOS program into two parts:
Calling inb and outb from a user-level program should be done only when testing devices that are unknown to the UNIX kernel (in other words, do not have a driver installed in the kernel). Do not access standard system devices (such as tapes, disks, and network adapter cards) in this way. Any direct user-level access of I/O addresses that are used by a kernel-level driver can corrupt the kernel, because the kernel's notion of the hardware state is no longer valid.
On SVR5,
kdb
has the ability to set breakpoints
when someone does direct I/O access,
which enables you to identify the %eip
of a user-level process that may be causing problems.
For testing and migration purposes, the inb and outb instructions can be issued from a standard application on SCO UNIX systems.
The SCO OpenServer 5 call to do this is:
if (sysi86(SI86V86, V86SC_IOPL, 0x3000) < 0) { perror ("Cannot enable direct I/O!"); exit(1); }On SVR5 systems, the comparable call is:
#include <sys/sysi86.h> #include <sys/inline.h>This can only be done with the native UDK compiler on SVR5 systems, not with gcc and other non-native compilers.if (sysi86(SI86IOPL, 3) < 0) { perror ("Cannot enable direct I/O!"); exit(1);
If you are using the UODK to build a binary that works on both SVR5 and SCO OpenServer 5, you must get the values of the sysi86( ) arguments for both hosts and determine at runtime which arguments to pass to sysi86( ).
On Linux, the comparable call is:
#include <asm/io.h> if (iopl(3) < 0) { perror ("Cannot enable direct I/O!"); exit(1);The Linux <asm/io.h> file contains inline asm functions that the system compiler uses to generate the appropriate instructions. The code must be compiled with optimization.
as -o io386.o io386.s
The e3D sample driver that is included in the SCO OpenServer 5 ndsample package includes source code for the acfg user-level utility that illustrates how to implement this functionality.
On SCO OpenServer 5 systems, you can set up devices such as /dev/inb as an alternative implementation. This method incurs a fair amount of overhead so is not recommended when that is a problem, but for simple operations such as poking devices and checking status, this is useful.
mknod c /dev/inb 4 3 mknod c /dev/outb 4 3 mknod c /dev/ind 4 5 mknod c /dev/outd 4 5 mknod c /dev/inw 4 4 mknod c /dev/outw 4 4
Be extremely careful about the operations that are done to /dev/inb and the related devices; commands such as dd, wc, and sum can hang the system and may even damage the hardware itself.
If performance is a concern and the application needs to read/write larger amounts of data or do frequent transfers, implementing an ioctl( ) operation that can transfer a string of bytes from user-level to kernel-level is more efficient than an implementation that incurs the overhead of repeated switches across the user/kernel boarder.