linux设备驱动(二)---字符设备之按键驱动

Linux按键输入实验-对按键驱动进行测试 阅读详情

按键驱动比较复杂,主要是软件去抖动要用到定时器,手头没有画流程图,回头补一下,先说一下大概

按键直接接在了外部驱动的管脚上,因此首先使用外部中断,然后进入外部中断后,将按健状态设置为不确定态DOWNX,然后关闭外部中断,启动定时器,定时20ms,然后进入定时器中断函数,这时候首先判断按键是否还在按下,

若不是,说明是抖动,直接恢复外部中中断,设置按键状态为UP抬起状态,退出

若是,说明按键真的按下了,那么将按键状态设置位DOWN,同时调用相关函数记录按键值,在启动一个100ms的定时器,目的是检测按键什么时候抬起。每次进入这个定时器中断,都去判断按键是否还在按下

若是,则在其动一次100ms定时

若不是,说明按键抬起了,则设置对应的状态,使能中断


几个问题说明一下

1. 关于request_irq的第三个参数,首先要说,这里4个按键用同一个驱动程序,那么中断中就要判断是哪个按键按下

根据中断函数传递的参数

static irqreturn_t s3c2440_eint_key(int irq,void *dev_id)

有两种方法,一个是根据中断号 int irq ,由于我的板子4个按键分别接再了4个外部中断上,中断号都不相同,那么用着个方法就很简单的区别

另一种就是要用void *dev_id这个参数,这个参数是怎么来的呢?先看中断申请的时候

request_irq(key_info_tab[i].irq_no,s3c2440_eint_key,IRQF_SHARED,DEVICE_NAME,(void *)(&key_id[i]))

这里的(void *)(&key_id[i])就是这个参数

之前我定义了static int key_id[4]={0,1,2,3};,这个作为给每个按键分配的id,为什么取0,1,2,3,很简单,我后面直接用这个id做按键数据结构数组 static struct key_info 的下标,这样定义可以直接用。

再说这个参数为什么要定义一个static int key_id[4],书上给出例子是

static int request_irqs(void)
{
int i;
for(i=0;i<(sizeof(key_info_tab))/sizeof(key_info_tab[0]);i++){
set_irq_type(key_info_tab[i].irq_no,IRQF_TRIGGER_RISING);//这里原书用的函数是老的形式,现在内核参数宏定义变了
if(request_irq(key_info_tab[i].irq_no,s3c2440_eint_key,IRQF_SHARED,DEVICE_NAME,i)){
return -1;
}
}
return 0;
}

我的定义是这样

static int request_irqs(void)
{
int i;
for(i=0;i<(sizeof(key_info_tab))/sizeof(key_info_tab[0]);i++){
//printk(KERN_EMERG "irq_no=%d\n",key_info_tab[i].irq_no);
set_irq_type(key_info_tab[i].irq_no,IRQF_TRIGGER_RISING);
if(request_irq(key_info_tab[i].irq_no,s3c2440_eint_key,IRQF_SHARED,DEVICE_NAME,(void *)(&key_id[i]))){
return -1;
}
}
return 0;
}

区别就是他直接用了循环的索引变量i,可能是内核更新的原因,现在要求这个函数的第三个参数为通用指针void * 类型,不知到以前是不是传值类型

如果简单的修改i位 &i,虽然类型对了,但这样做是不行的,因为&i取了i的地址,这个变量是局部变量,函数退出就销毁,以后再想访问当前值是访问不到的

我第一次没注意,改成&i,编译通过了,但使用中oops,说是调用了空指针,因此才有前面定义个静态数组的方法。


2. 使用定时器timer的话,一定要调用init_timer,初始化

3. disable_irq和disable_irq_nosync,两者都是关中断函数,不同在于,前者要等待中断处理完成才返回,后者不等,直接返回

因此再中断处理函数关中断操作的话一定要调用disable_irq_nosync,否则会死机。

这个处理在后文

static irqreturn_t s3c2440_eint_key(int irq,void *dev_id)

函数中

disable_irq_nosync(key_info_tab[key].irq_no);

