Linux内核混杂设备驱动

1.linux内核混杂设备驱动


1.1混杂设备驱动特点:

本质上还是一类字符设备,在驱动软件上,混杂设备的主设备号已经由内核指定主设备号为10;
各个混杂设备个体通过次设备号来区分;


1.2linux内核描述混杂设备的数据结构

struct miscdevice
{
int minor;
int name;
const struct file_operatiions *fops;
...
};
作用:描述混杂设备
成员:
minor:混杂设备对应的次设备号,切记主设备号
由内核指定为10,一般指定为宏MISC_DYNAMIC_MINOR,
表明让内核来帮你分配一个次设备号
name:设备文件名,并且设备文件由内核自动帮你创建
fops:指向混杂设备的硬件操作方法


1.3实现一个混杂设备驱动的编程步骤:

1.定义初始化混杂设备对象
struct miscdevice led_misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = “myled”,
.fops = &led_fops,
};

2.向内核注册混杂设备对象,一旦注册完毕,内核就有一个真是的混杂设备驱动
misc_register (&led_misc);
3.从内核卸载混杂设备对象
misc_deregister(&led_misc);

案例:

利用混杂设备编程思想来实现LED驱动

 实施步骤:
1.mkdir /opt/drivers/day05/2.0
2.cd /opt/drivers/day05/2.0
3.vim led_drv.c
4.vim led_test.c
5.vim Makefile
6.make
7.arm-linux-gcc -o led_test led_test.c
8.cp led_test led_drv.ko /opt/rootfs

ARM:
1.insmod led_drv.ko
2.ls /dev/myled -lh //查看主,次设备号的信息
3../led_test

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h> //struct miscdevice
#include <linux/fs.h> //strcut file_operations
#include <asm/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/uaccess.h> //copy_*

//声明描述LED硬件相关的数据结构
struct led_resource {
    int gpio;
    char *name;
};
//定义初始化LED硬件信息
static struct led_resource led_info[] = {
    [0] = {
        .gpio = S5PV210_GPC0(3),
        .name = "LED1"
    },
    [1] = {
        .gpio = S5PV210_GPC0(4),
        .name = "LED2"
    }
};

//定义开关命令字
#define LED_ON  0x100001
#define LED_OFF 0x100002

static long led_ioctl(struct file *file,
                        unsigned int cmd,
                        unsigned long arg)
{
    //定义内核缓冲区,保存用户要操作灯的编号
    int kindex;

    //拷贝用户数据到内核
    copy_from_user(&kindex, (int *)arg, sizeof(kindex));
    
    //解析用户命令,操作硬件
    switch(cmd) {
        case LED_ON:
            gpio_set_value(led_info[kindex - 1].gpio, 1);
            break;
        case LED_OFF:
            gpio_set_value(led_info[kindex - 1].gpio, 0);
            break;
    }
    return 0;
}

//定义初始化硬件操作的方法
static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = led_ioctl //发送命令 
};

//定义初始化混杂设备对象
static struct miscdevice led_misc = {
    .minor = MISC_DYNAMIC_MINOR, //内核分配次设备号
    .name = "myled", //设备文件名,内核自动创建/dev/myled
    .fops = &led_fops //混杂设备对象具有的硬件操作方法
};

static int led_init(void)
{
    int i;
    //注册混杂设备对象到内核
    misc_register(&led_misc);
    //申请GPIO,配置GPIO为输出,输出0
    for (i = 0; i < ARRAY_SIZE(led_info); i++) {
        gpio_request(led_info[i].gpio, led_info[i].name);
        gpio_direction_output(led_info[i].gpio, 0);
    }
    return 0;
}

static void led_exit(void)
{
    int i;
    //输出0,释放GPIO资源
    for (i = 0; i < ARRAY_SIZE(led_info); i++) {
        gpio_set_value(led_info[i].gpio, 0);
        gpio_free(led_info[i].gpio);
    }
    //卸载混杂设备对象
    misc_deregister(&led_misc);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LED_ON  0x100001
#define LED_OFF 0x100002

int main(void)
{
    int fd;
    int uindex; //用户缓冲区

    //打开设备
    //open->....->调用led_open
    fd = open("/dev/myled", O_RDWR);
    if (fd < 0) {
        printf("打开设备失败!\n");
        return -1;
    }
    
    //write->...->调用led_write
    while (1) {
        uindex = 1;
        ioctl(fd, LED_ON, &uindex);
        sleep(1);
        uindex = 2;
        ioctl(fd, LED_ON, &uindex);
        sleep(1);
        uindex = 1;
        ioctl(fd, LED_OFF, &uindex);
        sleep(1);
        uindex = 2;
        ioctl(fd, LED_OFF, &uindex);
        sleep(1);
    }
    //关闭设备
    //close->...->调用led_close
    close(fd);
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章