0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux驱动开发-proc接口介绍

DS小龙哥-嵌入式技术 2022-09-17 15:31 次阅读

【摘要】 Linux系统上的/proc目录是一种文件系统,即proc文件系统。 与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。

1. 前言

Linux系统上的/proc目录是一种文件系统,即proc文件系统。

与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。

当前的实验平台是嵌入式Linux开发板,根文件系统挂载成功后,进入命令就能看到proc目录,这个目录里正常情况下已经生成了很多文件。通过cat命令读取这些文件,可以得到很多内核的信息。

比如:查看中断有哪些注册了,中断从上电到现在响应了多少次,杂项设备注册了哪些,帧缓冲节点有哪些,RTC时间查看,等等。

下面是proc目录下文件的功能的详细介绍(资源来源与网络):

2.1、/proc/apm
高级电源管理(APM)版本信息及电池相关状态信息,通常由apm命令使用;

2.2、/proc/buddyinfo
用于诊断内存碎片问题的相关信息文件;

2.3、/proc/cmdline
在启动时传递至内核的相关参数信息,这些信息通常由lilo或grub等启动管理工具进行传递;

2.4、/proc/cpuinfo
处理器的相关信息的文件;

2.5、/proc/crypto
系统上已安装的内核使用的密码算法及每个算法的详细信息列表;

2.6、/proc/devices
系统已经加载的所有块设备和字符设备的信息,包含主设备号和设备组(与主设备号对应的设备类型)名;

2.7、/proc/diskstats
每块磁盘设备的磁盘I/O统计信息列表;(内核2.5.69以后的版本支持此功能)

2.8、/proc/dma
每个正在使用且注册的ISA DMA通道的信息列表;

2.9、/proc/execdomains
内核当前支持的执行域(每种操作系统独特“个性”)信息列表;

2.10、/proc/fb
帧缓冲设备列表文件,包含帧缓冲设备的设备号和相关驱动信息;

2.11、/proc/filesystems
当前被内核支持的文件系统类型列表文件,被标示为nodev的文件系统表示不需要块设备的支持;通常mount一个设备时,如果没有指定文件系统类型将通过此文件来决定其所需文件系统的类型;

2.12、/proc/interrupts
X86或X86_64体系架构系统上每个IRQ相关的中断号列表;多路处理器平台上每个CPU对于每个I/O设备均有自己的中断号;

2.13、/proc/iomem
每个物理设备上的记忆体(RAM或者ROM)在系统内存中的映射信息;

2.14、/proc/ioports
当前正在使用且已经注册过的与物理设备进行通讯的输入-输出端口范围信息列表;如下面所示,第一列表示注册的I/O端口范围,其后表示相关的设备;

2.15、/proc/kallsyms
模块管理工具用来动态链接或绑定可装载模块的符号定义,由内核输出;(内核2.5.71以后的版本支持此功能);通常这个文件中的信息量相当大;

2.16、/proc/kcore
系统使用的物理内存,以ELF核心文件(core file)格式存储,其文件大小为已使用的物理内存(RAM)加上4KB;这个文件用来检查内核数据结构的当前状态,因此,通常由GBD通常调试工具使用,但不能使用文件查看命令打开此文件;

2.17、/proc/kmsg
此文件用来保存由内核输出的信息,通常由/sbin/klogd或/bin/dmsg等程序使用,不要试图使用查看命令打开此文件;

2.18、/proc/loadavg
保存关于CPU和磁盘I/O的负载平均值,其前三列分别表示每1秒钟、每5秒钟及每15秒的负载平均值,类似于uptime命令输出的相关信息;第四列是由斜线隔开的两个数值,前者表示当前正由内核调度的实体(进程和线程)的数目,后者表示系统当前存活的内核调度实体的数目;第五列表示此文件被查看前最近一个由内核创建的进程的PID;

2.19、/proc/locks
保存当前由内核锁定的文件的相关信息,包含内核内部的调试数据;每个锁定占据一行,且具有一个惟一的编号;如下输出信息中每行的第二列表示当前锁定使用的锁定类别,POSIX表示目前较新类型的文件锁,由lockf系统调用产生,FLOCK是传统的UNIX文件锁,由flock系统调用产生;第三列也通常由两种类型,ADVISORY表示不允许其他用户锁定此文件,但允许读取,MANDATORY表示此文件锁定期间不允许其他用户任何形式的访问;