4. 关于按键资源数据结构

static struct key_info
{
int irq_no;
unsigned int gpio_port;
int key_no;
}key_info_tab[KEY_NUM]=
{
{IRQ_EINT0,GPF0,0},
{IRQ_EINT2,GPF2,1},
{IRQ_EINT3,GPF3,2},
{IRQ_EINT4,GPF4,3},
};

这里的GPF0等定义为

#define GPF0 (S3C2410_GPF(0)) //定义pin mach/gpio-nrs.h 头文件中的宏
#define GPF2 (S3C2410_GPF(2))
#define GPF3 (S3C2410_GPF(3))
#define GPF4 (S3C2410_GPF(4))

关于这个宏定义再上一篇博客中有详细的解释

这里的gpio_port对应的pin号一定要设置对,也就是这个GPF0,如果算不清楚就用上面的宏

我第一次就是自己算的地址写的,结果算错了,各种奇怪的问题



#include<linux/module.h>
#include<linux/types.h>
#include<linux/fs.h>
#include<linux/errno.h>
#include<linux/mm.h>
#include<linux/sched.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<asm/io.h>
#include<asm/system.h>
#include<asm/uaccess.h>
#include<mach/regs-gpio.h>
#include<linux/interrupt.h>
#include<linux/irq.h>
#include<linux/slab.h>
#include<linux/sched.h>
#include<linux/wait.h>
#include<mach/gpio-fns.h>


#define MAX_KEY_BUF 16
#define KEY_NUM 4
#define KEY_MAJOR 250
#define KEYSTATUS_UP 1
#define KEYSTATUS_DOWNX 2
#define KEYSTATUS_DOWN 0
//保证x在mod-1中循环
//比如,mod-1=7 -> 0x0000 0111
//x累加超过7的部分,经过与操作之后,高位为0
#define INC_BUF_POINTOR(x,mod)    ((++(x))&((mod)-1))
//判断按键是否按下,参数为对应的pin值
#define ISKEY_DOWN(x) (s3c2410_gpio_getpin(key_info_tab[x].gpio_port)==KEYSTATUS_DOWN)
#define KEY_TIMER_DELAY1 HZ/100
#define KEY_TIMER_DELAY2 HZ/10
#define DEVICE_NAME "mykeys"
//#define GPFCON (0x02A2)
#define GPF0 (S3C2410_GPF(0)) //定义pin mach/gpio-nrs.h 头文件中的宏
#define GPF2 (S3C2410_GPF(2))
#define GPF3 (S3C2410_GPF(3))
#define GPF4 (S3C2410_GPF(4))


