历史上的今天
返回首页

历史上的今天

今天是:2025年10月13日(星期一)

正在发生

2022年10月13日 | mini2440 按键驱动POLL机制实验

2022-10-13 来源:csdn

Makefile


KERN_DIR = /home/grh/kernel_source_code/linux-2.6.32.2

all : 

make -C $(KERN_DIR) M=`pwd` modules

arm-linux-gcc key_interrupt_app.c -o key_interrupt_app

clean :

make -C $(KERN_DIR) M=`pwd` modules clean

rm -rf modules.order

obj-m += test_driver.o

obj-m += key_poll.o

obj-m += key_interrupt.o

copy : 

cp key_interrupt.ko key_interrupt_app /nfs


驱动源代码,就只是添加了Poll相关的部分

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#define GRH_MODULE_NAME "key_interrupt"

 

static int major;

static struct class *key_interrupt_class;

static struct class_device *key_interrupt_device; 

static int key_value;

 

//wait_event_interruptible函数需要的两个变量

static DECLARE_WAIT_QUEUE_HEAD(grh_wait_interrupt); //休眠的进程队列头

static volatile int sleep_for_interrupt; //这个变量为0的时候read函数会休眠,中断里面将其置1,read函数末尾将其设置为0

 

 

 

//pin_desc是对每一个按键中断的描述,不仅仅可以是整数,也可以是更复杂到的字段,这里用简单的按键值就行了

int pin_desc[6] = {

1, 2, 3, 4, 5, 6

};

 

 

//中断处理函数

static irqreturn_t grh_handle_key_eint(int irq, void *dev_id){

int *p;

p = dev_id;

 

//printk(KERN_EMERG"key pressed! key=%dn", *p);

key_value = *p;

 

//唤醒休眠的进程

sleep_for_interrupt = 1;

wake_up_interruptible(&grh_wait_interrupt);

 

return IRQ_HANDLED;

}

 