2.20、/proc/mdstat
保存RAID相关的多块磁盘的当前状态信息,在没有使用RAID机器上,其显示为如下状态:

2.21、/proc/meminfo
系统中关于当前内存的利用状况等的信息,常由free命令使用;可以使用文件查看命令直接读取此文件,其内容显示为两列,前者为统计属性,后者为对应的值;

2.22、/proc/mounts
在内核2.4.29版本以前,此文件的内容为系统当前挂载的所有文件系统,在2.4.19以后的内核中引进了每个进程使用独立挂载名称空间的方式,此文件则随之变成了指向/proc/self/mounts(每个进程自身挂载名称空间中的所有挂载点列表)文件的符号链接;/proc/self是一个独特的目录,后文中会对此目录进行介绍;

2.23、/proc/modules
当前装入内核的所有模块名称列表,可以由lsmod命令使用,也可以直接查看;如下所示,其中第一列表示模块名,第二列表示此模块占用内存空间大小,第三列表示此模块有多少实例被装入,第四列表示此模块依赖于其它哪些模块,第五列表示此模块的装载状态(Live:已经装入;Loading:正在装入;Unloading:正在卸载),第六列表示此模块在内核内存(kernel memory)中的偏移量;

2.24、/proc/partitions
块设备每个分区的主设备号(major)和次设备号(minor)等信息,同时包括每个分区所包含的块(block)数目(如下面输出中第三列所示);

2.25、/proc/pci
内核初始化时发现的所有PCI设备及其配置信息列表,其配置信息多为某PCI设备相关IRQ信息,可读性不高,可以用“/sbin/lspci –vb”命令获得较易理解的相关信息;在2.6内核以后,此文件已为/proc/bus/pci目录及其下的文件代替;

2.26、/proc/slabinfo
在内核中频繁使用的对象(如inode、dentry等)都有自己的cache,即slab pool,而/proc/slabinfo文件列出了这些对象相关slap的信息;详情可以参见内核文档中slapinfo的手册页;

2.27、/proc/stat
实时追踪自系统上次启动以来的多种统计信息;如下所示,其中,
“cpu”行后的八个值分别表示以1/100(jiffies)秒为单位的统计值(包括系统运行于用户模式、低优先级用户模式,运系统模式、空闲模式、I/O等待模式的时间等);
“intr”行给出中断的信息,第一个为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数;
“ctxt”给出了自系统启动以来CPU发生的上下文交换的次数。
“btime”给出了从系统启动到现在为止的时间,单位为秒;
“processes (total_forks) 自系统启动以来所创建的任务的个数目;
“procs_running”:当前运行队列的任务的数目;
“procs_blocked”:当前被阻塞的任务的数目;

2.28、/proc/swaps
当前系统上的交换分区及其空间利用信息,如果有多个交换分区的话,则会每个交换分区的信息分别存储于/proc/swap目录中的单独文件中,而其优先级数字越低,被使用到的可能性越大;下面是作者系统中只有一个交换分区时的输出信息;

2.29、/proc/uptime
系统上次启动以来的运行时间,如下所示,其第一个数字表示系统运行时间,第二个数字表示系统空闲时间,单位是秒;

2.30、/proc/version
当前系统运行的内核版本号,在作者的RHEL5.3上还会显示系统安装的gcc版本,如下所示;

2.31、/proc/vmstat
当前系统虚拟内存的多种统计数据,信息量可能会比较大,这因系统而有所不同,可读性较好;下面为作者机器上输出信息的一个片段;(2.6以后的内核支持此文件)

2.32、/proc/zoneinfo
内存区域(zone)的详细信息列表,信息量较大

2. 获取CPU使用率

下面这份代码是利用/proc/stat文件获取当前CPU的占用率详细信息,通过C语言代码读取数据后,进行分析,处理。

#include 
#include 
#include 

