Make Input/Output operations from Linux user space


Input/Output operation are made with special x86 instructions. This mean this interface exist only in x86 systems and is not available in ARM platforms. The operation consist in send or receive data to/from special "registry" called port and is frequently used for a lot of common tasks.



Linux have a special device enabled by default in each x86 kernel allowing to read/write ports using standard function set for manage file. The device to use is the following:

/dev/port

Please note, since this device allow to have direct access to hardware you need to have root privileges to allow use. As other standard device you can access it by using standard file functions set. To start you need to open the device and get the handle as below:

int PortDev = open("/dev/port", O_RDWR | O_SYNC);

if(PortDev == -1)
{
    \\ Error
}

......

close(PortDev);

Please note the open params. Usually when you write to a file the write operation can not be immediate since the operating system cache the data to write in waiting of a time slot to execute the operation. Adding the param O_SYNC we'll force the system to execute the write operation immediately since is what we want in case of input/output operation. Once we got a valid handle to the device we can imagine to have access to a file with size 65535 to read or write. For historical reasons port number is contained in a word value. This mean the max port number available is from 0 to 0xFFFF (65535 in decimal). For have access to some specific port number, in our example port number 1234, you simply need to set file pointer to this address using seek function:

lseek(PortDev, 1234, SEEK_SET);

Now is possible to make input or output operation by reading or writing port. Depends on your hardware is possible to read/write port in byte, word or double word mode as follow:

// Read byte mode
read(PortDev, &Data, 1); 
// Read word mode
read(PortDev, &Data, 2); 
// Read double word mode
read(PortDev, &Data, 4); 

// Write byte mode
write(PortDev, &Data, 1);
// Write word mode
write(PortDev, &Data, 2);
// Write double word mode
write(PortDev, &Data, 4);

Please note a very important point. Since we are managing the device like a file all the read and write functions will act in the same way as standard file. This mean after a read/write operation the file pointer will automatically move to the next position. For make a practical example if you read a byte from port address 1234 as in our example and will try to read again you will not read the same port 1234 but will read at port address 1235 since the file pointer will be moved over. For continuously read/write always to same port address you need to call the seek function before any read/write operation to keep the port pointer address always set to the same value.

Comments

Popular posts from this blog

Access GPIO from Linux user space

Android: adb push and read-only file system error

Tree in SQL database: The Nested Set Model