//主设备号
static int key_major=KEY_MAJOR;
typedef unsigned char key_ret;
//typedef void (*f)(unsigned int);
//f keyEvent;
//设备结构体
struct key_dev
{
unsigned int keyStatus[KEY_NUM];//记录按键状态
key_ret buf[MAX_KEY_BUF];//记录键值
unsigned int head,tail;
wait_queue_head_t wq;
struct cdev cdev;
};
struct key_dev *key_devp;
//定义定时器,定时器使用之前要init_timer
static struct timer_list key_timer[KEY_NUM];
//按键信息,中断号,pin号,键值
static struct key_info
{
int irq_no;
unsigned int gpio_port;
int key_no;
}key_info_tab[KEY_NUM]=
{
{IRQ_EINT0,GPF0,0},
{IRQ_EINT2,GPF2,1},
{IRQ_EINT3,GPF3,2},
{IRQ_EINT4,GPF4,3},
};
//记录按键值
static void keyEvent(unsigned int key_index)
{
//printk(KERN_EMERG "keyEvent\n");
key_devp->buf[key_devp->head]=key_index;
//printk(KERN_EMERG "key_pressed=%d,key_head=%d\n",key_devp->buf[key_devp->head],key_devp->head);


key_devp->head=INC_BUF_POINTOR(key_devp->head,MAX_KEY_BUF);
//printk(KERN_EMERG "key_head=%d\n",key_devp->head);
//唤醒等待按键的列队
wake_up_interruptible(&(key_devp->wq));


}
static int s3c2440_key_open(struct inode *inode, struct file *filp)
{
//printk(KERN_EMERG "s3c2440_key_open\n");
key_devp->head=0;
key_devp->tail=0;
return 0;
}
static int s3c2440_key_release(struct inode *inode, struct file *filp)
{
//keyEvent=keyEvent_dummy;
return 0;
}
static ssize_t s3c2440_key_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos)
{
unsigned long flag;
unsigned int ret,tmp;
//printk(KERN_EMERG "s3c2440_key_read\n");


retry: if(key_devp->head!=key_devp->tail)
{
//进入临界区
local_irq_save(flag);
ret=key_devp->buf[key_devp->tail];
key_devp->tail=INC_BUF_POINTOR(key_devp->tail,MAX_KEY_BUF);
//推出临界区
local_irq_restore(flag);


//printk(KERN_EMERG "buffer not empty,\n");
tmp=copy_to_user(buf,&ret,sizeof(unsigned int));
//printk(KERN_EMERG "copy to user,tmp=%d\n",tmp);
return (sizeof(unsigned int));
}
else{
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN;
//请求按键值,没有读到则挂起等待
interruptible_sleep_on(&(key_devp->wq));
goto retry;
}
return 0;
}
static struct file_operations s3c2440_key_ops=
{
owner:THIS_MODULE,
open:s3c2440_key_open,
release:s3c2440_key_release,
read:s3c2440_key_read,
};
//字符设备注册
static void key_setup_cdev(struct key_dev* dev,int index)
{
int err,devno=MKDEV(key_major,index);
cdev_init(&dev->cdev,&s3c2440_key_ops);
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&s3c2440_key_ops;
err=cdev_add(&dev->cdev,devno,1);
if(err)
{
printk(KERN_NOTICE "Error %d adding Key%d",err,index);
} 


}
//按键中断
static irqreturn_t s3c2440_eint_key(int irq,void *dev_id)
{
int key,cnt;
key=0;
//根据中断号判断当前按键是哪个
for(cnt=0;cnt<KEY_NUM;cnt++){
if(key_info_tab[cnt].irq_no==irq)
{
key=key_info_tab[cnt].key_no;
break;
}
}
//printk(KERN_EMERG "key=%d,irq_no=%d,irq=%d\n",key,key_info_tab[key].irq_no,irq);
disable_irq_nosync(key_info_tab[key].irq_no);
key_devp->keyStatus[key]=KEYSTATUS_DOWNX;
key_timer[key].expires=jiffies+KEY_TIMER_DELAY1;
//启动去抖动定时器
add_timer(&key_timer[key]);
return IRQ_HANDLED;
}
static void key_timer_handler(unsigned long data)
{
int key=data;
//printk(KERN_EMERG "Timer interrupt handler,key=%d\n",key);
//printk(KERN_EMERG "tab1=%x,tab2=%x,tab3=%x,tab4=%x\n",&key_info_tab[0],&key_info_tab[1],&key_info_tab[2],&key_info_tab[3]);
//printk(KERN_EMERG "gpio=%x\n",key_info_tab[key].gpio_port);

//printk(KERN_EMERG "is_key_down=%x,gpio_port=%x\n",ISKEY_DOWN(key),s3c2410_gpio_getpin(key_info_tab[key].gpio_port));
if(ISKEY_DOWN(key))
{
//printk(KERN_EMERG "Key Down\n");
if(key_devp->keyStatus[key]==KEYSTATUS_DOWNX){
key_devp->keyStatus[key]=KEYSTATUS_DOWN;
key_timer[key].expires=jiffies+KEY_TIMER_DELAY2;
//printk(KERN_EMERG "key downX,key=%d\n",key);
keyEvent(key);
add_timer(&key_timer[key]);
}
else{
//printk(KERN_EMERG "Key Down down\n");
key_timer[key].expires=jiffies+KEY_TIMER_DELAY2;
add_timer(&key_timer[key]);
}
}
else{
key_devp->keyStatus[key]=KEYSTATUS_UP;
//printk(KERN_EMERG "key status=%d\n",key_devp->keyStatus[key]);
enable_irq(key_info_tab[key].irq_no);
//printk(KERN_EMERG "enabled key_irq_no=%d\n",key_info_tab[key].irq_no);
}


}
//按键id分配,用于传入中断申请的第三个参数,目前用中断号判断,这个参数暂时用不上
//如果相同中断号的设备用统一个中断程序,则可用这个参数
static int key_id[4]={0,1,2,3};
//申请中断
static int request_irqs(void)
{
int i;
for(i=0;i<(sizeof(key_info_tab))/sizeof(key_info_tab[0]);i++){
//printk(KERN_EMERG "irq_no=%d\n",key_info_tab[i].irq_no);
set_irq_type(key_info_tab[i].irq_no,IRQF_TRIGGER_RISING);
if(request_irq(key_info_tab[i].irq_no,s3c2440_eint_key,IRQF_SHARED,DEVICE_NAME,(void *)(&key_id[i]))){
return -1;
}
}
return 0;

}
static void free_irqs(void)
{
struct key_info *k;
int i;
for(i=0;i<sizeof(key_info_tab)/sizeof(key_info_tab[0]);i++)
{
k=key_info_tab+i;
free_irq(k->irq_no,s3c2440_eint_key);
}
}