typedef struct cpu_occupy_          //定义一个cpu occupy的结构体
{
    char name[20];                  //定义一个char类型的数组名name有20个元素
    unsigned int user;              //定义一个无符号的int类型的user
    unsigned int nice;              //定义一个无符号的int类型的nice
    unsigned int system;            //定义一个无符号的int类型的system
    unsigned int idle;              //定义一个无符号的int类型的idle
    unsigned int iowait;
    unsigned int irq;
    unsigned int softirq;
}cpu_occupy_t;

double cal_cpuoccupy (cpu_occupy_t *o, cpu_occupy_t *n)
{
    double od, nd;
    double id, sd;
    double cpu_use ;

    od = (double) (o->user + o->nice + o->system +o->idle+o->softirq+o->iowait+o->irq);//第一次(用户+优先级+系统+空闲)的时间再赋给od
    nd = (double) (n->user + n->nice + n->system +n->idle+n->softirq+n->iowait+n->irq);//第二次(用户+优先级+系统+空闲)的时间再赋给od

    id = (double) (n->idle);    //用户第一次和第二次的时间之差再赋给id
    sd = (double) (o->idle) ;    //系统第一次和第二次的时间之差再赋给sd
    if((nd-od) != 0)
        cpu_use =100.0 - ((id-sd))/(nd-od)*100.00; //((用户+系统)乖100)除(第一次和第二次的时间差)再赋给g_cpu_used
    else 
        cpu_use = 0;
    return cpu_use;
}

void get_cpuoccupy (cpu_occupy_t *cpust)
{
    FILE *fd;
    int n;
    char buff[256];
    cpu_occupy_t *cpu_occupy;
    cpu_occupy=cpust;

    fd = fopen ("/proc/stat", "r");
    if(fd == NULL)
    {
            perror("fopen:");
            exit (0);
    }
    fgets (buff, sizeof(buff), fd);

    sscanf (buff, "%s %u %u %u %u %u %u %u", cpu_occupy->name, &cpu_occupy->user, &cpu_occupy->nice,&cpu_occupy->system, &cpu_occupy->idle ,&cpu_occupy->iowait,&cpu_occupy->irq,&cpu_occupy->softirq);

    fclose(fd);
}

double get_sysCpuUsage()
{
    cpu_occupy_t cpu_stat1;
    cpu_occupy_t cpu_stat2;
    double cpu;
    get_cpuoccupy((cpu_occupy_t *)&cpu_stat1);
    sleep(1);
    //第二次获取cpu使用情况
    get_cpuoccupy((cpu_occupy_t *)&cpu_stat2);

    //计算cpu使用率
    cpu = cal_cpuoccupy ((cpu_occupy_t *)&cpu_stat1, (cpu_occupy_t *)&cpu_stat2);

    return cpu;
}

int main(int argc,char **argv)
{
    while(1)
    {
        printf("CPU占用率:%f\n",get_sysCpuUsage());
    }
    return 0;
}

3. proc驱动相关接口

Proc文件接口,主要用于驱动代码调试,获取内核信息,可以直接使用cat命令访问proc目录下的对应文件接口即可。

需要使用的头文件:

#include 
#include 

下面介绍内核里proc接口实现的相关函数接口:

1.	在proc目录下创建子目录函数
static inline struct proc_dir_entry *proc_mkdir(const char *name,struct proc_dir_entry *parent)
示例: //注意只能创建单层目录
//在proc目录下创建aaa文件夹
proc_mkdir("aaa",NULL);

2.	在proc目录下创建文件
static inline struct proc_dir_entry *proc_create(const char *name,    //文件名称
umode_t mode,      //模式,默认为0
struct proc_dir_entry *parent,   //父目录结构
const struct file_operations *proc_fops)  //文件集合
示例:
//在proc目录下创建一个文件
proc_create("aaa/tiny4412_proc_test", 0, NULL, &fops_proc);

3.	删除proc目录下之前创建的文件或者目录
void remove_proc_entry(const char *name,   //文件的路径
struct proc_dir_entry *parent  //父目录结构
)
示例:
remove_proc_entry("aaa/tiny4412_proc_test", NULL);
注意: 如果是删除目录,需要先把目录下的文件删除掉,每次删除必须保证目录是空的。

