本文共 4192 字,大约阅读时间需要 13 分钟。
irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)用于修改通过request_irq 注册中断号的handle其使用的例程如下:static int mvebu_pic_probe(struct platform_device *pdev){ struct device_node *node = pdev->dev.of_node; struct mvebu_pic *pic; struct irq_chip *irq_chip; struct resource *res; pic = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pic), GFP_KERNEL); if (!pic) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pic->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pic->base)) return PTR_ERR(pic->base); irq_chip = &pic->irq_chip; irq_chip->name = dev_name(&pdev->dev); irq_chip->irq_mask = mvebu_pic_mask_irq; irq_chip->irq_unmask = mvebu_pic_unmask_irq; irq_chip->irq_eoi = mvebu_pic_eoi_irq; pic->parent_irq = irq_of_parse_and_map(node, 0); if (pic->parent_irq <= 0) { dev_err(&pdev->dev, "Failed to parse parent interrupt\n"); return -EINVAL; } pic->domain = irq_domain_add_linear(node, PIC_MAX_IRQS, &mvebu_pic_domain_ops, pic); if (!pic->domain) { dev_err(&pdev->dev, "Failed to allocate irq domain\n"); return -ENOMEM; } #通过irq_set_chained_handler 来修改pic->parent_irq 中断号的handle irq_set_chained_handler(pic->parent_irq, mvebu_pic_handle_cascade_irq); irq_set_handler_data(pic->parent_irq, pic); on_each_cpu(mvebu_pic_enable_percpu_irq, pic, 1); platform_set_drvdata(pdev, pic); return 0;}其源码分析如下:static inline voidirq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle){ __irq_set_handler(irq, handle, 1, NULL);}继续调用__irq_set_handlervoid__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, const char *name){ unsigned long flags; #通过irq number获取中断描述符的时候需要通过irq_get_desc_buslock/irq_put_desc_busunlock 这一对函数来保护 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); if (!desc) return; #继续调用__irq_do_set_handler 来修改irq对应的handle __irq_do_set_handler(desc, handle, is_chained, name); irq_put_desc_busunlock(desc, flags);}static void__irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle, int is_chained, const char *name){ #handle 为null的话,就会被赋值handle_bad_irq,这种情况一般不会存在。如果不想删掉irq,可以通过这种方式来替换irq原本的handle,从而让irq取消执行 #原来的功能 if (!handle) { handle = handle_bad_irq; } else { struct irq_data *irq_data = &desc->irq_data;#一般不开这个宏 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY /* * With hierarchical domains we might run into a * situation where the outermost chip is not yet set * up, but the inner chips are there. Instead of * bailing we install the handler, but obviously we * cannot enable/startup the interrupt at this point. */ while (irq_data) { if (irq_data->chip != &no_irq_chip) break; /* * Bail out if the outer chip is not set up * and the interrrupt supposed to be started * right away. */ if (WARN_ON(is_chained)) return; /* Try the parent */ irq_data = irq_data->parent_data; }#endif #如果irq_data为null或者没有之指定irq_chip的话,则退出 if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip)) return; } /* Uninstall? */ #如果当前irq 的handle 是handle_bad_irq,则把irq的state设置为disable,这个case 一般也不会成立 if (handle == handle_bad_irq) { if (desc->irq_data.chip != &no_irq_chip) mask_ack_irq(desc); irq_state_set_disabled(desc); if (is_chained) desc->action = NULL; desc->depth = 1; } #这里才是核心代码,给irq对应的中断描述符设置为新的handler desc->handle_irq = handle; #设置name,通过这种方式的name强制为null. desc->name = name; #通过irq_set_chained_handler 设置的时候,is_chained 会为1,所以这个if条件一般成立 if (handle != handle_bad_irq && is_chained) { #得到中断触发类型,例如边沿,电平等 unsigned int type = irqd_get_trigger_type(&desc->irq_data); /* * We're about to start this interrupt immediately, * hence the need to set the trigger configuration. * But the .set_type callback may have overridden the * flow handler, ignoring that we're dealing with a * chained interrupt. Reset it immediately because we * do know better. */ #这里有重新设置一遍中断的类型和handle,因为is_chained为1,所以这里的handle 等于被设置了两次 if (type != IRQ_TYPE_NONE) { __irq_set_trigger(desc, type); desc->handle_irq = handle; } #设置中断描述符的flag irq_settings_set_noprobe(desc); irq_settings_set_norequest(desc); irq_settings_set_nothread(desc); desc->action = &chained_action; #重新激活和开始中断 irq_activate_and_startup(desc, IRQ_RESEND); }}
转载地址:http://zgjmi.baihongyu.com/