static int __init s3c2440_key_init(void)
{
int result,i,tmp;
//设备号,次设备号为0
dev_t devno=MKDEV(key_major,0);
result=register_chrdev_region(devno,1,"key");
key_devp=kmalloc(sizeof(struct key_dev),GFP_KERNEL);
if(!key_devp)
{
result=-ENOMEM;
//goto fail_malloc;
}
memset(key_devp,0,sizeof(struct key_dev));
key_setup_cdev(key_devp,0);
tmp=request_irqs();
if(tmp==-1)
{
printk(KERN_NOTICE "request_irqs error\n");
}
key_devp->head=0;
key_devp->tail=0;
//配置GPIO管脚,中断模式
s3c2410_gpio_cfgpin(GPF0,S3C2410_GPIO_IRQ);
s3c2410_gpio_cfgpin(GPF2,S3C2410_GPIO_IRQ);
s3c2410_gpio_cfgpin(GPF3,S3C2410_GPIO_IRQ);
s3c2410_gpio_cfgpin(GPF4,S3C2410_GPIO_IRQ);




for(i=0;i<KEY_NUM;i++)
{
key_devp->keyStatus[i]=KEYSTATUS_UP;
}
init_waitqueue_head(&(key_devp->wq));
for(i=0;i<KEY_NUM;i++)
{
init_timer(&key_timer[i]);
setup_timer(&key_timer[i],key_timer_handler,i);
}
printk(KERN_NOTICE "init module, result=%d\n",result);
//fail_malloc: unregister_chrdev_region(devno,1);
return result;

}
static void __exit s3c2440_key_exit(void)
{
free_irqs();
cdev_del(&key_devp->cdev);
kfree(key_devp);
unregister_chrdev_region(MKDEV(key_major,0),1);
printk(KERN_NOTICE "exit module\n");
}
MODULE_AUTHOR("weicz");
MODULE_LICENSE("Dual BSD/GPL");
module_init(s3c2440_key_init);
module_exit(s3c2440_key_exit);


测试程序:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#define LED0 "/dev/led0"    
#define LED1 "/dev/led1"    
#define LED2 "/dev/led2"    
#define LED3 "/dev/led3"    
#define LED4 "/dev/led4"    
static char* led_group[]={LED1,LED2,LED3,LED4};
static int cmd=0;
int main()
{
    int fd,ret,key_num;
    int led_fd;
    fd=open("/dev/key",0);
    if(fd<0)
    {
        printf("open error\n");
        return -1;
    }
    printf("open /dev/key\n");
    while(1){
        //printf("reading...\n");
        ret=read(fd,&key_num,sizeof(int));
        printf("key_value=%d\n",key_num);
        led_fd=open(led_group[key_num],0);
        ioctl(led_fd,cmd,0);
        cmd=(cmd==0)?1:0;
        close(led_fd);


    }
    close(fd);
    return 0;
}



