标签 GPIO 下的文章

“”

在用户空间访问 I/O 端口
以上函数主要提供给设备驱动使用,但它们也可在用户空间使用,至少在 PC上可以。 GNU C 库在 中定义了它们。如果在用户空间代码中使用必须满足以下条件:

(1)程序必须使用 -O 选项编译来强制扩展内联函数。

(2)必须用ioperm 和 iopl 系统调用(#include ) 来获得对端口 I/O 操作的权限。ioperm 为获取单独端口操作权限,而 iopl 为整个 I/O 空间的操作权限。 (x86 特有的)

(3)程序以 root 来调用 ioperm 和 iopl,或是其父进程必须以 root 获得端口操作权限。(x86 特有的)

若平台没有 ioperm 和 iopl 系统调用,用户空间可以仍然通过使用 /dev/prot 设备文件访问 I/O 端口。注意:这个文件的定义是体系相关的,并且I/O 端口必须先被注册。

ioperm和iopl介绍。

1.ioperm
 
功能描述:

为调用进程设置I/O端口访问权能。ioperm的使用需要具有超级用户的权限,只有低端的[0-0x3ff] I/O端口可被设置,要想指定更多端口的权能,可使用iopl函数。这一调用只可用于i386平台。 

用法:

int ioperm(unsigned long from, unsigned long num, int turn_on);      

参数:

from:起始端口地址。

num:需要修改权能的端口数。

turn_on:端口的新权能位。1为开启,0为关闭。

返回说明:

成功执行时,返回0。失败返回-1,errno被设为以下的某个值

EINVAL:参数无效
EIO:这一调用不被支持
EPERM:调用进程权能不足。 

  1. iopl

功能描述:该调用用于修改当前进程的操作端口的权限。可以用于所有65536个端口的权限。因此,ioperm相当于该调用的子集。和ioperm一样,这一调用仅适用于i386平台。 

用法:
   int iopl(int level);

参数:

level: 端口的权限级别。为3时可以读写端口。默认权能级别为0,用户空间不可读写。

返回说明:成功执行时,返回0。失败返回-1,errno被设为以下的某个值

EINVAL:level值大于3
ENOSYS:未实现该调用
EPERM:调用进程权能不足。 

二、程序示例

  1. ioperm.c

操作低于0x3FF的端口

该程序首先设置0x3FF端口的读写权限,然后读出原先的值,然后将原值的LSB翻转并写回端口,并在此读取端口值。

/*Description:This function is used to test ioperm()*/

#define PORT_ADDR 0x3FF 

int main(void)
{
      int ret;
      char port_val;

      /*set r/w permission of port_addr on, only one port*/
      ret = ioperm(PORT_ADDR, 1, 1);
      if(ret < 0){
           perror("ioperm set error");
           return 0;
      }
      port_val = inb(PORT_ADDR);
      printf("Original value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);    
      /*reverse the least significant bit */
      outb(port_val^0x01, PORT_ADDR);
      port_val = inb(PORT_ADDR);
      printf("Current value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);    
      /*set r/w permission of PORT_ADDR off, only one port*/
      ret = ioperm(PORT_ADDR, 1, 0);
      if(ret < 0){
           perror("ioperm set error");
           return 0;
      }
      return 0;
} 

程序执行的结果是:

[root@localhost misc-progs]# ./a.out
Original value of port 0x3ff is : 00
Current value of port 0x3ff is : 01
[root@localhost misc-progs]# ./a.out
Original value of port 0x3ff is : 01
Current value of port 0x3ff is : 00

该程序执行几次,将进行几次的LSB翻转。

这里有一个问题值得注意:在2.4(RH9)的内核上,当端口值大于0x3FF时,执行该程序则会报错:ioperm set error: Invalid argument。即IO端口的值设置有问题,超出了限制。但是在2.6内核下并没有报错,而且执行结果也符合程序既定的结果。但是man ioperm中仍然说明了0x3FF的限制。暂且存疑。

  1. iopl.c

该程序可以操作所有65536个端口。

该程序首先设置0x3FF端口的读写权限,然后读出原先的值,然后将原值的LSB翻转并写回端口,并在此读取端口值。

代码如下:

/*Description:This function is used to test iopl()*/

#define PORT_ADDR 0x3FF 

int main(void)
{
      int ret;
      char port_val; 

      /*set r/w permission of all 65536 ports*/
      ret = iopl(3);
      if(ret < 0){
           perror("iopl set error");
           return 0;
      }

      port_val = inb(PORT_ADDR);
      printf("Original value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);    

      /*reverse the least significant bit */
      outb(port_val^0x01, PORT_ADDR);
      port_val = inb(PORT_ADDR);
      printf("Current value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);  
      /*set r/w permission of  all 65536 ports*/
      ret = iopl(0);

      if(ret < 0){
           perror("iopl set error");
           return 0;
      }
      return 0;
}

程序执行结果:

[root@linux misc-progs]# ./a.out
Original value of port 0x3ff is : 01
Current value of port 0x3ff is : 00
[root@linux misc-progs]# ./a.out
Original value of port 0x3ff is : 00
Current value of port 0x3ff is : 01

该程序执行几次,将进行几次的LSB翻转。
Referenced from:http://blog.chinaunix.net/uid-10167808-id-25953.html

linux O_WRONLY 头文件 #include "fcntl.h"

#include <bits/stdc++.h>
#include "unistd.h"
#include "fcntl.h"

using namespace std;
#define MAX_BUF 256

int main(int argc, char* argv[])
{
    int fd;
    char buf[MAX_BUF]; 
    int gpio = 1;

    fd = open("/sys/class/gpio/export", O_WRONLY);
    sprintf(buf, "%d", gpio); 
    write(fd, buf, strlen(buf));
    close(fd);

    sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio);
    fd = open(buf, O_WRONLY);
    // Set out direction
    write(fd, "out", 3); 
    // Set in direction
    write(fd, "in", 2); 
    close(fd);

    sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);
    fd = open(buf, O_WRONLY);
    // Set GPIO high status
    write(fd, "1", 1); 
    // Set GPIO low status 
    write(fd, "0", 1);
    close(fd);

    char value;
    sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);
    fd = open(buf, O_RDONLY);
    read(fd, &value, 1);
    if(value == '0')
    { 
        // Current GPIO status low
    }
    else
    {
        // Current GPIO status high
    }
    close(fd);

    fd = open("/sys/class/gpio/unexport", O_WRONLY);
    sprintf(buf, "%d", gpio);
    write(fd, buf, strlen(buf));
    close(fd);

    return 0;
}