趣谈 Linux 操作系统
刘超
前网易杭州研究院云计算技术部首席架构师
85459 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 72 讲
趣谈 Linux 操作系统
15
15
1.0x
00:00/00:00
登录|注册

33 | 字符设备(下):如何建立直销模式?

irq_desc包含irqaction,指向设备驱动程序注册的中断处理函数
irq_desc放在基数树里面,方便查找
通过vector_irq映射为irq_desc
其他用于设备中断
前32位和32位系统调用已填好
《Linux Device Drivers》
查看每个CPU收到的中断
硬件中断的处理函数是do_IRQ进行统一处理
CPU拥有idt_table存放中断向量的处理函数
中断控制器发送中断向量给CPU
外部设备发起外部中断
推荐
课堂练习
中断处理机制

该思维导图由 AI 生成,仅供参考

上一节,我们讲了一个设备能够被打开、能够读写,主流的功能基本就完成了。我们讲输入输出设备的时候说到,如果一个设备有事情需要通知操作系统,会通过中断和设备驱动程序进行交互,今天我们就来解析中断处理机制。
鼠标就是通过中断,将自己的位置和按键信息,传递给设备驱动程序。
static int logibm_open(struct input_dev *dev)
{
if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
return -EBUSY;
}
outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
return 0;
}
static irqreturn_t logibm_interrupt(int irq, void *dev_id)
{
char dx, dy;
unsigned char buttons;
outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT);
dx = (inb(LOGIBM_DATA_PORT) & 0xf);
outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT);
dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4;
outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT);
dy = (inb(LOGIBM_DATA_PORT) & 0xf);
outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT);
buttons = inb(LOGIBM_DATA_PORT);
dy |= (buttons & 0xf) << 4;
buttons = ~buttons >> 5;
input_report_rel(logibm_dev, REL_X, dx);
input_report_rel(logibm_dev, REL_Y, dy);
input_report_key(logibm_dev, BTN_RIGHT, buttons & 1);
input_report_key(logibm_dev, BTN_MIDDLE, buttons & 2);
input_report_key(logibm_dev, BTN_LEFT, buttons & 4);
input_sync(logibm_dev);
outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
return IRQ_HANDLED
要处理中断,需要有一个中断处理函数。定义如下:
irqreturn_t (*irq_handler_t)(int irq, void * dev_id);
/**
* enum irqreturn
* @IRQ_NONE interrupt was not from this device or was not handled
* @IRQ_HANDLED interrupt was handled by this device
* @IRQ_WAKE_THREAD handler requests to wake the handler thread
*/
enum irqreturn {
IRQ_NONE = (0 << 0),
IRQ_HANDLED = (1 << 0),
IRQ_WAKE_THREAD = (1 << 1),
};
其中,irq 是一个整数,是中断信号。dev_id 是一个 void * 的通用指针,主要用于区分同一个中断处理函数对于不同设备的处理。
这里的返回值有三种:IRQ_NONE 表示不是我的中断,不归我管;IRQ_HANDLED 表示处理完了的中断;IRQ_WAKE_THREAD 表示有一个进程正在等待这个中断,中断处理完了,应该唤醒它。
上面的例子中,logibm_interrupt 这个中断处理函数,先是获取了 x 和 y 的移动坐标,以及左中右的按键,上报上去,然后返回 IRQ_HANDLED,这表示处理完毕。
其实,写一个真正生产用的中断处理程序还是很复杂的。当一个中断信号 A 触发后,正在处理的过程中,这个中断信号 A 是应该暂时关闭的,这样是为了防止再来一个中断信号 A,在当前的中断信号 A 的处理过程中插一杠子。但是,这个暂时关闭的时间应该多长呢?
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了鼠标通过中断将按键信息传递给设备驱动程序的机制,详细解释了中断处理函数的注册过程,包括request_irq和request_threaded_irq函数的调用以及中断描述结构的查找和初始化。此外,还介绍了CPU收到中断向量后的处理流程,包括中断向量表的设置和中断处理函数的调用。通过具体的代码和解释,深入浅出地介绍了中断处理函数的注册和实现过程,适合对中断处理机制感兴趣的读者阅读。文章通过代码和解释,展现了中断处理函数的注册和实现过程,适合对中断处理机制感兴趣的读者阅读。文章内容涉及了中断的整个处理过程,包括外部中断到达中断控制器,中断向量发送给CPU,以及CPU处理中断的流程。同时,还介绍了硬件中断的处理函数和irq_desc结构,以及如何查看每个CPU收到的中断。整体而言,本文通过深入的技术解释和代码示例,为读者提供了全面了解中断处理机制的机会。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《趣谈 Linux 操作系统》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(17)

  • 最新
  • 精选
  • book尾汁
    总结下: 系统有256个中断向量,定义在中断向量表中,其中前32位[0-31]用于系统自身的内部中断,第32位用于32位中断(?),剩余用以设备中断,这是硬件的中断向量表,表里面是中断信号与其对应的中断处理函数,最终都会走到do_irq 对于每个cpu来说会有一层虚拟中断层,因为对于多核系统,多个中断处理器,每个cpu会有自己的中断映射表来讲硬件的中断向量对应于虚拟中断向量,其实就是将中断向量表中对应的中断向量描述结构设置为虚拟中断信号的中断描述结构. 中断描述结构比较重要,其成员有中断处理的动作结构链表,设备的名字. 中断处理的动作结构体其组成成员有 对应的中断处理函数 虚拟中断号 该中断处理函数是否放在单独的线程中执行,以及对应的线程等 中断的流程: 当系统收到中断物理信号,会由中断控制器将物理信号转化为中断向量,然后发送给各个cpu 各个cpu通过硬件的中断向量表调用对应的中断处理函数,在中断处理函数中会把物理中断信号转化为虚拟中断信号,然后调用中断信号的中断处理函数(通过中断映射表里对应的中断描述结构来找到对应的中断处理函数)

    作者回复: 赞

    2020-04-26
    3
  • 嘉木
    这样 do_IRQ 会根据中断向量 vector 得到对应的irq_desc,然后调用 handle_irq。handle_irq 会调用 generic_handle_irq_desc,里面调用 irq_desc 的 handle_irq 老师这个地方绕不出来了。。。handle_irq最后又调用到handle_irq?

    作者回复: 两个handle_irq,名字一样而已

    2019-08-03
    2
  • Spring
    老师,每个CPU的中断向量表只有256项,留给设备的只有剩下的223项,请问是最多能处理223个不同设备的中断吗?中断向量表中的每一项跟设备之间是什么关系呢?

    作者回复: 有中断的一节会讲这个

    2019-06-23
    2
  • alexgzh
    老师, system call, interrup和exception处理的相同点和不同点能讲一下吗?

    作者回复: system call原来是软中断,后来是特殊的指令了。interrupt是中断,exception往往会因为指令非法,以中断的形式中止指令运行,还是走中断的正常流程。

    2019-06-15
    2
  • 佳俊
    每一个cpu都会有一个中断向量表,都是一样的吗?如果一个控制器中断来了之后,他会把中断给哪个cpu呢?

    作者回复: 中断也有路由,哪个处理都行

    2020-05-22
  • 安排
    每个CPU的前32个中断也会调用到do_IRQ吗?

    作者回复: 是的

    2019-06-12
    2
  • 石维康
    cat /proc/interrupts
    2019-06-12
    1
    13
  • ZYecho
    老师您好,第二个层次是中断控制器将物理中断信号转换成为中断向量 int发送给各个cpu,想请教一下 如果这个地方每个cpu都收到中断后,如果保证这个中断只会被处理一次?
    2019-09-12
    1
    10
  • 西山薄凉
    课代表在这里。 - 设备中断处理 - 定义中断处理函数:irq_handler_t - 函数入参 - int irq:中断信号 - void * dev_id:通用指针,主要用于区分同一个中断处理函数对于不同设备的处理 - 返回值 - IRQ_NONE:设备不是中断接收者 - IRQ_HANDLED:处理完了的中断 - IRQ_WAKE_THREAD:有一个进程正在等待这个中断,中断处理完了,应该唤醒它 - 很多中断处理程序将整个中断要做的事情分成两部分,称为上半部和下半部,或者成为关键处理部分和延迟处理部分。在中断处理函数中,仅仅处理关键部分,完成了就将中断信号打开,使得新的中断可以进来,需要比较长时间处理的部分,也即延迟部分,往往通过工作队列等方式慢慢处理。 - 注册中断处理函数:request_irq - 函数入参 - unsigned int irq 是中断信号 - irq_handler_t handler 是中断处理函数 - unsigned long flags 是一些标识位 - const char *name 是设备名称 - void *dev 这个通用指针应该和中断处理函数的 void *dev 相对应 - 初始化描述中断的结构体 irq_desc,其中 struct irqaction,用于表示处理这个中断的动作,irqaction 都有以下成员 - 中断处理函数 handler - void *dev_id 为设备 id - irq 为中断信号 - next 为指向下一个 action 的链表指针 - 如果中断处理函数在单独的线程运行,则有 thread_fn 是线程的执行函数,thread 是线程的 task_struct - irpaction 的存储数据结构通过宏 CONFIG_SPARSE_IRQ 配置 - 如果为连续下标则使用数组 - 如果为不连续下标则使用基数树 - irq 并不是真正的、物理的中断信号,而是一个抽象的、虚拟的中断信号 - 内部调用 request_threaded_irq->__setup_irq - 查找 irq_desc 是否已经有 irqaction - irq 有一个 next 的参数,如果已经有同类的 action,则将其挂在链表末尾 - 如果设定了以单独的线程运行中断处理函数,setup_irq_thread 就会创建这个内核线程,wake_up_process 会唤醒它 - 中断处理流程 - 外部设备给中断控制器发送物理中断信号 - 中断控制器将物理中断信号转换成为中断向量 interrupt vector,发给各个 CPU - 每个 CPU 都会有一个中断向量表,根据 interrupt vector 调用一个 IRQ 处理函数。注意这里的 IRQ 处理函数还不是咱们上面指定的 irq_handler_t,到这一层还是 CPU 硬件的要求 - 在 IRQ 处理函数中,将 interrupt vector 转化为抽象中断层的中断信号 irq,调用中断信号 irq 对应的中断描述结构里面的 irq_handler_t
    2020-03-01
    1
    6
  • 西山薄凉
    下半部分----- - 硬件 中断处理 - CPU 能够处理的中断总共 256 个,用宏 NR_VECTOR 或者 FIRST_SYSTEM_VECTOR 表示 - CPU 硬件要求每一个 CPU 都有一个中断向量表 idt_table,通过 load_idt 加载,里面记录着每一个中断对应的处理函数 - 中断被分为几个部分 - 0 到 31 的前 32 位是系统陷入或者系统异常,这些错误无法屏蔽,一定要处理;中断向量表中已经填好了前 32 位,外加一位 32 位系统调用 - 其他的都是用于设备中断 - 硬件中断的处理函数是 do_IRQ 进行统一处理,在这里会让中断向量,通过 vector_irq 映射为 irq_desc - 找到注册的中断处理 action 并执行
    2020-03-01
    4
收起评论
显示
设置
留言
17
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部