歡迎您光臨本站 註冊首頁

Linux下讀寫I/O port

←手機掃碼閱讀     火星人 @ 2014-03-24 , reply:0

1. 基礎知識:


1.1 在存取任何 I/O port之前,必??程式有如此做的?嘞? 要?成???目的你可以在你的程式一?始的地方 (但是要在任何 I/O port存取?幼髦?? 呼叫 ioperm() ???函數 (?函數被聲明於?n案 /usr/include/sys/io.h).

使用?法是:

ioperm(from, num, turn_on)

其中 from 是第一??允?存取的 I/O port位址;num 是接著??存取 I/O port位址的?的? 例如, ioperm(0x300, 5, 1) 的意思就是?允?存取port 0x300 到 0x304 (一共五??port位址). 而最後一????凳且??布爾值用?碇付ㄊ欠窠o予程式存取 I/O port的?嘞 (true (1)) 或是除去存取的?嘞 (false (0)).

函數 ioperm() 只能?你取得Port位址 0x000 到 0x3ff 的存取?嘞? 至於?高位址的Port, 你得使用函數 iopl() (?函數?你一次可以存取所有的Port位址). ??嘞薜燃???抵翟O? 3 (例如, iopl(3)) 以便你的程式能?虼嬡 所有的 I/O Port。


1.2 獲得讀取許可權后,就可以對I/O port進行讀寫了。

a.讀

要?哪??Port地址讀取一?? byte (8 ?? bits) 的?料, 可以調用函數 inb(port);類似的有:


inw (port) //讀取 2 個 bytes


inl (port) //讀取 4 個bytes


b.寫

要向某??Port地址寫入一?? byte (8 ?? bits) 的?料,調用函數 outb(value, port);類似的有:

outw(value, port)

outl(value, port)

2. 應用實列:
2.1 源程序:

/* name: pci.c */
#include
#include
#include

#define IO_PORTS1 1 /* ioport <= 0x3ff */
#define IO_PORTS2 2 /* ioport >0x3ff && ioport < 0xffff */
#define IO_PERMOFF 0
#define IO_PERMON 1
#define IO_PERMON2 3

#define RW_DELAY 10000 /*delay 100000 microseconds for reading and writing I/O ports. */
#ifndef BOOL
typedef unsigned char BOOL;
#endif

#ifndef BYTE
typedef unsigned char BYTE;
#endif

#ifndef DWORD
typedef unsigned long DWORD;
#endif

#ifndef INT
typedef unsigned int INT;
#endif

#ifndef ULONG
typedef unsigned long ULONG;
#endif

#ifndef WORD
typedef unsigned short WORD;
#endif
/*
** Function : Write the value of the specified I/O port by giving the length and the
** starting address.
** Parameter: PortAddr: the port address
** PortVal : the value to set
** size : size = 1 for reading 1 byte, 2 for word, 4 for double words
** Return : 1 returned if success, or 0 returned
*/
BOOL SetPortVal(WORD PortAddr, DWORD PortVal, BYTE size)
{
BOOL Ret = 0;
INT tmpRet = 0;
ULONG numperm = 1;
INT privilege = 0;
assert(PortAddr>0);
if(PortAddr <=0x3ff)
{
tmpRet = ioperm((ULONG)PortAddr, numperm, IO_PERMON);
privilege = IO_PORTS1;
}
else if( PortAddr > 0x3ff
{
tmpRet = iopl(IO_PERMON2);
privilege = IO_PORTS2;
}
else
return Ret;
if(tmpRet<0)
{
fprintf(stderr, "can't set the io port permission for setting !\n";
return Ret;
}
else
{
switch(size)
{
case 1: /*write one byte to the port */
outb(PortVal, PortAddr);
break;
case 2: /*write one word to the port */
outw(PortVal, PortAddr);
break;
case 4: /*write double words to the port */
outl(PortVal, PortAddr);
break;
default:
Ret = 0;
break;
}
usleep(RW_DELAY);
Ret = 1;
}
if( privilege == IO_PORTS1
ioperm((ULONG)PortAddr, numperm, IO_PERMOFF);
else if(privilege == IO_PORTS2
iopl(IO_PERMOFF);
return Ret;
}

/*
** Function : Read the value of the specified I/O port by giving the lenght and the
** starting address.
** Parameter: PortAddr : the port address
** PortVal : value from port
** size : size = 1 for reading 1 byte, 2 for word, 4 for double words
** Return : 1 returned if success, or 0 returned.
*/
BOOL GetPortVal(WORD PortAddr, DWORD * PortVal, BYTE size)
{
BOOL Ret = 0;
int tmpRet = 0;
unsigned long numperm = 1;
int privilege = 0;
assert(PortAddr>0);
assert(PortVal!=NULL);
if(PortAddr <=0x3ff)
{
tmpRet = ioperm((unsigned long)PortAddr, numperm, IO_PERMON);
privilege = IO_PORTS1;
}
else if( PortAddr > 0x3ff
{
tmpRet = iopl(IO_PERMON2);
privilege = IO_PORTS2;
}
else
return Ret;
if(tmpRet<0)
{
fprintf(stderr, "can't set the io port permission for reading !\n";
return Ret;
}
else
{
switch(size)
{
case 1: /*read one byte from the port */
*PortVal = inb(PortAddr);
break;
case 2: /*read one word from the port */
*PortVal = inw(PortAddr);
break;
case 4: /*read double words from the port */
*PortVal = inl(PortAddr);
break;
default:
Ret = 0;
break;
}
usleep(RW_DELAY);
Ret = 1;
}

if( privilege == IO_PORTS1
ioperm( (unsigned long)PortAddr, numperm, IO_PERMOFF ;
else if( privilege == IO_PORTS2
iopl(IO_PERMOFF);
return Ret;
}

int main (int argc, char * argv[])
{
WORD add_port = 0xcf8;
WORD data_port = 0xcfc;
DWORD addr = 0x80000000;
DWORD port_value;
BYTE size = 4;
int input;
printf("Please select the option number as follow:\n";
printf("1--bus 0:dev:0 fun:0 as address 0x80000000\n";
printf("2--bus 0:dev:1 fun:0 as address 0x80000800\n";
printf("3--input your own defined address value:\n";
scanf("%d",&input);
switch(input)
{
case 1:
addr=0x80000000;
break;
case 2:
addr=0x80000800;
break;
case 3:
printf("please input the 32 bits address in Hex format(such as 80007800): ";
scanf ("%x", &addr);
break;
default:
printf("input invalid option num, exit program.\n";
return -1;
}
printf ("The addr is :%X\n", addr);
printf ("The add_port is : %X\n", add_port);
printf ("The data_port is : %X\n", data_port);
if (SetPortVal(add_port, addr, size))
{
if (GetPortVal(data_port, &port_value, size))
{
printf("port value is :%08X\n", port_value);
return 0;
}
}
return -1;
}

2.2 編譯:
gcc ?o pci pci.c
gcc 帶參數 ?o 指定輸出的文件名,如不帶參數則默認以a.out做為文件名;
如要加入調試信息,則帶參數-g,然後用gdb命令進行調試:
gcc ?o pci ?g pci.c
gdb pci
有關gdb的用法參見相關資料;

2.3 運行:
輸入: ./pci (注意: / 前有.表示當前目錄下)
可以將結果和系統的pci信息對照,以檢查結果是否正確:
more /proc/pci

[火星人 ] Linux下讀寫I/O port已經有2583次圍觀

http://coctec.com/docs/linux/show-post-135130.html