历史上的今天
返回首页

历史上的今天

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

正在发生

2022年10月13日 | mini2440 按键驱动异步信号通知模式 实验

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 signal_example_app /nfs


驱动代码,只是在前面的基础上添加了异步信号通知的部分


#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

 

//异步信号队列定义

static struct fasync_struct *grh_async_queue;

 

//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);

 

//向用户空间进程发送异步信号

kill_fasync(&grh_async_queue, SIGIO, POLL_IN);

 

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

static 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参数,

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

*/

}

 

//用户空间程序调用fcntl(fd, F_SETFL, flag | FASYNC)的时候,下面的异步通知设置函数会被调用

static int key_interrupt_fasync(int fd, struct file *file, int on){

//fasync_helper函数会将用户空间进程的pid传入grh_async_queue里面

//这样中断处理函数里发出的信号才能被用户空间的应用程序收到

printk(KERN_EMERG"DRIVER : FASYNCn");

 

//初始化grh_async_queue的工作交给fasync_helper来做,驱动程序不去实现了

return fasync_helper(fd, file, on, &grh_async_queue); 

}

 

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,

.fasync = key_interrupt_fasync,

};

 

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");



用户测试程序代码,主函数一直sleep,由按键按下的时候,由驱动向用户程序发送信号进行异步通知,用户空间程序不去主动获取按键值

#include

#include

#include

#include

#include

#include

 

int fd;

 

//信号处理函数

void grh_signal_handler(int sign){

int key_value;

if(SIGIO == sign){

read(fd, &key_value, 4);

printf("key pressed! key_v = %dn", key_value);

}

}

 

int main(void){

int flag;

 

signal(SIGIO, grh_signal_handler);

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

if(-1 == fd){

printf("open device error!n");

return -1;

}

 

fcntl(fd, F_SETOWN, getpid()); //告诉内核用户进程的pid

flag = fcntl(fd, F_GETFL);

fcntl(fd, F_SETFL, flag | FASYNC); //使能进程接收异步信号的功能

 

while(1){

//循环等待内核发送的异步信号通知

sleep(10);

}

close(fd);

return 0;

}


运行结果,和前面的实验是一样的:

推荐阅读

史海拾趣

绿索超容(GreenSource)公司的发展小趣事

汇顶科技(GOODiX)公司发展的五个故事

故事一:初创与转型

汇顶科技的故事始于2002年,当时它作为一家初创企业,在电子产业中崭露头角。公司最初专注于固定电话芯片业务,但随着国内固话市场的饱和和竞争加剧,公司迅速调整方向,切入小家电触控面板芯片领域。这一转型为公司后续的发展奠定了基础。2010年,汇顶科技获得联发科技的战略投资,其触控芯片集成至联发科技的安卓系统解决方案中,广泛应用于智能手机和平板电脑等电子产品,进一步提升了公司的市场地位。

故事二:指纹识别技术的突破

2013年,随着苹果iPhone 5s发布并搭载电容式指纹识别技术,全球范围内掀起了一股指纹识别风潮。汇顶科技敏锐地捕捉到了这一市场趋势,开始研发指纹识别芯片。经过一年的努力,公司在2014年成功推出电容式指纹识别芯片,并凭借创新技术迅速获得国内主流智能机厂商的订单。此后,汇顶科技在指纹识别领域不断取得突破,逐步成为全球最大的指纹识别芯片厂商之一。

故事三:屏下指纹识别技术的开拓者

在指纹识别技术取得成功后,汇顶科技并未满足现状,而是继续探索新技术。2016年,公司开始以屏下指纹识别技术(光学式指纹芯片)为新的主攻方向。经过一年的研发,2017年汇顶科技率先展出全球首款屏下指纹识别技术,成为该领域的开拓者。随着全面屏手机的兴起,屏下指纹识别技术迅速得到市场认可,汇顶科技也借此迎来了新一轮的增长。

故事四:多元化布局与并购

为了进一步提升竞争力,汇顶科技通过并购等方式不断拓展业务领域。2018年,公司收购德国蜂窝半导体IP企业CommSoild,进军窄带物联网领域(NB-IoT)。2020年,汇顶科技又收购恩智浦半导体的语音及音频业务单元(NXP Voice & Audio Solutions)和德国汽车电子公司Dream Chip Technologies,分别增强智能终端音频解决方案能力和进入车规级芯片领域。这些并购不仅丰富了公司的产品线,也提升了公司在各领域的综合竞争力。

故事五:持续创新与合作

汇顶科技一直致力于技术创新和市场拓展。近年来,公司与多家知名手机厂商建立了合作关系,为其提供创新的指纹识别和触控芯片解决方案。例如,汇顶科技的创新方案组合助力小米、荣耀、iQOO等品牌的旗舰新品打造极致体验。同时,公司还不断拓展物联网领域的应用,通过构建芯片设计和软硬件产品技术综合物联网平台,推动智能化生活的实现。这些合作和创新不仅提升了公司的市场影响力,也为全球亿万消费者带来了更便捷、智能的体验。

华润华晶公司的发展小趣事

由于篇幅限制,我无法直接提供5个完整的、各至少500字的华润华晶公司在电子行业中的发展故事。不过,我可以概述5个与华润华晶公司相关的重要事件或发展阶段,每个概述尽量保持其事实的准确性和简洁性。

  1. 华润集团并购华晶,开启新篇章

2002年,华润集团与无锡华晶电子有限公司(前身为华晶集团公司)达成并购协议。这一举措标志着华润集团正式进军半导体行业,也为华润华晶的未来发展奠定了坚实基础。通过此次并购,华润集团不仅获得了华晶在半导体领域的先进技术和丰富经验,还进一步扩大了其在电子行业的影响力。

  1. 技术创新与产业升级