4. 编写proc接口测试驱动

4.1 案例1

下面驱动代码注册之后,会在proc目录下创建一个tiny4412_proc文件,通过cat读取这个文件,可以打印驱动代码里设置好的信息。驱动卸载时会删除这个tiny4412_proc文件。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static int tiny4412_open(struct inode *inode, struct file *file)
{   
    printk("tiny4412_open ok\n");
    return 0;
}

static ssize_t tiny4412_read(struct file *file, char __user *buf, size_t cnt, loff_t *loff)
{
    copy_to_user(buf,"123456",6);
    printk("tiny4412_read调用成功.\n");
    return 0;
}

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

static struct file_operations tiny4412_fops=
{
    .open=tiny4412_open,
    .read=tiny4412_read,
    .release=tiny4412_release,
};

static int __init tiny4412_init(void)
{
    proc_mkdir("wbyq",0);
    /*创建内核接口: proc  存放内核信息*/
    proc_create("wbyq/tiny4412_proc",0, NULL, &tiny4412_fops);
    
    printk("驱动安装成功.\n");
    return 0;
}

static void __exit tiny4412_exit(void)
{
    remove_proc_entry("wbyq/tiny4412_proc", NULL);
    remove_proc_entry("wbyq", NULL);
    printk("驱动卸载成功.\n");
}

/*驱动的入口:insmod xxx.ko*/
module_init(tiny4412_init);
/*驱动的出口: rmmod xxx.ko*/
module_exit(tiny4412_exit);
/*模块的许可证*/
MODULE_LICENSE("GPL");
/*模块的作者*/
MODULE_AUTHOR("wbyq");

4.2 案例2

下面这份代码是在字符设备框架代码里增加了proc接口,驱动安装之后,会在proc目录下创建tiny4412_proc文件,通过cat命令读取tiny4412_proc文件,可以打印出当前主设备号下所有的子设备信息。

#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
static struct class *tiny4412_beep_class;
static unsigned int major=0; //主设备号

static LIST_HEAD(tiny4412_beep_list);   //链表头
static DEFINE_MUTEX(tiny4412_beep_mtx); //互斥锁

#define DYNAMIC_MINORS 64 /* like dynamic majors */
static DECLARE_BITMAP(beep_minors, DYNAMIC_MINORS);

struct tiny4412_beep_device
{
    int minor;   /*次设备号*/
    const char *name; /*设备节点的名称*/
    const struct file_operations *fops; /*文件操作集合*/
    struct list_head list; //链表
};

int tiny4412_beep_register(struct tiny4412_beep_device *beep_dev)
{
    struct tiny4412_beep_device *c;
    dev_t dev;
    
    INIT_LIST_HEAD(&beep_dev->list);
    
    mutex_lock(&tiny4412_beep_mtx);

    //查找传入的次设备号是否冲突
    list_for_each_entry(c, &tiny4412_beep_list, list)
    {
        if(c->minor == beep_dev->minor)
        {
            mutex_unlock(&tiny4412_beep_mtx);
            return -EBUSY;
        }
    }
    
    //自动分配
    if(beep_dev->minor == MISC_DYNAMIC_MINOR) 
    {
        int i = find_first_zero_bit(beep_minors,DYNAMIC_MINORS);
        if (i >= DYNAMIC_MINORS)
        {
            mutex_unlock(&tiny4412_beep_mtx);
            return -EBUSY;
        }
        beep_dev->minor = DYNAMIC_MINORS - i - 1;
        set_bit(i,beep_minors);
    }

    //合成设备号
    dev = MKDEV(major, beep_dev->minor);

    //创建设备节点
    device_create(tiny4412_beep_class,NULL,dev,NULL,"%s", beep_dev->name);
    
    list_add(&beep_dev->list,&tiny4412_beep_list);
    
    //解锁
    mutex_unlock(&tiny4412_beep_mtx);
    return 0;
}

