1、字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。

2、块设备:是指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。

  每一个字符设备或块设备都在/dev目录下对应一个设备文件。linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备。

主设备号和次设备号(二者一起为设备号):
  一个字符设备或块设备都有一个主设备号和一个次设备号。主设备号用来标识与设备文件相连的驱动程序,用来反映设备类型。次设备号被驱动程序用来辨别操作的是哪个设备,用来区分同类型的设备。

驱动程序原理图:

第一个驱动之字符设备驱动(一)

那么对于刚接触驱动的我们来说如何快速编写一个驱动程序呢?

最好也是最快的方法是参考内核源代码中的demo。例如现在,我想编写我们的第一个字符驱动程序,那么我们可以看看别人是怎么实现的,在内核driver目录下找到led的驱动程序,参考别人是如何实现。还有就是厂家的参考demo。这是我们最快的学习方式。和STM32学习固件库函数一样的道理。

先写出两个函数模型,打开(open)和写(write)函数:

static int first_drv_open(struct inode *inode, struct file *file)
{
    
    return 0;
}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
    return 0;
}

然后是要告诉内核有这两个函数,怎样告诉内核呢?通过定义下面这样结构:

第一个驱动之字符设备驱动(一)

/*
 * NOTE:
 * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
 * can be called without the big kernel lock held in all filesystems.
 */
struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    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 *);
    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
    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 *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, struct dentry *, 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 (*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 (*dir_notify)(struct file *filp, unsigned long arg);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
}

然后通过一个函数告诉内核:

第一个驱动之字符设备驱动(一)

 

 那么谁来调用上面这个函数呢?调用上面这个函数的函数就叫做驱动入口函数(这里是first_drv_init):

第一个驱动之字符设备驱动(一)

 

入口函数需要区分是哪个驱动,所以需要修饰一下,怎么修饰呢?就是调用一个函数:

 完整的myled.c函数如下:

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <asm/uaccess.h>

#include <asm/irq.h>

#include <asm/io.h>

#include <asm/arch/regs-gpio.h>

#include <asm/hardware.h>



static int first_drv_open(struct inode *inode, struct file *file)

{

    printk("first_drv_open...\r\n");

    return 0;

}



static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

{

    printk("first_drv_write...\r\n");

    return 0;

}



/* 这个结构是字符设备驱动程序的核心

 * 当应用程序操作设备文件时所调用的open、read、write等函数,

 * 最终会调用这个结构中指定的对应函数

 */

static struct file_operations first_drv_fops = {

    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

    .open   =   first_drv_open,            

    .write    =    first_drv_write,       

};

int fisrt_drv_init(void)

{

    register_chrdev(111, "first_drv", &first_drv_fops);

    return 0;

}



void fisrt_drv_exit(void)

{

    unregister_chrdev(111, "first_drv");

}



module_init(fisrt_drv_init);

module_exit(fisrt_drv_init);

MODULE_AUTHOR("http://www.100ask.net");

MODULE_VERSION("0.1.0");

MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver");

MODULE_LICENSE("GPL");
View Code

相关文章:

  • 2021-07-28
  • 2022-12-23
  • 2021-10-19
  • 2022-01-10
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-12-06
  • 2021-06-25
  • 2021-10-22
  • 2021-12-24
  • 2022-12-23
  • 2021-11-13
  • 2021-11-30
相关资源
相似解决方案