Linux驱动开发 | 设备类

使用的内核版本为3.4.39,开发工具为Ubuntu的vim编辑器。

一、设备类

1.1 简介

        操作系统为方便描述设备,提高代码的复用性,linux为用户封装好了一些描述设备的类,用户在编写关于设备的代码时可以使用。

1.2 主要结构体和方法

#include  <linux/device.h>

// 描述设备类的结构体

struct class {
    const char        *name;
    struct module        *owner;

    struct class_attribute        *class_attrs;
    struct device_attribute        *dev_attrs;
    struct bin_attribute        *dev_bin_attrs;
    struct kobject            *dev_kobj;

    int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
    char *(*devnode)(struct device *dev, umode_t *mode);

    void (*class_release)(struct class *class);
    void (*dev_release)(struct device *dev);

    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);

    const struct kobj_ns_type_operations *ns_type;
    const void *(*namespace)(struct device *dev);

    const struct dev_pm_ops *pm;

    struct subsys_private *p;
};

// 创建设备类

extern struct class * __must_check __class_create(struct module *owner,
                          const char *name,
                          struct lock_class_key *key);

#define class_create(owner, name)        \
({                        \
    static struct lock_class_key __key;    \
    __class_create(owner, name, &__key);    \
})

// 销毁设备类
extern void class_destroy(struct class *cls);

// 创建设备文件

struct device *device_create(struct class *cls, struct device *parent,
                 dev_t devt, void *drvdata,
                 const char *fmt, ...);

// 销毁设备文件
extern void device_destroy(struct class *cls, dev_t devt);

1.3 代码思路

         在/sys/class目录下可以查看操作系统的设备类,在初始化的函数中使用class_create函数可以创建一个设备类,创建成功后可以在该目录查看。在/dev可以查看操作系统下的设备文件,在初始化函数中使用device_create函数可以自动创建一个设备文件,创建成功后可以在该目录下查看,使用这个接口就可以避免每次插入驱动都需要重新创建设备文件了。最后在出口函数中销毁创建的类和设备文件。

1.4 示例代码

Makefile

KERNEL_DIR = /opt/wkspace/kernel-build/kernel-3.4.39/

obj-m += myclass.o

all:
        make modules M=`pwd` -C $(KERNEL_DIR) CROSS_COMPILE=/usr/local/arm/arm-eabi-4.8/bin/arm-eabi-
clean:
        make modules clean M=`pwd` -C  $(KERNEL_DIR) CROSS_COMPILE=/usr/local/arm/arm-eabi-4.8/bin/arm-eabi-
        rm -rf app 

myclass.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/kdev_t.h>

struct class *cls = NULL;
struct device *dev = NULL;

int major = 100,minor = 0;

static int __init mydev_init(void){
        printk(KERN_INFO "mydev init!\n");

        cls = class_create(THIS_MODULE,"myclass");
        if(cls == NULL){
                printk(KERN_INFO "create class failed!\n");
                return -1;
        }

        dev = device_create(cls,NULL,MKDEV(major,minor),NULL,"mydev");
        if(dev == NULL){
                printk(KERN_INFO "create device failed!\n");
                return -1;
        }

        return 0;
}

static void __exit mydev_exit(void){
        printk(KERN_INFO "platform dev exit!\n");

        device_destroy(cls,MKDEV(major,minor));
        class_destroy(cls);
        return ;
}

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");

二、杂交设备类misc

2.1 简介

        misc是操作系统供用户使用的一个描述设备的通用的类,操作系统中也有专用设备类,在没有对应的专用设备类时,我们可以选择misc杂交设备类。杂交设备类只提供一些简单的平台操作和处理机制,涉及到复杂的电路和操作的时候可能不适合。

2.2 杂交设备类和方法

#include <linux/miscdevice.h>

// 杂交设备类描述结构体

struct miscdevice  {
    int minor;    // 次设备号
    const char *name;   // 设备名称
    const struct file_operations *fops;   // 驱动方法
    struct list_head list;   // 链表结构
    struct device *parent;   // 继承基类
    struct device *this_device;
    const char *nodename;
    umode_t mode;
};

// 杂交设备类注册

extern int misc_register(struct miscdevice * misc);

// 杂交设备类注销
extern int misc_deregister(struct miscdevice *misc);

// 描述设备操作的结构体

struct file_operations { struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);

 // 应用使用read函数时调用该指针指向的函数
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

 // 应用使用write函数时调用该指针指向的函数

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 

ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);  // 应用使用open函数时调用该指针指向的函数
    int (*flush) (struct file *);
    int (*release) (struct inode *, struct file *);  // 应用使用close函数时调用该指针指向的函数
    int (*fsync) (struct file *, loff_t, loff_t, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);

ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);

ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);

ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);

ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int); };

2.3 代码思路

        创建一个miscdevice结构体,填写次设备号等设备信息,这里主设备号已经规定是10,所以只需要填写次设备号,misc设备在操作系统中已经被创建,所以规定了主设备号。然后再初始化函数中注册misc设备,在出口函数中注销misc设备。驱动插入后会执行初始化函数,之后可以在/dev看到一个主设备号为10,此设备号为66的test设备。

2.4 示例代码

Makefile

KERNEL_DIR = /opt/wkspace/kernel-build/kernel-3.4.39/

obj-m += misc.o

all:
        make modules M=`pwd` -C $(KERNEL_DIR) CROSS_COMPILE=/usr/local/arm/arm-eabi-4.8/bin/arm-eabi-
clean:
        make modules clean M=`pwd` -C  $(KERNEL_DIR) CROSS_COMPILE=/usr/local/arm/arm-eabi-4.8/bin/arm-eabi-
        rm -rf app 
~                       

misc.c

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

int misc_open(struct inode *mnode,struct file *mfile){

        return 0;
}

int misc_release(struct inode *mnode,struct file *mfile){

        return 0;
}

struct file_operations misc_fop = {
        .open = misc_open,
        .release = misc_release,
};

struct miscdevice miscdev = {
        .minor = 66,
        .name = "test",
        .fops = &misc_fop,
};

static int __init mydev_init(void){
        printk(KERN_INFO "mydev init!\n");

        misc_register(&miscdev);
        return 0;
}

static void __exit mydev_exit(void){
        printk(KERN_INFO "platform dev exit!\n");

        misc_deregister(&miscdev);
        return ;
}

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值