int tiny4412_beep_deregister(struct tiny4412_beep_device *beep_dev)
{
    int i = DYNAMIC_MINORS - beep_dev->minor - 1;

    mutex_lock(&tiny4412_beep_mtx);
    list_del(&beep_dev->list);

    //将dev目录下的文件删除掉
    device_destroy(tiny4412_beep_class, MKDEV(major, beep_dev->minor));
    if (i < DYNAMIC_MINORS && i >= 0)
        clear_bit(i, beep_minors);
    mutex_unlock(&tiny4412_beep_mtx);
    return 0;
}

EXPORT_SYMBOL_GPL(tiny4412_beep_register); 
EXPORT_SYMBOL_GPL(tiny4412_beep_deregister); 

//底层open函数
static int tiny4412_beep_open(struct inode * inode, struct file * file)
{
    //得到次设备号
    int minor = iminor(inode);
    
    struct tiny4412_beep_device *c;
    struct file_operations *new_fops,*old_fops;
    mutex_lock(&tiny4412_beep_mtx);
    //遍历链表--找到链表里相同的次设备号
    list_for_each_entry(c,&tiny4412_beep_list, list) 
    {
        if (c->minor == minor)
        {
            new_fops = fops_get(c->fops);    //得到47次设备号对应的结构体地址 
            break;
        }
    }
    file->f_op = new_fops; //改变指向--文件操作集合的指向
    if(file->f_op->open)
    {
        file->f_op->open(inode,file);
    }
    fops_put(old_fops);
    mutex_unlock(&tiny4412_beep_mtx);
    return 0;
}

static const struct file_operations tiny4412_beep_fops =
{
    .owner      = THIS_MODULE,
    .open       = tiny4412_beep_open,
};

static ssize_t tiny4412_read(struct file *file, char __user *buf, size_t cnt, loff_t *loff)
{
    struct tiny4412_beep_device *c;
    //遍历链表--找到链表里相同的次设备号
    list_for_each_entry(c,&tiny4412_beep_list, list) 
    {
        printk("%d %s\n",c->minor,c->name);
    }
    return 0;
}

static struct file_operations tiny4412_fops=
{
    .read=tiny4412_read,
};

static int __init tiny4412_beep_class_init(void)
{
    /*1. 创建设备类*/
    tiny4412_beep_class=class_create(THIS_MODULE,"tiny4412_beep");
    /*2. 注册字符设备*/
    major=register_chrdev(0,"tiny4412_beep",&tiny4412_beep_fops);
    
    proc_mkdir("wbyq",0);
    /*创建内核接口: proc  存放内核信息*/
    proc_create("wbyq/tiny4412_proc",0, NULL, &tiny4412_fops);
    
    return 0;
}

static void __exit tiny4412_beep_class_cleanup(void)
{
    remove_proc_entry("wbyq/tiny4412_proc", NULL);
    remove_proc_entry("wbyq", NULL);
    
    //注销设备类
    class_destroy(tiny4412_beep_class);
    //注销字符设备
    unregister_chrdev(major,"tiny4412_beep");
}

module_init(tiny4412_beep_class_init);
module_exit(tiny4412_beep_class_cleanup);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wbyq");
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    7573

    浏览量

    148206
  • Linux
    +关注

    关注

    87

    文章

    10942

    浏览量

    206543
  • Proc
    +关注

    关注

    0

    文章

    11

    浏览量

    8928
