树莓派驱动开发(五)平台总线platform设备驱动之点亮LED

平台总线设备驱动采用了设备信息和设备注册分离的方式,分别放在了device.c和driver.c文件里面,其中设备注册的方式就是杂项设备驱动的方式,详情请看 树莓派驱动开发(四)杂项设备驱动之点亮LED

直接上代码
device.c

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

void led_release(struct device *dev)
{
        printk("led_release \n");
}

struct resource led_res[] = {
        [0] = {
                .start = 0xfe200000,
                .end = 0xfe200003,
                .flags = IORESOURCE_MEM,
                .name = "GPIO1_IO4DIR",
        },
        [1] = {
                .start = 0xfe20001c,
                .end = 0xfe20001f,
                .flags = IORESOURCE_MEM,
                .name = "GPIO1_IO4H"
        },
        [2] = {
                .start = 0xfe200028,
                .end = 0xfe20002b,
                .flags = IORESOURCE_MEM,
                .name = "GPIO1_IO4L"
        },
};

struct platform_device led_device = {
        /* name必须与static struct platform_driver.name的name字段相同 */
        .name = "led_test",
        .id = -1,
        .resource = led_res,
        .num_resources = ARRAY_SIZE(led_res),
        .dev={
                .release = led_release,
        },

};

static int device_init(void)
{
        /*
                注册驱动程序并将其放入由内核维护的驱动程序列表中
                以便,每当发现新的匹配时,就可以按需调用其probe()函数
        */
        platform_device_register(&led_device);
        printk("platform_device_register ok \n");

        return 0;
}

static void device_exit(void)
{
        platform_device_unregister(&led_device);

        printk("goodbye! \n");
}

module_init(device_init);
module_exit(device_exit);

MODULE_LICENSE("GPL");
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h> //注册杂项设备头文件
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/io.h>

unsigned int *vir_gpio4_dr=NULL;
unsigned int *vir_gpio4_h=NULL;
unsigned int *vir_gpio4_l=NULL;

struct resource *gpio4_dir;
struct resource *gpio4_h;
struct resource *gpio4_l;

struct resource *leddir_mem_test;
struct resource *ledh_mem_test;
struct resource *ledl_mem_test;

ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{
        char kbuf[64] = {0};
        if ( copy_from_user( kbuf, ubuf, size) != 0)
        {
                printk( "copy_from_user error\n ");
                return -1;
        }
        printk( "kbuf is %s\n ", kbuf);
        *vir_gpio4_dr |= (001<<(3*4));
        if( kbuf[0] == 1)
        {

                *vir_gpio4_h |=(1<<4);
        }
        else if( kbuf[0]==0)
        {
                *vir_gpio4_l |=(1<<4);
        }
        return 0;
}

int misc_release( struct inode *inode, struct file *file)
{
        printk( "hello misc_relaease bye bye \n ");
        return 0;
}

int misc_open( struct inode *inode, struct file *file)
{
        printk( "hello misc_open\n ");
        return 0;
}
//文件操作集
struct file_operations misc_fops = {
                .owner = THIS_MODULE,
                .open = misc_open,
                .release = misc_release,
                .write = misc_write,
                };
//miscdevice 结构体
struct miscdevice misc_dev = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = "hello_misc",
        .fops = &misc_fops,
};


