Linuxカーネル用のFPGA文字デバイスドライバーを追加します

Linuxのドライバーは、オペレーティングシステムとハードウェアの間にあります。これは、オペレーティングシステムとハードウェアの間のリンクです。今日は、単純なFPGA文字ドライバーをLinuxに追加します。

I.Linuxキャラクタードライバーの紹介

Linuxのドライバーは、キャラクタードライバー、ブロックデバイスドライバー、ネットワークデバイスドライバーに分けられます。キャラクターデバイスドライバーは、最も単純なドライバーの1つです。キャラクターデバイスとは、1バイト×1バイトしか読み書きできず、デバイス内の特定のデータをランダムに読み取ることができないデバイスを指します。データは順番に読み取る必要があります。

II。キャラクタードライバーを追加する手順

ここに写真の説明を挿入
ここに写真の説明を挿入
その他のC / C ++ Linuxビデオ資料については、qun:832218493またはvxを追加して、Zero SoundAcademyを無料でフォローしてください。

1.文字デバイス番号を取得します
。Linuxでは、cat / proc / devicesコマンドを使用してさまざまなデバイスとそれに対応するデバイス番号を表示できます。カーネルでは、通常、次の2つの関数を使用してデバイス番号を取得します

int register_chrdev_region(dev_t first, unsigned int count, char *name);
/* 参数:
    dev_t first - 要申请的设备号(起始)
    unsigned int count - 要申请的设备号数量
    const char *name - 设备名
   返回值:
    成功:0
    失败:负数
   需要事先知道哪个设备号没有被占用!!!
*/
int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
/* 参数:
    dev_t *dev - 用于保存分配到的第一个设备号(起始)
    unsigned int firstminor - 起始次设备号
    unsigned int count - 要分配设备号的数量
    char *name - 设备名
   返回值:
    成功:0
    失败:负数(绝对值是错误码)
   不需要事先知道哪个设备号被占用,系统会根据实际情况自行分配
*/

2.ファイル操作をcdev構造に登録します
。Linuxカーネルコードでは、文字デバイスの記述は通常struct cdevによって行われます。メンバーの1つはfile_operationsへのポインターです。将来的には、ハードウェアを通常のファイルのように操作したいと考えています。デバイスの場合、次のコードに示すように、file_operationsの.open、.read、.write、.release、.llseek関数を完了し、それらを特定のハードウェアデバイス操作にマップする必要があります。

static const struct file_operations fpga_fops = {
    
    
    .read        = fpga_read,
    .write        = fpga_write,
    .llseek = fpga_llseek,
    .open        = fpga_open,
    .release    = fpga_release,
};

ファイル操作を定義した後、ファイル操作をcdev構造に登録してから、デバイスドライバーをカーネルに登録する必要があります。コードは次のとおりです。

III。FPGAアドレスマッピングと読み取りおよび書き込み通信

私が書いたキャラクタードライバーでは、ioremap()関数を使用してアドレスマッピングを実装しました。注意が必要な点は次のとおりです。コアボードのFPGAイネーブルピンとアドレスピンに従って実際のアドレスを決定する必要があります。ブラインドコピー; FPGAの読み取りおよび書き込み操作を実装するためのcopy_to_user()およびcopy_from_user()関数。詳細については、コードを参照してください。

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/device.h>

#include <asm/io.h>
#include <asm/uaccess.h>


#define FPGA_BASE_ADDR 0xF0000000
#define FPGA_SIZE 0x4000000
#define DEV_NAME "fpga"

struct cdev fpga_dev;
dev_t fpga_no;
struct class *fpga_class;


static char *fpga_addr = NULL;

static int fpga_open(struct inode *ino, struct file *filp);
static int fpga_release(struct inode *ino, struct file *filp);
static loff_t fpga_llseek(struct file *, loff_t, int);
static ssize_t fpga_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t fpga_write(struct file *, const char __user *, size_t, loff_t *);

static const struct file_operations fpga_fops = {
    
    
    .read        = fpga_read,
    .write        = fpga_write,
    .llseek = fpga_llseek,
    .open        = fpga_open,
    .release    = fpga_release,
};


static int fpga_open(struct inode *ino, struct file *filp)
{
    
    
    return 0;
}
static int fpga_release(struct inode *ino, struct file *filp)
{
    
    
    return 0;
}
static loff_t fpga_llseek(struct file *file, loff_t off, int whence)
{
    
    
    if(fpga_addr)
        iounmap(fpga_addr);
    if(off <= FPGA_SIZE)
        fpga_addr=ioremap(FPGA_BASE_ADDR+off,FPGA_SIZE-off);
    return off;
}
static ssize_t fpga_read(struct file *file, char __user *buf, size_t count,
            loff_t *ppos)
{
    
    
    printk("user data: %x", buf[0]);
    printk("kern data: %x", fpga_addr[0]);
    if(copy_to_user(buf, fpga_addr, count))
        return -EFAULT;
    
    return count;
}

static ssize_t fpga_write(struct file *file, const char __user *buf,
                        size_t count, loff_t *ppos)
{
    
    
    printk("user data: %x", buf[0]);
    printk("kern data: %x", fpga_addr[0]);
    if(copy_from_user(fpga_addr, buf, count))
        return -EFAULT;
    printk("kern data: %x", fpga_addr[0]);
    return count;
}
static int __init fpga_init(void)
{
    
    
    int ret;
    ret = alloc_chrdev_region(&fpga_no, 0, 1, "fpga"); /* device num you get, from where to allocate, num of this kind of device, device name */
    if(ret)
    {
    
    
        printk("alloc_chrdev_region failed!\n");
        unregister_chrdev_region(fpga_no, 1); /* first device number, num of this kind of device */
        return ret;
    }
    else
    {
    
    
        printk("alloc_chrdev_region success!\n");
    }

    cdev_init(&fpga_dev, &fpga_fops); /* initialize your device settings */

    ret = cdev_add(&fpga_dev, fpga_no, 1); /* register your device to the kernel */
    if(ret)
    {
    
    
        printk("fpga dev add fail.\n");
        unregister_chrdev_region(fpga_no, 1);
        return ret;
    }
    else
    {
    
    
        printk("fpga dev add success!\n");
    }
    /* ==================add module to /dev/fpga=================== */
    fpga_class = class_create(THIS_MODULE, "fpga");
    device_create(fpga_class, NULL, fpga_no, NULL, "fpga");
    /* ==================address mapping ===================== */
    fpga_addr = ioremap(FPGA_BASE_ADDR, FPGA_SIZE);
    if(fpga_addr)
    {
    
    
        printk("ioremap success~\n");
    }
    else
    {
    
    
        unregister_chrdev_region(fpga_no, 1);
        return -ENODEV;
    }
    return 0;
}
static void __exit fpga_exit(void)
{
    
    
    if(fpga_addr)
        iounmap(fpga_addr);
    cdev_del(&fpga_dev);
    unregister_chrdev_region(fpga_no, 1);
    printk("fpga dev exit success!\n");
}
module_init(fpga_init);

上記のコードをカーネルにコンパイルすると、cat / proc / devicesを使用してfpgaデバイスとそのデバイス番号を確認でき、/ dev /ディレクトリでfpgaを確認できます~~~

おすすめ

転載: blog.csdn.net/lingshengxueyuan/article/details/108552547