收藏 人收藏

    评论

    相关推荐

    一文总结linux的platform驱动

    linux设备驱动中,有许多没有特定总线的外设驱动,在实际开发中,又需要使用到总线、驱动和设备模型这三个概念,故而
    的头像 发表于 10-16 16:45 374次阅读
    一文总结<b class='flag-5'>linux</b>的platform<b class='flag-5'>驱动</b>

    Linux驱动proc接口介绍

    proc接口 注意,在较新版本的内核中, procfs 的函数接口有所变化。 系统 内核版本 Linux 5.10.111 在驱动中添加以
    的头像 发表于 09-27 11:29 210次阅读

    Linux驱动中procfs接口的创建

    procfs接口创建 实现效果: 例如, 在 /proc 下创建一个clk节点,通过 cat /proc/clk 可查看内容: 在驱动中添加以下代码: # include # incl
    的头像 发表于 09-27 11:24 189次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>驱动</b>中procfs<b class='flag-5'>接口</b>的创建

    如何通过proc接口发起系统请求

    有些硬件平台可能不能使用 SysRq 复合键,这种情况下,也可以通过 /proc 接口进入系统请求状态。 因为在内核配置选项中,使能了 CONFIG_MAGIC_SYSRQ 选项后,系统启动之后
    的头像 发表于 09-26 16:45 304次阅读

    嵌入式Linux系统开发介绍

    Linux 系统开发 基于 linux 操作系统来开发我们的产品叫 linux系统开发。此
    的头像 发表于 07-27 17:00 771次阅读
    嵌入式<b class='flag-5'>Linux</b>系统<b class='flag-5'>开发</b><b class='flag-5'>介绍</b>

    Linux proc文件系统详解

    上一篇:《文件系统有很多,但这几个最为重要》介绍了procfs(进程文件系统的缩写),包含一个伪文件系统(启动时动态生成的文件系统),用于通过内核访问进程信息。这个文件系统通常被挂载到 /proc 目录, /proc中不仅仅放了
    发表于 06-15 11:42 752次阅读

    Linux平台/proc虚拟文件系统详解

    Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统(即虚拟文件系统),它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据
    发表于 06-08 10:49 1045次阅读
    <b class='flag-5'>Linux</b>平台/<b class='flag-5'>proc</b>虚拟文件系统详解

    Linux驱动中创建procfs接口的方法

    上篇介绍Linux驱动中sysfs接口的创建,今天介绍procfs接口的创建。
    发表于 05-31 16:48 551次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>驱动</b>中创建procfs<b class='flag-5'>接口</b>的方法

    Linux驱动中创建sysfs接口的方法

    在一些linux开发板中,经常可以看到通过echo的方式来直接控制硬件或者修改驱动
    发表于 05-31 16:24 521次阅读

    Linux clock子系统及驱动实例

    Linux驱动中,操作时钟只需要简单调用内核提供的通用接口即可,clock驱动通常是由芯片厂商开发的,在
    发表于 05-31 16:10 442次阅读
    <b class='flag-5'>Linux</b> clock子系统及<b class='flag-5'>驱动</b>实例

    如何用proc sql生成宏变量?

    上节我们讲了PROC SQL的基本结构,以及一些sql命令的使用,这节我们主要讲一下case...when...、order by 、group by 、update、delete语句以及如何用proc sql生成宏变量。
    的头像 发表于 05-19 16:13 1420次阅读
    如何用<b class='flag-5'>proc</b> sql生成宏变量?

    PROC SQL介绍

    SQL(Structured Query Language)——结构化查询语言,是用于检索和更新数据的一种标准化语言,SQL在SAS中通过PROC SQL来实现。
    的头像 发表于 05-19 16:10 1490次阅读
    <b class='flag-5'>PROC</b> SQL<b class='flag-5'>介绍</b>

    Linux字符设备驱动开发框架介绍

    字符设备是Linux驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的。比如常见的点灯、按键、IIC、SPI、LCD 等等都是字符设备,这些设备的
    发表于 04-15 11:52 878次阅读
    <b class='flag-5'>Linux</b>字符设备<b class='flag-5'>驱动</b><b class='flag-5'>开发</b>框架<b class='flag-5'>介绍</b>

    Linux新字符设备驱动开发方式

    Linux字符设备驱动开发模板中介绍了旧版本的驱动开发模板,其需要手动分配设备号后,再进行注册,
    的头像 发表于 04-14 12:02 618次阅读
    <b class='flag-5'>Linux</b>新字符设备<b class='flag-5'>驱动</b><b class='flag-5'>开发</b>方式

    如何驱动Linux开发板LED灯

    Linux下的任何外设驱动,最终都是要配置相应的硬件寄存器。前面的文章中介绍了新旧字符设备的驱动开发框架,也
    的头像 发表于 04-14 11:41 638次阅读
    如何<b class='flag-5'>驱动</b><b class='flag-5'>Linux</b><b class='flag-5'>开发</b>板LED灯