int led_probe( struct platform_device *pdev)
{

        int ret;

        printk( "led_probe\n");
        ret = misc_register( &misc_dev); //注册杂项设备
        if (ret < 0)
        {
                printk( "misc registe is error \n");
        }
        printk( "misc registe is succeed \n");

        gpio4_dir = platform_get_resource( pdev, IORESOURCE_MEM, 0);
        gpio4_h   = platform_get_resource( pdev, IORESOURCE_MEM, 1);
        gpio4_l   = platform_get_resource( pdev, IORESOURCE_MEM, 2);

        vir_gpio4_dr = ioremap( gpio4_dir->start,4);
        if( vir_gpio4_dr== NULL )
        {
                printk( "gpio4dr ioremap error\n");
                return EBUSY;
        }

        vir_gpio4_h = ioremap( gpio4_h->start,4);
        if( vir_gpio4_h== NULL)
        {
                printk( "gpio4h ioremap error\n");
                return EBUSY;
        }

        vir_gpio4_l = ioremap( gpio4_l->start,4);
        if( vir_gpio4_l == NULL)
        {
                printk( "gpio4l ioremap error\n");
                return EBUSY;
        }
        printk( "gpio ioremap success\n");

        return 0;
#if 0
        leddir_mem_test = request_mem_region( gpio4_dir->start, gpio4_dir->end - gpio4_dir->start +1, "led_dir");
        if( leddir_mem_test == NULL){
                printk( "platform_get_resource iserror \n");
                goto errdir_region;
        }

        ledh_mem_test = request_mem_region( gpio4_dir->start, gpio4_dir->end - gpio4_dir->start +1, "led_dir");
        if( ledh_mem_test == NULL){
                printk( "platform_get_resource iserror \n");
                goto errh_region;
        }

        ledl_mem_test = request_mem_region( gpio4_dir->start, gpio4_dir->end - gpio4_dir->start +1, "led_dir");
        if( ledl_mem_test == NULL){
                printk( "platform_get_resource iserror \n");
                goto errl_region;
        }
        return 0;

errdir_region:
        release_mem_region( gpio4_dir->start, gpio4_dir->end - gpio4_dir->start +1);

        return -EBUSY;
errh_region:
        release_mem_region( gpio4_h->start, gpio4_h->end - gpio4_h->start +1);

        return -EBUSY;
errl_region:
        release_mem_region(gpio4_l->start, gpio4_l->end - gpio4_l->start +1);

        return -EBUSY;
#endif
}

int led_remove( struct platform_device *pdev)
{
        printk("led_remove\n");
        return 0;
}
struct platform_driver led_driver ={
        .probe = led_probe,
        .remove = led_remove,
        .driver = {
                .owner = THIS_MODULE,
                .name = "led_test"
        },
};

static int led_driver_init( void)
{
        int ret =0;
        ret = platform_driver_register( &led_driver);
        if( ret<0)
        {
                printk( "platform_driver_register error \n");
        }
        printk( "platform_driver_register ok \n");
        return 0;
}

static void led_driver_exit(void)
{
        misc_deregister( &misc_dev); //卸载杂项设备
        printk( "misc gooodbye! \n");
        iounmap( vir_gpio4_dr);
        iounmap( vir_gpio4_h);
        iounmap( vir_gpio4_l);

        // platform 驱动卸载
        platform_driver_unregister( &led_driver);
        printk( "goodbye! \n");
}

module_init( led_driver_init);
module_exit( led_driver_exit);

MODULE_LICENSE( "GPL");

app.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
        int fd;
        char buf[10];
        fd = open("/dev/hello_misc",O_RDWR);//打开设备节点
        if(fd < 0)
        {
                perror("open error \n");
                return fd;
        }
        buf[0]=atoi(argv[1]);
        write(fd,buf,sizeof(buf)); //向内核层写数据
        close(fd);
        return 0;
}

Makefile

# 判断是否在内核构建系统内。如果没有定义 KERNELRELEASE,则表示这是从命令行调用。
ifneq ($(KERNELRELEASE),)
        # 如果不是内核构建系统,则定义需要编译的模块对象文件。
        # obj-m 是内核模块的编译变量,+= 表示添加模块文件(.o)
        obj-m += device.o
        obj-m += driver.o
else
        # 定义内核头文件的位置,使用当前正在运行的内核版本。
        KDIR := /home/interest/linux/lib/modules/$(shell uname -r)/build

        # 定义当前的工作目录。
        PWD := $(shell pwd)

        # 默认目标。如果调用了 make 而没有指定目标,会执行这个部分。
        # -C $(KDIR) 表示切换到内核源码目录进行编译
        # M=$(PWD) 表示在当前模块的目录下执行内核模块编译
all:
        $(MAKE) -C $(KDIR) M=$(PWD) modules

        # 清理目标:用于清理编译产生的中间文件。
clean:
        rm -f *.mod.c *.order *.ko *.o *.mod *.symvers
endif

编译

Make //编译驱动代码
gcc app.c -o app //编译测试代码
sudo insmod driver.ko //加载驱动模块
sudo ./app 1 //led亮
sudo ./app 0 //led灭
sudo rmmod driver //卸载模块

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值