这个程序是跟上一篇博客中led驱动联调用的

Makefile跟led那个差不多,模块名改一下就好

暂时先写着么多把

Linux 设备驱动分类(快速理解驱动架构) • Linux 设备驱动的 3 大分类(字符设备、块设备、网络设备) • /dev 目录下的设备文件解析 • 设备驱动与文件系统的关系 阅读详情

相关推荐

Linux驱动---字符设备

本篇文章详细讲解了Linux下字符设备的驱动开发,从驱动的基本知识到字符设备驱动开发框架。除此,还通过程序代码进一步加深对字符设备驱动开发的理解。后续也会增加相关的实战文章。

m0_65292176的博客 1586

Linux驱动之设备树添加按键驱动

每日一个简单的驱动,日久方长,对Linux驱动就越来越熟悉,也越来容易学会写驱动程序。今日进行第三个简单的按键驱动。

Wang_XB_3434的博客 1291

linux设备驱动

这本阿里P8撰写的算法笔记,再次推荐给大家,身边不少朋友学完这本书最后加入大厂: Github 疯传!史上最强悍!阿里大佬「LeetCode刷题手册」开放下载了! 一.Linux设备分类 字符设备: 以字节为单位读写的设备。 块设备 : 以块为单位(效率最高)读写的设备。 网络设备 : 用于网络通讯设备。 字符设备: 字符(char)设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序 来实现这种特性。字符设备驱动程序通常至少要实现open、close、read和w...

manongxianfeng的博客 5750

Linux按键输入实验-按键的字符设备驱动代码框架

Linux按键输入实验-按键的字符设备驱动代码框架

wojiaxiaohuang2014的博客 885

嵌入式Linux驱动开发(三)——字符设备驱动之查询的方式获取按键值

之前的文章讨论了字符设备驱动的框架以及通过自负设备驱动程序来控制开发板上的LED 嵌入式Linux驱动开发(一)——字符设备驱动框架入门 嵌入式Linux驱动开发(二)——字符设备驱动之控制LED 在这里我们可以简单的复习一下。 首先,字符设备驱动程序的框架核心是file_operations结构体,其中注册上层应用和底层驱动程序的对应关系。正式通过这个结构体,应用层的write才能找到驱动程序中

Toonle的专栏 1379

【Linux内核】设备驱动之字符设备介绍

字符设备驱动是Linux设备驱动中的重要组成部分,通过文件系统接口为用户空间提供访问硬件设备的能力。开发字符设备驱动需要理解等核心结构,并掌握设备的注册、注销以及操作函数的实现。通过实际开发产品实例,可以更好地理解字符设备驱动的具体技术要点和细节。

以实战经验介绍行业知识 1047

Linux 外设驱动 应用 2 KEY 按键实验

按键是指轻触式按键开关,也称之为轻触开关。按键开关是一种电子开关,属于电子元器件类,最早出现在日本,称之为:敏感型开关,使用时以满足操作力的条件向开关操作方向施压开关功能闭合接通,当撤销压力时开关即断开,其内部结构是靠金属弹片受力变化来实现通断的。

huanghongqi11的博客 996

linux按键驱动程序

嵌入式linux按键驱动程序,本人调试通过,代码风格良好,易于自己根据需要修改学习。

Linux按键驱动程序设计详解---从简单到不简单

混杂设备驱动模型: 1. 混杂设备描述         在Linux系统中,存在一类字符设备,它们拥有相同的主设备号(10),单次设备号不同,我们称这类设备为混            杂设备(miscdevice).所有的混杂设备形成一个链表,对设备访问时内核根据次设备号查到相应的混杂设备。          混杂设备也是字符设备!      linux中使用struct miscdevi

coding__madman的博客 1万+

AI 与新媒体

