Menu Close

Ubuntu Linux 简单字符设备驱动程序编写

此文章介绍了如何在 Ubuntu 中编写一个简单字符设备驱动程序。

相关参考文章:SOC 教学教案

 

先进入 Ubuntu 并在主目录 home 下创建一个名为 work 的文件夹。在终端中进入此文件夹后,运行以下命令创建一个新的 PetaLinux 工程。

sptl
petalinux-create - t project --template zynq -n fii-module

注意我们将其命名为了 fii-module,与我们使用的开发板相符。

%title插图%num

接下来我们将把 FPGA SDK 目录 FII_7030.sdk 拷贝到我们刚创建的 work 文件夹并编辑 fii_module。我们将使用一下命令进入 fii_module 工程目录。

cd fii-module

接下来我们将运行 sptl 命令并且使用以下命令编辑工程。

petalinux-config --get-hw-description ~/work/FII_7030.sdk/

%title插图%num

我们不需要修改任何配置,直接关闭打开的窗口。

%title插图%num

%title插图%num

下面我们将使用以下命令填入并创建 fpga 设备树驱动。

petalinux-create -t modules --name fii-driver

%title插图%num

接下来我们可以进入 ~/work/fii-module/project-spec/meta-user/recipes-modules/fii-driver/files 目录下通过编辑 fii-driver.c 文件编辑驱动。

%title插图%num

文件打开后,我们将以此修改:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>  /* for put_user */
#include <asm/errno.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
//#include <linix/of_platform.h>

/*
    0x43c0_0000 + 4 = value
    0x43c0_0000 + 8 = direction
*/

#define DEVICE_NAME   "fii-module"
#define CLASS_NAME    "fii-module_class"
static int major;
static struct class  *swled_class;

static  unsigned int *gpio_data;
static  unsigned int *gpio_dir ;

static int swled_open(struct inode* node,struct file* filp){

    unsigned int gpio_base = (0x43c00000);
    gpio_data = ioremap(gpio_base,8);

    if(gpio_data){
        printk("kernel: ioremap(0x%08x)=0x%08x \n",gpio_base,gpio_data);
    }

    else{
        return -EINVAL;
    }

    gpio_dir = gpio_data + 1;

    printk("kernel: gpio_data address = 0x%08x \n", gpio_data);
    printk("kernel: gpio_dir  address = 0x%08x \n", gpio_dir);

    return 0;
}


int swled_release(struct inode *inode, struct file *filp)
{
//    MOD_DEC_USE_COUNT;
    iounmap(gpio_data);
    return 0;
}

/*
    0x43c0_0000 + 0 = value
    0x43c0_0000 + 4 = direction
*/

static ssize_t swled_read(struct file *filp, char *buf, size_t size, loff_t *offset)
{
    unsigned char val[32];
    unsigned int temp;
    unsigned int *addr_p;
    int i = 0, cnt;
    printk("kernel: swled_read start.... size = %d\n", size);
    cnt = size;

    addr_p = gpio_data;
    temp = *addr_p ;

    for(i = 0; i < cnt/4; i++ )
    {
        val[i*4 + 3] = temp & 0xff;
        val[i*4 + 2] = (temp >> 8) & 0xff;
        val[i*4 + 1] = (temp >> 16) & 0xff;
        val[i*4 + 0] = (temp >> 24) & 0xff;
        addr_p ++;
        temp = *addr_p;
    }

    if(i % 4 == 1)
    {
        val[i*4 + 0] = temp & 0xff;
    }

    if(i % 4 == 2)
    {
        val[i*4 + 1] = temp & 0xff;
        val[i*4 + 0] = (temp >> 8) & 0xff;
    }

    if(i % 4 == 3)
    {
        val[i*4 + 2] = temp & 0xff;
        val[i*4 + 1] = (temp >> 8) & 0xff;
        val[i*4 + 0] = (temp >> 16) & 0xff;
    }

    copy_to_user(buf, val, cnt);
    return cnt;
}

static ssize_t swled_write(struct file * filp, const char __user *buf, size_t size, loff_t * offset) {
    unsigned char val[32];
    unsigned int temp = 0;
    unsigned int * addr_p;
    int i,cnt;

    memset(val,0,32);
    addr_p = gpio_data;

    printk("kernel: swled_write start.... size = %d\n", size);
    copy_from_user(&val, buf, size);
    cnt = size - 1;

    printk("kernel: val[0] = 0x%08x \n", val[0]);

    if(val[0] == 'w')
    {
        temp = val[2];
        temp = temp << 8 | val[3];
        temp = temp << 8 | val[4];
        temp = temp << 8 | val[5];

        *addr_p = temp;
        printk("kernel: gpio_data = 0x%08x \n", temp);
    }

    else if(val[0] == 'd')
    {
        addr_p ++;
        temp = val[2];
        temp = temp << 8 | val[3];
        temp = temp << 8 | val[4];
        temp = temp << 8 | val[5];

        *addr_p = temp;
        printk("kernel: gpio_dir = 0x%08x \n", temp);
    }

    else
    {
        printk("kernel: invalid parameter \n");
    }

    return size;
}

static struct file_operations   swled_oprs = {
    .owner  = THIS_MODULE,
    .open   = swled_open,
    .write  = swled_write,
    .read   = swled_read,
    .release= swled_release,
};

static int swled_init(void){       /* register device  */
/*
 *
 * int register_chrdev (unsigned int major,
 *                      const  char *name,
 *                      struct file_operations*fops);
 *
 *  major => 0, automatic mode; others major device ID
 */
    major=register_chrdev(0, DEVICE_NAME, &swled_oprs);
    if (major < 0) {
         printk ("Registering the character device failed with %d\n", major);
         return major;

    }

    swled_class = class_create(THIS_MODULE, CLASS_NAME);
    device_create(swled_class, NULL, MKDEV(major,0), NULL, DEVICE_NAME);
    return 0;
}

static void swled_exit(void){
    unregister_chrdev(major, DEVICE_NAME);
    device_destroy(swled_class,MKDEV(major,0));
    class_destroy(swled_class);
};

module_init(swled_init);
module_exit(swled_exit);

MODULE_LICENSE("GPL");

代码写完后请运行以下指令编辑 PetaLinux 驱动配置。

petalinux-config -c rootfs

图形界面打开后,进入 modules 并按下 [Y] 选择包含 fii-driver。退出前不要忘记保存。

%title插图%num

%title插图%num

接下来我们将使用以下命令编译内核。

petalinux-build -c kernel

%title插图%num

接下来我们将使用以下命令编译驱动。

petalinux-build -c fii-driver

%title插图%num

使用以下命令编译整个工程:

petalinux-build

%title插图%num

我们现在可以通过执行以下命令创建工程文件:

petalinux-package --boot --fsbl --fpga --u-boot --force

%title插图%num

我们将把 ~/work/fii-module/images/linux/ 中的 BOOT.BIN 和 image.ub 文件拷贝到 SD 卡的 boot 启动分区中,并把 rootfs.cpio 解压到 rootfs 分区中。

我们也将把 ~/work/fii_module/build/tmp/sysroots-components/plnx_zynq7/fii-driver/lib/modules/4.14.0-xilinx-v2018.3/extra/fii-driver.ko 文件拷入到 SD 卡中。

拷贝完之后请把 SD 卡插入 fii_7030 开发板并启动系统,并通过 PuTTY 建立连接。注意用户名和密码都是 root。

 

Posted in 教材与教案

2 Comments

发表评论

相关链接