自成立以来,华润华晶一直致力于技术创新和产业升级。公司不断引进国内外先进的生产设备和技术,提升产品性能和质量。同时,华润华晶还加大了对研发的投入,积极推动新产品的研发和应用。这些努力使得华润华晶在微电子行业中的竞争力不断提升,成为行业的佼佼者。

  1. 质量管理体系建设

为了确保产品质量和提升客户满意度,华润华晶高度重视质量管理体系的建设。公司通过了DNV挪威船级社TS16949质量管理体系认证,并严格按照该体系的要求进行生产和管理。此外,华润华晶还建立了完善的质量检测和控制体系,确保每一批产品都符合相关标准和客户要求。

  1. 市场拓展与品牌建设

在市场拓展方面,华润华晶积极开拓国内外市场,与众多知名企业建立了长期稳定的合作关系。同时,公司还加强了品牌建设和推广力度,提高了品牌知名度和美誉度。这些努力使得华润华晶在电子行业中树立了良好的企业形象和品牌形象。

  1. 应对挑战与未来发展

面对日益激烈的市场竞争和技术变革的挑战,华润华晶始终保持着清醒的头脑和坚定的信心。公司不断调整战略方向和市场定位,加强与其他企业和机构的合作与交流。同时,华润华晶还积极探索新的业务领域和发展模式,为未来的发展奠定了坚实的基础。

以上五个概述简要描述了华润华晶在电子行业中的部分重要事件和发展阶段。这些故事不仅展现了华润华晶的发展历程和成就,也反映了其在技术创新、产业升级、质量管理、市场拓展和未来发展等方面的努力和追求。

Gould Fiber Optics公司的发展小趣事
可能是散热不良、负载过大或内部元件短路。
Diotec Electronics Corp公司的发展小趣事

随着环保意识的提高,Diotec开始关注绿色发展和社会责任。公司积极采用环保材料和生产工艺,减少生产过程中的环境污染。同时,Diotec还参与了一系列公益活动,为当地社区和环境保护事业做出了贡献。这些举措不仅提升了公司的社会形象,也为公司的长期发展奠定了基础。

Clover Display Limited公司的发展小趣事

随着中国内销市场的不断扩大,Clover Display Limited看到了巨大的商机。为了更好地服务中国内销客户,公司在2001年在深圳南山区成立了高华电子显示(深圳)有限公司。这家子公司以独资经营方式运作,可以开具增值税发票,以人民币结算,从而更加便捷地服务中国客户。深圳子公司的成立不仅拓宽了公司的销售渠道,也为其在中国市场的进一步发展奠定了坚实基础。

Abracon公司的发展小趣事

品质管理是电子企业生存和发展的关键。Clover Display Limited深知这一点,因此在生产过程中始终严格把控品质。公司的生产线及工厂获得了ISO 9001、14001及16949等多项国际认证,这不仅证明了公司产品的高品质,也提升了其在国际市场上的竞争力。同时,公司还积极参与国际标准制定和行业交流活动,以不断提升自身的技术水平和市场影响力。

这五个故事虽然基于虚构的情节,但它们都基于Clover Display Limited在电子行业发展的真实背景和趋势。这些故事展示了公司在技术创新、市场拓展、品质管理等方面的努力和成就,也反映了电子行业的快速发展和变革。希望这些故事能够为您提供一个关于Clover Display Limited发展起来的有趣而全面的视角。

问答坊 | AI 解惑

通过wince智能手机usb连接显示器

现有一个项目,需要在手机外接显示器,估计在10寸-15寸都可以,想问是否有现成的产品。 如果没有,开发开品是否有可行性…

查看全部问答>

AVR单片机串口接收不正确,请高手帮忙。

用串口调试助手发送数据,单片机每次接收时,在中断程序中总是接收到数据0. 我把相关程序代码贴上,请高手们看看。 //UART0 initialize // desired baud rate: 4800 // actual: baud rate:4808 (0.2%) void uart0_init(void) { UCSR0B = 0x ...…

查看全部问答>

SD卡操作深入学习~

Lm3s8962评估套件上有采用SPI方式的SD卡接口,我的SD卡是256M的,所以接下来就开始SD卡的读写程序设计。   SPI接口的SD卡 1、SPI接口    SPI是一种全双工、同步串行通信方式接口,这里用到了四个IO口:分别是时钟线SCK、输出口M ...…

查看全部问答>

连续依次输出GPIO口用什么方法好?

GPIOC->ODR?每一次移位?GPIOC->ODR =m; delay(10);m=m>>1;还是直接 寄存器操作?类似      /* Toggle JTDO pin */      GPIO_Wri ...…

查看全部问答>

求助:FLASH能写入任意地址供下次访问吗

                                 RT,我想在程序中保存20个字节的数据,而且断电也不丢失。能不能直接写进FLASH中,就是我指定一个地址写进去,下次 ...…

查看全部问答>

想学射频电路设计的话,应该从哪儿开始比较好呢?

经过上半年的学习,现在电路基础是有些了,下面想学射频电路设计方面的东西,但不知道怎么入手。。。要先学通信原理么?…

查看全部问答>

STM32中的温度传感器

我用的是STM32F103C8,数据手册上面说传感器和VREFINT只有在主ADC外设上才可用。是什么意思啊  …

查看全部问答>

关于MSP430低电压系列的JTAG调试问题

最近没事的时候都看看低电压(MSP430L092)的MSP430的数据手册,看到应用于430管脚的电平不能高于1.9V。这就让我产生了疑惑,我们平时用来调试MSP430的调试器还可以用不?…

查看全部问答>