• 0、内核一个重要结构的简单解释


    Q:内核中的如何描述设备号?

    A:Struct kdev_t

    Q:如何从kdev_t结构中分解出主设备号?

    A:MAJOR(kdev_t dev)

    Q:如何从kdev_t结构中分解出次设备号?

    A:MINOR(kdev_t dev)

    1. 创建设备文件:
      1. 使用mknod命令手工创建。
      2. 使用devis提供的函数在驱动程序中自动创建。

    2.Mknod用法:

    Mknod filename type major minor

    Filename:设备文件名

    Type:设备文件类型

    Major:主设备号

    Minor:次设备号

    例子:mknod serial0 c 100 0(创建的设备名字为serial0,c代表的是字符设备,主设备号为100,次设备号为0)。

    3.重要结构:

    在linux字符设备驱动程序设计中,有三种非常重要的数据结构。

    Struct file

    Struct inode

    Struct file_operations

    Struct file:代表一个打开的文件,系统中每个打开的文件在内核中都有一个关联的struct file. 它由内核在打开文件时创建,在文件关闭后,内核释放这个数据结构。

    重要成员:

    Loff_t f_pos /*文件读写位置*/

    Struct file_operations *f_op

    Struct inode:用来表示物理上存在的文件。因此,它和代表打开文件描述符的file是不同德。一个物理上存在的文件可以有多个打开描述符file,但只有一个inode结构。

    重要成员:

    Kdev_t i_dev:设备号

     

    Struct file_operations:一个函数指针的集合,定义能在设备上进行的操作。结构中的成员指向驱动中的函数,这些函数实现一个特别的操作,对于不支持的操作保留为null。

    例子:men_fops

    Struct file_operations mem_fops={

    .owner= THIS_MODULE,

    .llseek=mem_seek,

    .read = mem_read,

    .write =mem_write,

    .ioctl = mem_ioctl,

    .open = mem_open,

    .release = mem_release,

    };

     

    设备驱动安装:

            安装一个设备驱动的方法:

        Int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

        这里,major是主设备号,name是驱动的名字(出现在/proc/devices),fops是file_operations结构。

            卸载一个字符设备驱动的方法:

        Int unregister_chrdev(unsigned int major, const char *name);

        Major和name必须和传递给register_chrdev的相同,否则调用会失败。

    设备操作:

    Int (*pen)(struct inode *, struct file *)

    这是操作在设备文件上的第一个操作,然而并不要求驱动程序一定要声明这个方法。如果该项为NULL,设备的打开操作永远成功。

    Void (*release)(struct inode *, struct file *)

    当设备文件被关闭时调用这个操作。与open相仿,release也可以没有。

    Int (*read)(struct inode *, struct file *, char *, int);

    用来从设备中读取数据。当其为null指针时将引起read系统调用返回-EINVAL。函数返回一个非负数表示成功的读取了一个字节。

     

    Int (*write)(struct inode *, struct file *, const char *, int);

    向设备发送数据。如果没有这个函数,write系统调用向调用程序返回一个-EINVAL。

    Int (*select)(struct inode *, struct file *, int , select_table *);

    Select一般用于程序询问设备是否可读和可写。

    Int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);

    系统调用ioctl提供调用设备相关命令的方法,对于任何内核没有定义的请求,ioctl系统调用将返回-EINVAL.当调用成功时,返回给程序一个非负返回值。

    Int (*mmap)(struct inode *, struct file *, struct vm_area_struct *);

    Mmap用来将设备内存映射到进程内存中。

    Int (*lseek)(struct inode *, struct file *, off_t, int);

    用来修改一个文件的当前读写位置,并将新位置作为返回值。

    Open方法:

        Open方法是驱动程序用来为以后的操作完成初始化准备工作的。此外,open还会增加设备计数,以便于防止文件在关闭前模块被卸载出内核。在大部分驱动程序中,open完成如下工作:

    初始化设备。表明次设备号。增加使用计数。

    Release方法:

        Release方法的作用正好与open相反。这个设备方法又是也称为close。它应该:使用计数减1.关闭设备。

    读和写:

        读和写方法都是进行类似的任务,从和到应用程序代码拷贝数据。因此,他们的原型相当类似:

        Ssize_t xxx(dev)_read(struct file *filp, char *buff, size_t count, loff_t *offp);

        Ssize_t xxx(dev)_write(struct file *filp, const char *buff, size_t count, loff_t *offp);

    对于这两个方法,flip是文件指针,count是请求的传输数据大小。Buff参数指向数据缓存。最后,offp他指向用户正在存取的文件位置。

        Read和write方法的buff参数是用户空间指针。因此,他不能被内核代码直接引用,理由如下:

        用户空间指针在内核空间时可能根本是无效的----没有那个地址的映射。

        驱动必须能够存取用户空间缓存以完成它的工作。但是,为了安全起见这个存取必须使用特殊的,内核提供的函数,例如:

        Unsigned long copy_to_user(void __user *to, const void *from, unsigned long count).

        Unsigned long copy_from_user(void *to, const void __user *from, unsigned long count).

    上面的例子中app=mem.c是测试的程序,memdev.c和memdev.h是驱动程序。该驱动程序实现的功能,它不驱动具体的设备,只是访问某个内存。

     

     

  • 相关阅读:
    将内容重定向到剪切板(clip.exe)
    加速数组操作(Array)
    错误信息输出,重定向到文件
    格式化数字字符串
    PowerShell常用的.Net 、COM对象(New-Object、Assembly)、加载程序集
    计算文件夹大小、拷贝文件显示进度
    草稿-Hyper-V
    右下角显示提示窗口(New-Object,COM)
    《TCP/IP详解卷一:协议》数据链路层(一)
    tcpdump抓包命令
  • 原文地址:https://www.cnblogs.com/FORFISH/p/5188417.html
Copyright © 2020-2023  润新知