Linux教程

linux driver --- platform框架应用完整实例

本文主要是介绍linux driver --- platform框架应用完整实例,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

平台设备文件

button_device.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>

static void button_release(struct device *dev)
{
    printk("%s\n", __FUNCTION__);
    return;
}

struct resource    button_resource[] = {
    {
        .start = 0x20c406c,
        .end = 0x20c406c+3,        // IORESOURCE_MEM必须要加上end,不然会报错
        .name = "CCGR",
        .flags = IORESOURCE_MEM,
    },
    {
        .start = 0x229000c,
        .end = 0x229000c+3,
        .name = "SW_MUX_CTL",
        .flags = IORESOURCE_MEM,
    },
    {
        .start = 0x2290050,
        .end = 0x2290050+3,
        .name = "SW_PAD_CTL",
        .flags = IORESOURCE_MEM,
    },
    {
        .start = 0x20ac004,
        .end = 0x20ac004+3,
        .name = "GDIR",
        .flags = IORESOURCE_MEM,
    },
    {
        .start = 0x20ac008,
        .end = 0x20ac008+3,
        .name = "PSR",
        .flags = IORESOURCE_MEM,
    },
    {
        .start = 1,
        .end = 0,
        .name = "pin",
        .flags = IORESOURCE_IRQ,
    },
    {
        .start = 30,
        .end = 0,
        .name = "clock_offset",
        .flags = IORESOURCE_IRQ,
    },
};

struct platform_device button_device = {
    .name = "my_button",     // 这个名字必须要和设备资源结构体里面的name一致,不然这两个模块匹配不了
    .id = -1,
    .num_resources = ARRAY_SIZE(button_resource),
    .resource = button_resource,
    .dev = {
        .release = button_release,
    },
};

// 入口函数
static int button_platform_device_init(void)
{
    int ret = 0;
    printk("%s\n", __FUNCTION__);
    ret = platform_device_register(&button_device);  // 注册设备信息
    return ret;
}

// 出口函数
static void button_platform_device_exit(void)
{
    printk("%s\n", __FUNCTION__);

    platform_device_unregister(&button_device);
}

module_init(button_platform_device_init);
module_exit(button_platform_device_exit);
MODULE_LICENSE("GPL");

平台驱动文件

button_driver.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <asm/mach/map.h>
#include <linux/platform_device.h>
#include <asm/io.h>

static u32 *vi_ccgr;
static u32 *vi_mux_ctl;
static u32 *vi_pad_ctl;
static u32 *vi_gdir;
static u32 *vi_psr;
static u32 pin;
static u32 clock_offset;

static int major = 0;
static struct class *button_class;

static ssize_t button_drv_read(struct file * file, char __user * buf, size_t size, loff_t *offset)
{
    char status = 0;
    int ret;
    if (*vi_psr & (1<<pin)) {
        //printk("按键点击了\n");
        status = 1;
    } else {
        status = 0;
    }

    ret = copy_to_user(buf, &status, 1);
    return 1;
}

static ssize_t button_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{

    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}

static int button_drv_open(struct inode *node, struct file *file)
{
    
    // 初始化设备
    *(vi_ccgr) |= (3<<clock_offset);
    *(vi_mux_ctl) &= ~0xf;
    *(vi_mux_ctl) |= 0x5;
    *(vi_gdir) &= ~(1<<pin);
    
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}
static int button_drv_close(struct inode *node, struct file *file)
{
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}
static struct file_operations button_opr = {
    .open = button_drv_open,
    .release = button_drv_close,
    .read = button_drv_read,
    .write = button_drv_write,
};

static int button_probe(struct platform_device *pdev)
{
    int i = 0;
    struct resource *res;
    u32 ph_addr[5];
    int err;

    // 获取资源

    for (i=0;i<5;i++) {
        res = platform_get_resource(pdev, IORESOURCE_MEM, i);
        if (res == NULL) {
            printk("not get resource\n");
            return -1;
        }
        ph_addr[i] = res->start;
    }
    res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    pin = res->start;
    res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
    clock_offset = res->start;

    // 内存映射
    vi_ccgr = ioremap(ph_addr[0], 4);
    vi_mux_ctl = ioremap(ph_addr[1], 4);
    vi_pad_ctl = ioremap(ph_addr[2], 4);
    vi_gdir = ioremap(ph_addr[3], 4);
    vi_psr = ioremap(ph_addr[4], 4);
    
    // 完成设备注册的操作
    // register_chrdev() class_create()  device_create()
    major = register_chrdev(0, "my_button", &button_opr);

    button_class = class_create(THIS_MODULE, "button_class");
    err = PTR_ERR(button_class);
    if (IS_ERR(button_class)) {
        unregister_chrdev(major, "my_button");
        return -1;
    }

    device_create(button_class, NULL, MKDEV(major, 0), NULL, "my_button");

    printk("%s\n", __FUNCTION__);
    return 0;
}

static int button_remove(struct platform_device *pdev)
{
    printk("%s\n", __FUNCTION__);

    // 释放虚拟内存
    iounmap(vi_ccgr);
    iounmap(vi_mux_ctl);
    iounmap(vi_pad_ctl);
    iounmap(vi_gdir);
    iounmap(vi_psr);
    
    // 完成设备取消注册的操作
    device_destroy(button_class, MKDEV(major,0));

    class_destroy(button_class);

    unregister_chrdev(major, "my_button");

    printk("%s\n", __FUNCTION__);
    return 0;
}

struct platform_driver button_driver = {
    .probe = button_probe,
    .remove = button_remove,
    .driver = {
        .name = "my_button",
    },
};

// 入口函数
static int button_platform_driver_init(void)
{
    int ret = 0;
    printk("%s\n", __FUNCTION__);
    ret = platform_driver_register(&button_driver);  // 注册设备信息
    return ret;
}

// 出口函数
static void button_platform_driver_exit(void)
{
    printk("%s\n", __FUNCTION__);
    platform_driver_unregister(&button_driver);  // 注册设备信息
}

module_init(button_platform_driver_init);
module_exit(button_platform_driver_exit);
MODULE_LICENSE("GPL");

应用层测试程序

button_test.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

int main(int argc, char **argv)
{
    int fd;
    char status = 0;
    int ret = 0;
    int bnt = 0;
    
    if (argc !=2 ) {
        printf("Usage: %s <dev-path>\n", argv[0]);
        return -1;
    }
    fd = open(argv[1], O_RDWR);
    if (fd < 0) {
        perror("open error");
        return -1;
    }

    while(1) {
        ret = read(fd, &status, 1);
        if (ret < 0) {
            perror("read error");
            return -1;
        } else if (ret == 1 && status == 1) {
            printf("button %d\n", bnt++);
        }
    }

    return 0;
}

 

Makefile文件

Makefile

ARCH=arm
CROSS_COMPILE=arm-linux-gnueabihf-   // 该参数与你的交叉编译工具有关
export  ARCH  CROSS_COMPILE

KERN_DIR = /home/hxd/workdir/ebf_linux_kernel_6ull_depth1/build_image/build   // 该目录与你的编译好的内核目录有关

all:
    make -C $(KERN_DIR) M=`pwd` modules 
    $(CROSS_COMPILE)gcc -o button_test button_test.c 

clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
    rm -rf modules.order
    rm -f button_test

obj-m    += button_device.o button_driver.o

编译运行

编译好后将得到的button_device.ko,button_driver.ko和button_test拷贝到开发板上

 

这篇关于linux driver --- platform框架应用完整实例的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!