AI重构新媒体生态:从生产到分发的全链路变革 AI正成为新媒体领域的核心基础设施,通过五大能力重塑内容产业:自动化生产(AIGC写作/制图/剪辑效率提升5-10倍)、智能分发(算法精准匹配用户)、数据洞察(实时舆情分析)、风险管控(审核效率提升12倍)和运营优化(A/B测试自动化)。这推动行业从"人找内容"转向"内容找人",制作成本下降90%的同时,也带来同质化加剧、版权争议和职业重构等挑战。当前阶段,人机协同成为主流——AI处理标准化生产,人类专注创意与价值观把控。

eastyuxiao的专栏 380

用 Python 和 uiautomation 实现微信批量发送

思路是这样,将要发送的人员名单(包括称呼)以及发送内容都维护到Excel里,程序运行时读取Excel里内容,自动搜索人员姓名(微信昵称或备注名),填入要发送的内容,拼接上称呼(如果需要的话)自动点击发送,这样轮巡直至名单人员全部发送完成。、

jankingdom的专栏 1471

Linux设备驱动开发详解

Linux设备驱动开发详解Linux设备驱动开发详解Linux设备驱动开发Linux设备驱动开发详解1. linux设备驱动概述及开发环境搭建2. 驱动设计的硬件基础3. linux内核及内核编程4. linux内核模块5. linux文件系统与设备文件6. 字符设备驱动7. linux设备驱动中的并发控制8. linux设备驱动中的阻塞与非阻塞I/O9. linux设备驱动中的异步通知与异步I/O10. 中断与时钟11. 内存与I/O访问12. linux设备驱动的软件架构思想13. linux块设备驱.

tan1666的博客 2万+

超聚变安装银河麒麟服务器系统ky10-server-x86

超聚变-通过BMC口进服务器管理界面如下图为BMC管理口:默认BMC口IP:https://192.168.2.100l浏览器打开网页,输入用户名和密码登陆后,如下图红框处,选择“启动虚拟控制台”——选择“HTML集成远程控制台”系统银河麒麟服务器系统ky10 server x86选择镜像文件X86架构我们一般选择下图2212版本选择启动方式:光驱重启出现安装图形化界面选装安装系统的磁盘系统安装盘选完后如下图,会置灰创建root密码开始安装系统首次进入,有协议界面。

zengliguang的专栏 5965

linux 设备驱动(一)——字符设备驱动

linux 设备驱动一、概述1.1 设备驱动介绍二、字符设备驱动2.1. 字符设备驱动简介2.2. LCD驱动 一、概述 1.1 设备驱动介绍 二、字符设备驱动 2.1. 字符设备驱动简介 2.2. LCD驱动 感谢阅读,祝君成功! -by aiziyou ...

qq_27094347的博客 5347

VMware 虚拟机里连不上网的五种解决方案

在VMware虚拟机里的虚拟机系统连接不上网络 首先,注意查看适配器选项里的网络连接这两个网络连接是否存在,如果不存在可以重新装一下VM 如果存在,连不上网 解决办法一: 虚拟机设置里,找到“网络适配器”,右边的网络连接选择“NAT 模式”,如果不行的话再linux系统。还是不行的话接着看第二种解决方案。 解决方法二: 可能原因是VMware NET Service...

墨轩 18万+

生成式引擎优化(GEO)全景指南:技术架构、实施策略与未来趋势

生成式引擎优化(GEO)全景指南摘要 GEO(生成式引擎优化)是针对AI生成内容(如ChatGPT、文心一言等)的优化策略,通过结构化数据、权威建设与语义优化提升企业内容在AI答案中的引用优先级,实现“无点击曝光”。其核心价值在于从流量竞争转向信任构建,突破传统SEO局限。技术架构依托RAG(检索增强生成)、向量数据库及反馈学习机制,动态优化内容生成与引用逻辑。实施策略包括:部署结构化数据(如JSON-LD)、维护动态知识图谱、适配多模态内容(3D/VR)、联合权威机构发布白皮书。行业案例显示,美妆、智能家

