深入浅出LDD-3- 自动地申请某设备号和加入某设备节点

/***************************************************************************************************
                                    设备驱动程序
* gvar.c
* 动态分配设备号
* 自动加入节点
* 注意:user.c 要找 /dev/gvar66
* 张永辉 2012年9月4日10:49
***************************************************************************************************/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>

MODULE_LICENSE("GPL");

static int             gvar = 0;
dev_t                  gvar_num;                //  设备号
static int             gvar_Major = 0;          //主设备号
static int             gvar_Minor = 0;          //次设备号

static struct cdev     *gvar_cdev;
static struct class    *gvar_class;

/**************************************读写操作****************************************************/
static ssize_t gvar_read (struct file *, char *,       size_t, loff_t*);
static ssize_t gvar_write(struct file *, const char *, size_t, loff_t*);

static ssize_t gvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
    //将global_var从内核空间复制到用户空间
    if ( copy_to_user(buf, &gvar, sizeof(int)))
    {
        return - EFAULT;
    }
    printk(KERN_ALERT "gvar_read enter ,the data is %d\n",gvar);
    return sizeof(int);
}

static ssize_t gvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
    //将用户空间的数据复制到内核空间的global_var
    if (copy_from_user(&gvar, buf, sizeof(int)))
    {
        return - EFAULT;
    }
    printk(KERN_ALERT "gvar_write enter ,the data is %d\n",gvar);
    return sizeof(int);
}
/*****************************************创建和注销************************************************/
//file_operations 主要提供的入口有:open ()、release ()、read ()、write ()、ioctl ()、llseek()、poll()等。
//初始化字符设备驱动的file_operations结构体 read: gvar_read, write: gvar_write,
//此写法是非标准C的写法,linux独家提供。
struct file_operations gvar_fops =
{
    .write  = gvar_write,
    .read   = gvar_read,
    .owner = THIS_MODULE,
};

static int __init gvar_init(void)
{
    int ret;

    //初始化cdev
    gvar_cdev = cdev_alloc();
    cdev_init(gvar_cdev, &gvar_fops);
    gvar_cdev->owner = THIS_MODULE;

    //动态获取主设备号(dev_t devid中包含"主设备号"和"次设备号"信息)
    alloc_chrdev_region(&gvar_num, 66, 1, "gvar");              //从66开始分配1个设备号
    gvar_Major = MAJOR(gvar_num);
    gvar_Minor = MINOR(gvar_num);

    printk(KERN_INFO "gvar major number %d \n", gvar_Major);
    printk(KERN_INFO "gvar minor number %d \n", gvar_Minor);

    //注册字符设备
    ret = cdev_add(gvar_cdev, gvar_num, 1);
    if (ret)
    {
        printk(KERN_NOTICE "gvar adding device error %d \n", ret);
        return -1;
    }

    gvar_class = class_create(THIS_MODULE, "gvar_class1");//在/sys目录下建立了一个gvar_class1的目录
    if (IS_ERR(gvar_class))
    {
        printk(KERN_INFO "gvar_class create error\n");
        return -1;
    }

    device_create(gvar_class,NULL,gvar_num,NULL,"gvar" "%d", MINOR(gvar_num));
    printk(KERN_ALERT "gvar create seccse , gvar_num = %d \n",gvar_num);

    return 0;
}

static void __exit gvar_exit(void)
{
    printk(KERN_ALERT "gvar exit success\n");
    unregister_chrdev_region(gvar_num, 1);
    cdev_del(gvar_cdev);
    device_destroy(gvar_class, gvar_num);
    class_destroy(gvar_class);
}

module_init(gvar_init);
module_exit(gvar_exit);

/***************************************************************************************************
自动创建设备节点
    原理:
        内核提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面。
        创建好了这个类后调用device_create(…)函数,会在/dev目录下创建相应的设备节点。
        加载模块时,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

关于类 struct class:

    定义处:  include/linux/device.h
    实  现: /drivers/base/class.c

    创建:struct class *class_create(struct module *owner, const char *name);
            第一个参数指定类的所有者是哪个模块,第二个参数指定类名。
            用于动态创建设备的逻辑类,并完成部分字段的初始化,然后将其添加进linux内核系统中。

    释放:class_destroy(…)
            用于在模块卸载时删除类。

关于设备:

    定义:#include <linux/device.h>
    实现 /drivers/base/core.c中实现

    创建:struct device *device_create(
                        struct class *class,        要创建的设备所从属的类,
                        struct device *parent,      void类型的指针,代表回调函数的输入参数
                        dev_t devt,                 设备号,    这个设备的父设备,如果没有就指定为NULL,
                        const char *fmt,            逻辑设备的设备名
                         ...)

    释放:void device_destroy(struct class *dev, dev_t devt);
            从linux内核系统设备驱动程序模型中移除一个设备,
            会删除/sys/devices/virtual目录下对应的设备目录及/dev/目录下对应的设备文件
***************************************************************************************************/

/***************************************************************************************************
                                    使用方法
共三个文件: gvar.c 驱动代码
             Makefile       用于编译驱动
             user.c         用户程序,会使用gvar驱动。

放到同一目录,做如下操作
    #make                           编译驱动
    #insmod gvar.ko            安装驱动
    #lsmod                          查看都有哪些驱动,是否成功安装
    #gcc user.c                     编译用户程序
    #./a.out                        执行用户程序,处会执行成功
     ...
    #rmmod gvar.ko             卸载驱动
    #./a.out                        执行用户程序,处会执行失败,以为没有gvar模块了。
     ...

张永辉  2012年8月28日  suseLinux验证通过。
***************************************************************************************************/
#include <stdio.h>
#include <sys/stat.h>       //获得文件的属性,它可以返回一个结构,里面包含文件全部属性
#include <fcntl.h>          //设备驱动程序接口是由结构说明,它定义在fcntl.h中
#include <sys/types.h>      //类型 clock_t,dev_t,off_t,ptrdiff,size_t,ssize_t,time_t

int main(void)
{
    int fd, num;

    fd = open("/dev/gvar66", O_RDWR, S_IRUSR | S_IWUSR);
    printf("fd = %d \n",fd);

    if (fd != -1 )
    {
        read(fd, &num, sizeof(int));
        printf("The gvar is %d\n", num);

        printf("Please input the num written to gvar\n");
        scanf("%d", &num);

        write(fd, &num, sizeof(int));
        read(fd, &num, sizeof(int));
        printf("The gvar is %d\n", num);

        close(fd);
    }else
    {
        printf("Device open failure\n");
    }
    return 0;
}

 

//-----------------------------------------------------------------------------------------------------------------

obj-m := gvar.o                                    #模块编译的目标必须以obj-m 这样的形式指出
KERNELDIR ?= /lib/modules/$(shell uname -r)/build       #模块的编译必须指定内核源代码的路径

PWD := $(shell pwd)
modules:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules            #本行开头必须使用 Tab 键
modules_install:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clearn:
 rm -rf *.o *.ko *mod.o [mM]odule* .*.cmd .tmp_versions

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值