static void init_key(void){

//注册irq中断处理函数,将按键值和中断号绑定,所有清中断操作以及初始化中断相关寄存器的操作全部交给

//内核自动完成了,不再需要像裸机程序一样显式地对寄存器进行读写了,中断发生后会自动跳到grh_handle_key_eint

request_irq(IRQ_EINT8, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key1", pin_desc);

request_irq(IRQ_EINT11, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key2", pin_desc+1);

request_irq(IRQ_EINT13, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key3", pin_desc+2);

request_irq(IRQ_EINT14, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key4", pin_desc+3);

request_irq(IRQ_EINT15, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key5", pin_desc+4);

request_irq(IRQ_EINT19, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key6", pin_desc+5);

}

 

static int key_interrupt_open(struct inode *inode, struct file *file){

printk(KERN_EMERG"DRIVER: OPENn");

sleep_for_interrupt = 0;

init_key();

return 0;

}

 

static ssize_t key_interrupt_write(struct inode *inode, const char __user *buf, size_t count, loff_t *ppos){

printk(KERN_EMERG"DRIVER: WRITEn");

return 0;

}

 

static ssize_t key_interrupt_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){

printk(KERN_EMERG"DRIVER: READn");

//根据sleep_for_interrupt的数值决定是否将驱动进程加进休眠队列grh_wait_interrupt中,立即休眠进程

wait_event_interruptible(grh_wait_interrupt, sleep_for_interrupt);

copy_to_user(buf, &key_value, 4);

 

//下一次进入read的时候继续休眠等待中断发生

sleep_for_interrupt = 0;

return 0;

}

 

int key_interrupt_release(struct inode *inode, struct file *file){

//注销中断

free_irq(IRQ_EINT8, pin_desc);

free_irq(IRQ_EINT11, pin_desc+1);

free_irq(IRQ_EINT13, pin_desc+2);

free_irq(IRQ_EINT14, pin_desc+3);

free_irq(IRQ_EINT15, pin_desc+4);

free_irq(IRQ_EINT19, pin_desc+5);

printk(KERN_EMERG"DRIVER: RELEASEn");

return 0;

}

 

//sys_poll会反复在死循环里面调用key_interrupt_poll

unsigned int key_interrupt_poll(struct file *file, struct poll_table_struct *wait){

unsigned int mask;

printk(KERN_EMERG"DRIVER POLLn");

poll_wait(file, &grh_wait_interrupt, wait); //把当前进程挂到休眠队列里面,但是不立即休眠

mask = 0;

if(sleep_for_interrupt){ //中断发生了

mask |= POLLIN | POLLRDNORM; //把有可读数据的标志位设置为1,用户层可以得到这个mask

}

 

return mask;

/*

如果返回的mask是0那么进程直接进入定时休眠,如果在定时休眠过程中中断发生了,sys_poll里面的

定时休眠结束,sys_poll又会循环调用key_interrupt_poll,但这个时候mask一定返回非零数值了,这时

sys_poll中的休眠结束,进程继续运行。如果定时休眠过程中中断一直没有发生,那么定时休眠超时之后,

sys_poll再调用一次key_interrupt_poll,然会判断是否超时,如果超时直接结束进程的休眠。这是

Linux内核的poll机制的大概原理,这样在用户层调用一次poll函数,进程最多休眠时间就是传进来的wait参数,

中断一发生,定时休眠立刻结束,否则进程就休眠到一次定时休眠结束为止。

*/

}

 

 

static struct file_operations key_interrupt_fops = {

.owner = THIS_MODULE,

.open = key_interrupt_open,

.write = key_interrupt_write,

.read = key_interrupt_read,

.release = key_interrupt_release,

.poll = key_interrupt_poll

};

 

int key_interrupt_module_init(void){

printk(KERN_EMERG"INIT MODULE!n");

 

//register the driver with the device

major = register_chrdev(0, GRH_MODULE_NAME, &key_interrupt_fops);

 

//create my own device class

key_interrupt_class = class_create(THIS_MODULE, "key_interrupt_class");

//create my device of my own class

key_interrupt_device = device_create(key_interrupt_class, NULL, MKDEV(major,0), NULL, "key_interrupt_device");

 

return 0;

}

 

void key_interrupt_module_exit(void){

unregister_chrdev(major, GRH_MODULE_NAME);

device_unregister(key_interrupt_device);

class_destroy(key_interrupt_class);

printk(KERN_EMERG"EXIT MODULE!n");

}

 

module_init(key_interrupt_module_init);

module_exit(key_interrupt_module_exit);

 

MODULE_AUTHOR("GRH");

MODULE_VERSION("1.0");

MODULE_DESCRIPTION("KEY POLL DRIVER");

MODULE_LICENSE("GPL");



用户空间测试程序,每次在Poll之后判断是不是发生了中断,如果发生了中断就打印按键值,如果超时了就直接退出程序

#include

#include

#include

#include

#include

#include

#include

 

int main(void){

struct pollfd fds[1];

int i, sum, ret;

int key_value;

int fd;

 

fd = open("/dev/key_interrupt_device", O_RDWR);

if(-1 == fd){

printf("open key device error!n");

return -1;

}

fds[0].fd = fd;

fds[0].events = POLLIN;

 

while(1){

ret = poll(fds, 1, 5000); //只监控一个设备,这里不使用poll的多路复用功能,休眠延时是5000ms

if(-1 == ret){

printf("poll error!n");

break;

}

else if(0 == ret){

printf("poll time out!n");

break;

}

else{

//读操作结束的时候自然驱动程序里面的中断发生的标志sleep_for_interrupt

//就清空了,实际上read的时候该标志比为1,进程已经不可能进入休眠了,因为poll

//返回正值的时候,才会进入read

read(fd, &key_value, 4); 

printf("key pressed : %dn", key_value);

}

}

close(fd);

return 0;

}



测试结果(经过测试在timeout情况下,驱动里面poll会调用两次,这和Linux内核中poll机制的实现是吻合的,内核里面实现Poll机制的源代码这里就不分析了,有兴趣的自己去读一下吧,这里只是我自己对实验代码做一个记录而已):

推荐阅读

史海拾趣

Hayashi Denko Co Ltd公司的发展小趣事

HARTING公司自1945年成立以来,在电子行业里经历了多个重要的发展阶段,以下是五个与HARTING公司发展相关的事实性故事:

1. 创立与初期发展

创立背景:1945年,Wilhelm和Marie Harting在德国创立了HARTING公司,起初以生产日常所需的设备为主,如节能灯泡、电炉等。随着德国工业的发展,他们逐渐意识到新兴行业对技术产品的需求,于是将公司转向开发和生产电气连接器及连接系统。这一转变标志着HARTING正式进入电子行业,并为其后续发展奠定了基础。

初期产品:早期,HARTING开发的Han®连接器在市场上取得了巨大成功,该连接器以其坚固耐用、易于操作的特点,迅速成为行业内的标准产品,为HARTING在电子行业树立了良好的口碑。

2. 技术创新与全球化拓展

技术创新:HARTING始终致力于技术创新,不断推出新产品以满足市场需求。例如,他们研发的矩形连接器在1965年问世后,迅速替代了传统的圆形军用规格连接器,成为工业连接的新标准。此外,HARTING还在数据通信、网络技术、芯片卡、多媒体技术等领域取得了显著成就。

全球化拓展:随着业务的不断发展,HARTING开始在全球范围内设立子公司和生产工厂。目前,HARTING已在40多个国家设立了附属公司,生产工厂遍布德国、英国、瑞士、美国、罗马尼亚及中国等7个国家。这种全球化布局不仅提升了HARTING的市场占有率,还使其能够更好地服务全球客户。

3. 进入中国市场

中国市场布局:1988年,HARTING正式进入中国市场,并在珠海投资兴建了生产基地。这一举措标志着HARTING对中国市场的重视和承诺。随着在中国市场的不断深耕,HARTING已在中国设立了多个销售和服务中心,覆盖了包括香港、珠海、深圳、广州在内的多个城市。

本地化生产与服务:为了更好地服务中国客户,HARTING在中国实现了本地化生产和服务。他们不仅提供高质量的产品,还为客户提供设计咨询、系统集成、定制化解决方案等一系列专业服务。这些举措使HARTING在中国市场赢得了广泛认可。

4. 工业4.0与数字化转型

工业4.0引领者:面对工业4.0和数字化转型的浪潮,HARTING积极投入研发和创新,推出了多款面向未来的产品和技术。例如,HARTING MICA®是一款将工业4.0功能引入现有机器和设备的工业边缘网关,它能够帮助企业实现生产过程的智能化和自动化。

数字化转型服务:除了产品创新外,HARTING还为客户提供数字化转型的解决方案和服务。他们利用自身在连接技术领域的优势,帮助企业构建高效、可靠的数字化生产体系,提升生产效率和产品质量。

5. 定制化解决方案与行业应用

定制化解决方案:HARTING深知不同行业对连接技术的不同需求,因此他们始终致力于为客户提供定制化的解决方案。无论是电力、通信、自动化还是航空、汽车等行业,HARTING都能根据客户的具体需求,提供最适合的连接技术和产品。

行业应用案例:在多个行业领域,HARTING的产品和技术都得到了广泛应用。例如,在汽车行业,HARTING的3D-MID技术帮助客户将复杂的电子设备集成到汽车中,提高了汽车的安全性和舒适性;在轨道交通行业,HARTING的连接器产品被广泛应用于信号传输和电源分配等领域,确保了轨道交通的安全运行。

通过以上五个故事,我们可以看出HARTING公司在电子行业里的发展历程和成就。从创立初期的艰难探索到如今的全球化布局和技术创新,HARTING始终保持着对技术的热爱和追求,为客户提供高质量的产品和服务。

成都芯进(CrossChip)公司的发展小趣事

2023年6月,成都芯进电子宣布完成超1亿元A轮融资。这一轮融资的成功,不仅为公司的发展提供了充足的资金保障,也吸引了更多知名产业机构和投资基金的关注。公司借此机会扩大了研发团队和生产规模,进一步提升了产品的研发和生产能力。

DAYA公司的发展小趣事

随着全球化趋势的加速,大雅智能积极实施国际化战略,拓展海外市场。通过与国外知名企业的合作与交流,大雅智能引进先进技术和管理经验,不断提升自身的核心竞争力。同时,大雅智能还积极参加国际展览和论坛活动,展示其创新成果和产品实力。这些努力让大雅智能在国际舞台上崭露头角,为全球消费者提供更多优质的电子产品。

Bussmann (Eaton)公司的发展小趣事

随着电子技术的快速发展,对电路保护的要求也越来越高。为了满足市场需求,Bussmann于1992年开始研发芯片保险丝。这款新型保险丝将可熔性材料沉降到陶瓷基底上,具有体积小、安装方便等优点,能够广泛应用于印刷电路板等电子设备中。芯片保险丝的推出不仅进一步提升了Bussmann的技术实力,也为其在电子行业打开了新的市场空间。

ABL Heatsink公司的发展小趣事

早期,ABL Heatsink公司主要生产通用型散热器,但随着市场竞争的加剧,公司意识到必须调整市场定位。于是,公司开始专注于研发针对特定电子设备的高性能散热器。通过深入了解客户需求,ABL Heatsink成功开发出一系列定制化产品,赢得了市场的青睐。

BRIGHT公司的发展小趣事

随着BRIGHT公司在国际市场上的不断拓展,其品牌和产品也引起了一定的争议。在一些国家和地区,BRIGHT公司的某些行为或言论引发了公众的不满和批评。然而,这并没有阻挡BRIGHT公司前进的步伐。他们坚持自己的发展策略,通过不断创新和改进产品,积极应对各种挑战和机遇。在国际市场上,BRIGHT公司逐渐树立起了自己的品牌形象,并为电子行业的发展做出了重要的贡献。

这些故事展示了BRIGHT公司在电子行业中的不同领域所取得的成就和发展。无论是无线耳机领域的开创者、太阳能领域的突破者,还是健康技术领域的创新者、酒店业务的拓展者,以及在国际市场上的拓展与争议,都体现了BRIGHT公司不断创新、追求卓越的精神。这些故事不仅反映了BRIGHT公司的发展历程,也展示了电子行业的多样性和活力。

问答坊 | AI 解惑

初学Zigbee(MiWi),有前辈给指点下如何快速上手不?

-Micrchip MiWi solution. -Demo board都有了 -相关文档也看了不少,总觉得比较浅,望有经验的前辈指点下接下来怎样更全面的学习…

查看全部问答>

【讨论】wince系统下的波形失真问题?

一个采集音频信号并且输出波形的小程序。 在EVC中的模拟器下可以看到比较好的效果,无信号时的零线平滑笔直。 下载到板子上,再运行程序,就会发现零线是一条小锯齿的形状,通过一条音频线将PC与ARM相连,短路相接也还是有锯齿。。。 问问大虾这 ...…

查看全部问答>

哪位高手能用AM402设计一个恒流源

哪位高手能用AM402设计一个恒流源…

查看全部问答>

请汇编高手看看这个程序:混编的

以下是源码,我想弄清楚unsigned long GetCurTick(void)返回的值有什么用,是不是一个OS的计数值,与系统的时钟有关。 static unsigned long curTimer; static unsigned long TimeOutIni=5400; unsigned long GetCurTick(void) { unsigned lo ...…

查看全部问答>

ARM初学者

大家好! 我是电子信息开发领域的新手,现在想学习基于ARM Cortex M0内核的系统,不知道应该如何入门?本人貌似只有一些单片机的基础,还有就是电子领域的基本知识(数电、模电、高频电路、51单片机、C程序设计等),不知道学习ARM的难度大吗? ...…

查看全部问答>

新手求救:谁有2407扩展cy7c1021cv33 RAM的电路图

我想扩展一片64Kcy7c1021cv33的RAM作调试程序用,谁有这方面的电路图?主要是不知道该把接DS,还PS。     谢谢 brettwkl@163.com…

查看全部问答>

验证电路板的连接

   我想验证电路板的连接,  如果我向数据总线ED16写个高电平,怎么才能在CCS中查看到确实写入了一个高电平呢? …

查看全部问答>

DK-LM3S9B96开发板相关资料

为感谢论坛再次提供开发板的团购机会,我整理一下相关资料,都是网上转来的,方便大家查找, 本人很喜欢这款开发板,虽然可能又要上课抢购不了了~但还是支持这个活动   一,套件清单及硬件资源 二,相关技术资料     ...…

查看全部问答>

【一起学习器件指标】MOS管的参数你知道哪些呢

在原理图上,你分得清NMOS和PMOS不?说实话用过分立的MOS么?你知道的MOS管的参数又有哪些呢?这个在PC上很常见哦原理图对不对呢?…

查看全部问答>

lm3s系列的内部资源已经学完(但不很熟练),现在是否上系统啊

lm3s系列的内部资源已经学完(但不很熟练),现在是否上系统啊  ,上什么系统 ,,请各位 指点。。  现在大部分人都在弄linux , 像UC一类的 还有前途不?请各位解答…

查看全部问答>