解锁AI流量新红利!🚀 GEO优化(生成引擎优化)助您掌控AI搜索,让AI成为您的品牌最佳代言人! 1451

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的关系

绝对干货~~学习Linux设备驱动开发的过程中自然会遇到字符设备驱动、平台设备驱动、设备驱动模型和sysfs等相关概念和技术。对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相当不错。本文横向比较关联各个驱动相关的知识点和纵向剖析Linux整个驱动软件层次,传道授业解惑!!

嵌入式企鹅圈 5481

【Java】JAVA知识总结浅析

Java是一门功能强大的编程语言,广泛应用于多个领域。Java的编程思想,包括面向过程和面向对象编程,Java的发展历史,各版本的特点,JVM原理,数据类型,Java SE与Java EE的区别,应用场景,JDK与JDBC,Java Web技术,Spring Boot系列,以及MyBatis框架的基本实现,最后还将讨论Java在大数据、人工智能、嵌入式和Android等领域的应用。

wnm23的专栏 5231

Linux设备驱动开发---字符设备驱动程序

字符设备驱动程序1 主设备和次设备的概念设备号的注册和释放静态方法动态方法区别2 设备文件操作struct file_operations与struct file、struct inode关系3 分配和注册字符设备class_createcdev_adddevice_create4 字符设备驱动程序 字符设备通过字符(一个接一个的字符)以流方式向用户程序传递数据,就像串行端口那样。字符设备驱动通过/dev目录下的特殊文件公开设备的属性和功能,通过这个文件可以在设备和用户应用程序之间交换数据,也可以通过它来控

qq_41683305的博客 4369

SPMI协议学习总结

SPMI(System Power Management Interface)是由MIPI(Mobile Industry Processor Interface)联盟定义的一种硬件接口标准,它主要用于移动设备中,连接SoC(System on Chip)处理器系统的集成电源控制器与一个或多个电源管理IC(PMIC),以实现精确的电源管理

歌颂苦难的行为是无耻的; 1082

【WRF理论第十四期】 VEGPARM.TBL 文件详解

WRF 读取 VEGPARM.TBL 文件

WW、forever的博客 576

设备驱动: Linux系统下的字符设备驱动程序编程

一、实验目的 通过一个简单的设备驱动的实现过程。学会Linux中设备驱动程序的编写。 二、实验环境 Ubuntu20.04TSL,Linux5.10.0 三、实验内容 1、编写一个字符设备驱动程序,并在设备的打开操作中打印主次设备号; 2、编写一个用户测试程序,实现设备的读操作。 四、实验原理 实验中用到的系统调用函数(包括实验原理中介绍的和自己采用的),实验步骤 字符设备是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序。字符设备是面向流的设备,常见的字符设备有

hrdate(菜菜菜带带带) 2919

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联

参考原文:https://www.kancloud.cn/yueqian_scut/emlinux/106829 对原文笔误地方做了修改、重新排版 目录字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联一. 驱动设备二. 字符设备驱动三. 设备驱动模型四. sysfs文件系统五. 平台设备驱动 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动、平台设备驱动、设备驱动模型和sysfs等相关概念和技术,横向比较关联各个驱动相

_Modest_的博客 2080

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Linux 字符设备驱动开发模板

介绍字符驱动开发的基本模式

安迪西_嵌入式攻城狮 3699

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Linux设备驱动程序——一个简单的字符设备驱动程序

对于想入门Linux设备驱动程序的人来说,字符设备驱动往往是最简单的了解和实践的最佳选择,这里就实现一个简单的字符驱动,以便于大家了解字符设备驱动程序。 字符设备驱动程序 这里就我实现的字符设备驱动程序的源代码来讲解,这只是最简单的实现,便于大家了解,因此并没有涉及到锁,休眠等操作,不过在实际的字符设备驱动程序中,这些操作也是很常见的。 char.c源代码 #include <linux/m...

Alex_wu的博客 1830
上一篇: linux设备驱动(一)---字符设备之led驱动
下一篇: linux设备驱动(三)--应用input子系统实现按键驱动
weicz
博客等级 码龄19年 10粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值