Linux下PCI设备驱动开发详解(八)

Linux下PCI设备驱动开发详解(八)

RIFFA的Linux驱动文件夹下有6个C源码文件,riffa_driver.c、riffa_driver.h、circ_queue.c、circ_queue.h、riffa.c、riffa.h。

其中riffa.c和riffa.h不属于驱动源码,它们是系统函数调用驱动封装的一层接口,属于用户态应用程序的一部分。

在讲解riffa之前,我们先看一下什么是系统调用。

开源地址:https://github.com/KastnerRG/riffa

一、系统调用

1. 理论基础

1704777731099.png

探究系统调用,以ioctl为例子,通俗来讲,其实就是探究操作系统实现应用层的ioctl对应上特定驱动程序的ioctl的过程。

由于应用程序的ioctl处于用户空间,驱动程序的ioctl处于内核空间,所以这两者之间不属于简单的调用关系;另外,考虑到内核空间操作的安全性,系统调用过程大量的安全性处理,进而使得系统调用看起来十分复杂。

ioctl作用:应用层的ioctl函数传入的cmd和arg参数会直接传入驱动层的ioctl接口,在对应驱动文件会对相应的命令进行操作。对于传递的ioctl命令有一定的规范,具体可以参考:/include/asm/ioctl.h,/Documentation/ioctl-number.txt 这两个文件。

应用层和驱动程序联系如下:

最终ioctl是通过系统调用sys_ioctl软中断陷入到内核,通过系统中断号最终调用到内核态的ioctl函数。

2. 代码实例

构造ioctl命令linux已经给我们提供了宏命令:

_IO    an ioctl with no parameters
_IOW   an ioctl with write parameters (copy_from_user)
_IOR   an ioctl with read parameters  (copy_to_user)
_IOWR  an ioctl with both write and read parameters
相关参数:
/*
    type:    幻数(设备相关的一个字母,避免和内核冲突)
    nr:      命令编号
    datatype:数据类型
*/
_IO(type,nr)           //无参数的命令
_IOR(type,nr,datatype)  //应用从驱动中读数据
_IOW(type,nr,datatype)  //应用从驱动中写数据

下面给出简单的实例用户态应用层代码:

//应用程序
 
#define MOTOR_CMD_BASE'M'  
#define SET_MOTOR_STEP _IOW(MOTOR_CMD_BASE, 1u, int)
#define GET_MOTOR_STEP _IOW(MOTOR_CMD_BASE, 2u, int)
 ...
    int step= 0;
    int value = 0;
    int fd = -1;
 
    fd = open("/dev/motor",O_RDWR);   
    if (fd== -1) {   
        printf("open device error!/n");   
        return -1;   
    }  
   ...  
    printf("Please input the motor step:/n"  
    scanf("%d",&step);    
    if(ioctl(fd, SET_MOTOR_STEP, &step)<0){  
          perror("ioctl error");  
        exit(1);  
    }  
 

驱动程序的代码:

//驱动程序
//假设该驱动程序建立了名为motor的字符设备
 
#define MOTOR_CMD_BASE'M'  
#define SET_MOTOR_STEP _IOW(MOTOR_CMD_BASE, 1u, int)
#define GET_MOTOR_STEP _IOW(MOTOR_CMD_BASE, 2u, int)
 
 
int motor_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)  
{
    int step=0;   
    int value = 0;
    switch (cmd) {  
        case SET_MOTOR_STEP :  
            if(copy_from_user(&step, (int*)arg, sizeof(int)))
                  return fail;
          //处理程序
            break;
        case GET_MOTOR_STEP :
            value = 100;
            if(copy_to_user((int*)arg, &value, sizeof(int)))
                return fail;
            break;
    ...
    }
}  

二、RIFFA代码分析

这里我们直接给出源代码:

fpga_t * fpga_open(int id) 
{
    fpga_t * fpga;

    // Allocate space for the fpga_dev
    fpga = (fpga_t *)malloc(sizeof(fpga_t));
    if (fpga == NULL)
        return NULL;
    fpga->id = id;  

    // Open the device file.
    fpga->fd = open("/dev/" DEVICE_NAME, O_RDWR | O_SYNC);
    if (fpga->fd < 0) {
        free(fpga); 
        return NULL;
    }
    
    return fpga;
}

void fpga_close(fpga_t * fpga) 
{
    // Close the device file.
    close(fpga->fd);
    free(fpga);
}

int fpga_send(fpga_t * fpga, int chnl, void * data, int len, int destoff, 
    int last, long long timeout)
{
    fpga_chnl_io io;

    io.id = fpga->id;
    io.chnl = chnl;
    io.len = len;
    io.offset = destoff;
    io.last = last;
    io.timeout = timeout;
    io.data = (char *)data;

    return ioctl(fpga->fd, IOCTL_SEND, &io);
}

int fpga_recv(fpga_t * fpga, int chnl, void * data, int len, long long timeout)
{
    fpga_chnl_io io;

    io.id = fpga->id;
    io.chnl = chnl;
    io.len = len;
    io.timeout = timeout;
    io.data = (char *)data;

    return ioctl(fpga->fd, IOCTL_RECV, &io);
}

void fpga_reset(fpga_t * fpga)
{
    ioctl(fpga->fd, IOCTL_RESET, fpga->id);
}

int fpga_list(fpga_info_list * list) {
    int fd;
    int rc;

    fd = open("/dev/" DEVICE_NAME, O_RDWR | O_SYNC);
    if (fd < 0)
        return fd;
    rc = ioctl(fd, IOCTL_LIST, list);
    close(fd);
    return rc;
}

对应的ioctls

// IOCTLs
#define IOCTL_SEND _IOW(MAJOR_NUM, 1, fpga_chnl_io *)
#define IOCTL_RECV _IOR(MAJOR_NUM, 2, fpga_chnl_io *)
#define IOCTL_LIST _IOR(MAJOR_NUM, 3, fpga_info_list *)
#define IOCTL_RESET _IOW(MAJOR_NUM, 4, int)

riffa.c代码定义了几个用户操作:打开、关闭、读、写、以及复位。其实都是通过ioctl实现的。如果我们后期扩展,想加上自己的函数,调用一个指定编号的ioctl,同时在驱动里面自己写好这个驱动,就可以实现我们想要的功能了。
eg,

    #define IOCTL_XXX _IOR(MAJOR_NUM, 5, XXX)

分析代码我们看到其实这些功能实现都是想组装一个IOCTRL结构,之后通过IOCTRL把这些参数传递给下层驱动进行控制。

这些参数应该是在每次读写开始的时候都要写到FPGA里面进行设置的。

另外,riffa.c是编译成静态库文件(.a),供大家调用的,其实使用的时候直接包含进来这个riffa.c的源文件也可以。

当然我们也可以使用动态调用.so文件。

三、写在最后的话

至此,Linux下PCI设备驱动开发详解(一)-(八),详细介绍了linux下驱动、内核、FPGA、用户态的理论知识,以及结合著名的开源RIFFA框架,分析了源代码的细节、框架、层次,做到了理论结合实践的最佳应用。

欢迎大家随时留言、沟通交流,详情+V:beijing_bubei(备注来意)

四、参考资料

https://zhuanlan.zhihu.com/p/478247461

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容