转自:https://blog.csdn.net/tiantao2012/article/details/78957472

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tiantao2012/article/details/78957472

[html] view plain copy
int setup_irq(unsigned int irq, struct irqaction *act)用于设置irq对应的irqaction. 其使用的例程如下:
struct irq_domain * __init __init_i8259_irqs(struct device_node *node)
{
struct irq_domain *domain; insert_resource(&ioport_resource, &pic1_io_resource);
insert_resource(&ioport_resource, &pic2_io_resource); init_8259A(); domain = irq_domain_add_legacy(node, , I8259A_IRQ_BASE, ,
&i8259A_ops, NULL);
if (!domain)
panic("Failed to add i8259 IRQ domain"); setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
return domain;
}
其源码分析如下: int setup_irq(unsigned int irq, struct irqaction *act)
{
int retval;
struct irq_desc *desc = irq_to_desc(irq);
#中断描述为null,或者设置了_IRQ_PER_CPU_DEVID 标志的话,则直接退出
if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
return -EINVAL; retval = irq_chip_pm_get(&desc->irq_data);
if (retval < )
return retval;
#核心代码,设置irq对应的irqaction *act
retval = __setup_irq(irq, desc, act); if (retval)
irq_chip_pm_put(&desc->irq_data); return retval;
}
static int
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
struct irqaction *old, **old_ptr;
unsigned long flags, thread_mask = ;
int ret, nested, shared = ;
#中断描述符为null,则退出
if (!desc)
return -EINVAL;
#没有设置irq_data.chip,所以irq_data.chip 会等于no_irq_chip。这属于异常case ,退出.
if (desc->irq_data.chip == &no_irq_chip)
return -ENOSYS;
#增加这个模块的引用计数
if (!try_module_get(desc->owner))
return -ENODEV;
#更新struct irqaction *new 中的irq number
new->irq = irq; /*
* If the trigger type is not specified by the caller,
* then use the default for this interrupt.
*/
#没有设置中断触发类型的话,则用默认值.
if (!(new->flags & IRQF_TRIGGER_MASK))
new->flags |= irqd_get_trigger_type(&desc->irq_data); /*
* Check whether the interrupt nests into another interrupt
* thread.
*/
#检查这里是否是中断嵌套,正常情况下irq_chip 基本都不支持中断嵌套
nested = irq_settings_is_nested_thread(desc);
if (nested) {
if (!new->thread_fn) {
ret = -EINVAL;
goto out_mput;
}
/*
* Replace the primary handler which was provided from
* the driver for non nested interrupt handling by the
* dummy function which warns when called.
*/
new->handler = irq_nested_primary_handler;
} else {
#这里检查是否为这个中断设置一个thread,也就是说是否支持中断线程化
if (irq_settings_can_thread(desc)) {
ret = irq_setup_forced_threading(new);
if (ret)
goto out_mput;
}
} /*
* Create a handler thread when a thread function is supplied
* and the interrupt does not nest into another interrupt
* thread.
*/
#在没有支持中断嵌套且用户用设置中断线程的情况下,这里会创建一个中断线程
if (new->thread_fn && !nested) {
ret = setup_irq_thread(new, irq, false);
if (ret)
goto out_mput;
#中断线程化时是否支持第二个线程。如果支持的话,再创建一个中断线程.
if (new->secondary) {
ret = setup_irq_thread(new->secondary, irq, true);
if (ret)
goto out_thread;
}
} /*
* Drivers are often written to work w/o knowledge about the
* underlying irq chip implementation, so a request for a
* threaded irq without a primary hard irq context handler
* requires the ONESHOT flag to be set. Some irq chips like
* MSI based interrupts are per se one shot safe. Check the
* chip flags, so we can avoid the unmask dance at the end of
* the threaded handler for those.
*/
#有设置oneshot 标志的话,则清掉这个标志.
if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
new->flags &= ~IRQF_ONESHOT; /*
* Protects against a concurrent __free_irq() call which might wait
* for synchronize_irq() to complete without holding the optional
* chip bus lock and desc->lock.
*/
mutex_lock(&desc->request_mutex); /*
* Acquire bus lock as the irq_request_resources() callback below
* might rely on the serialization or the magic power management
* functions which are abusing the irq_bus_lock() callback,
*/
chip_bus_lock(desc); /* First installed action requests resources. */
#中断描述符的action为null的话,则通过irq_request_resources 来申请中断资源.
if (!desc->action) {
ret = irq_request_resources(desc);
if (ret) {
pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
new->name, irq, desc->irq_data.chip->name);
goto out_bus_unlock;
}
} /*
* The following block of code has to be executed atomically
* protected against a concurrent interrupt and any of the other
* management calls which are not serialized via
* desc->request_mutex or the optional bus lock.
*/
raw_spin_lock_irqsave(&desc->lock, flags);
old_ptr = &desc->action;
old = *old_ptr;
#如果这个中断号对应的中断描述符中的action 不为null,说明这个中断号之前可能已经申请过中断了
#这里同样可以得出结论,同一个中断好,可以重复申请中断,但是可能会继承前一次的中断触发类型.
if (old) {
/*
* Can't share interrupts unless both agree to and are
* the same type (level, edge, polarity). So both flag
* fields must have IRQF_SHARED set and the bits which
* set the trigger type must match. Also all must
* agree on ONESHOT.
*/
unsigned int oldtype; /*
* If nobody did set the configuration before, inherit
* the one provided by the requester.
*/
if (irqd_trigger_type_was_set(&desc->irq_data)) {
oldtype = irqd_get_trigger_type(&desc->irq_data);
} else {
oldtype = new->flags & IRQF_TRIGGER_MASK;
irqd_set_trigger_type(&desc->irq_data, oldtype);
} if (!((old->flags & new->flags) & IRQF_SHARED) ||
(oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||
((old->flags ^ new->flags) & IRQF_ONESHOT))
goto mismatch; /* All handlers must agree on per-cpuness */
if ((old->flags & IRQF_PERCPU) !=
(new->flags & IRQF_PERCPU))
goto mismatch; /* add new interrupt at end of irq queue */
do {
/*
* Or all existing action->thread_mask bits,
* so we can find the next zero bit for this
* new action.
*/
thread_mask |= old->thread_mask;
old_ptr = &old->next;
old = *old_ptr;
} while (old);
shared = ;
} /*
* Setup the thread mask for this irqaction for ONESHOT. For
* !ONESHOT irqs the thread mask is 0 so we can avoid a
* conditional in irq_wake_thread().
*/
if (new->flags & IRQF_ONESHOT) {
/*
* Unlikely to have 32 resp 64 irqs sharing one line,
* but who knows.
*/
if (thread_mask == ~0UL) {
ret = -EBUSY;
goto out_unlock;
}
/*
* The thread_mask for the action is or'ed to
* desc->thread_active to indicate that the
* IRQF_ONESHOT thread handler has been woken, but not
* yet finished. The bit is cleared when a thread
* completes. When all threads of a shared interrupt
* line have completed desc->threads_active becomes
* zero and the interrupt line is unmasked. See
* handle.c:irq_wake_thread() for further information.
*
* If no thread is woken by primary (hard irq context)
* interrupt handlers, then desc->threads_active is
* also checked for zero to unmask the irq line in the
* affected hard irq flow handlers
* (handle_[fasteoi|level]_irq).
*
* The new action gets the first zero bit of
* thread_mask assigned. See the loop above which or's
* all existing action->thread_mask bits.
*/
new->thread_mask = 1UL << ffz(thread_mask); } else if (new->handler == irq_default_primary_handler &&
!(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {
/*
* The interrupt was requested with handler = NULL, so
* we use the default primary handler for it. But it
* does not have the oneshot flag set. In combination
* with level interrupts this is deadly, because the
* default primary handler just wakes the thread, then
* the irq lines is reenabled, but the device still
* has the level irq asserted. Rinse and repeat....
*
* While this works for edge type interrupts, we play
* it safe and reject unconditionally because we can't
* say for sure which type this interrupt really
* has. The type flags are unreliable as the
* underlying chip implementation can override them.
*/
pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n",
irq);
ret = -EINVAL;
goto out_unlock;
}
#非共享中断
if (!shared) {
#初始化一个等待队列,这个等待队列包含在中断描述符中
init_waitqueue_head(&desc->wait_for_threads); /* Setup the type (level, edge polarity) if configured: */
if (new->flags & IRQF_TRIGGER_MASK) {
ret = __irq_set_trigger(desc,
new->flags & IRQF_TRIGGER_MASK); if (ret)
goto out_unlock;
} /*
* Activate the interrupt. That activation must happen
* independently of IRQ_NOAUTOEN. request_irq() can fail
* and the callers are supposed to handle
* that. enable_irq() of an interrupt requested with
* IRQ_NOAUTOEN is not supposed to fail. The activation
* keeps it in shutdown mode, it merily associates
* resources if necessary and if that's not possible it
* fails. Interrupts which are in managed shutdown mode
* will simply ignore that activation request.
*/
#激活这个中断
ret = irq_activate(desc);
if (ret)
goto out_unlock; desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
IRQS_ONESHOT | IRQS_WAITING);
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
#是不是percpu中断
if (new->flags & IRQF_PERCPU) {
irqd_set(&desc->irq_data, IRQD_PER_CPU);
irq_settings_set_per_cpu(desc);
} if (new->flags & IRQF_ONESHOT)
desc->istate |= IRQS_ONESHOT; /* Exclude IRQ from balancing if requested */
#不用设置irq balance
if (new->flags & IRQF_NOBALANCING) {
irq_settings_set_no_balancing(desc);
irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
}
#开始中断
if (irq_settings_can_autoenable(desc)) {
irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
} else {
/*
* Shared interrupts do not go well with disabling
* auto enable. The sharing interrupt might request
* it while it's still disabled and then wait for
* interrupts forever.
*/
WARN_ON_ONCE(new->flags & IRQF_SHARED);
/* Undo nested disables: */
desc->depth = ;
} } else if (new->flags & IRQF_TRIGGER_MASK) {
unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;
unsigned int omsk = irqd_get_trigger_type(&desc->irq_data); if (nmsk != omsk)
/* hope the handler works with current trigger mode */
pr_warn("irq %d uses trigger mode %u; requested %u\n",
irq, omsk, nmsk);
} *old_ptr = new;
#设置power相关
irq_pm_install_action(desc, new); /* Reset broken irq detection when installing new handler */
desc->irq_count = ;
desc->irqs_unhandled = ; /*
* Check whether we disabled the irq via the spurious handler
* before. Reenable it and give it another chance.
*/
if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {
desc->istate &= ~IRQS_SPURIOUS_DISABLED;
__enable_irq(desc);
} raw_spin_unlock_irqrestore(&desc->lock, flags);
chip_bus_sync_unlock(desc);
mutex_unlock(&desc->request_mutex); irq_setup_timings(desc, new); /*
* Strictly no need to wake it up, but hung_task complains
* when no hard interrupt wakes the thread up.
*/
# 如果有中断线程的话,则wakeup线程
if (new->thread)
wake_up_process(new->thread);
if (new->secondary)
wake_up_process(new->secondary->thread);
#注册irq在proc中的接口
register_irq_proc(irq, desc);
new->dir = NULL;
register_handler_proc(irq, new);
return ; mismatch:
if (!(new->flags & IRQF_PROBE_SHARED)) {
pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n",
irq, new->flags, new->name, old->flags, old->name);
#ifdef CONFIG_DEBUG_SHIRQ
dump_stack();
#endif
}
ret = -EBUSY;
#一下都是异常case
out_unlock:
raw_spin_unlock_irqrestore(&desc->lock, flags); if (!desc->action)
irq_release_resources(desc);
out_bus_unlock:
chip_bus_sync_unlock(desc);
mutex_unlock(&desc->request_mutex); out_thread:
if (new->thread) {
struct task_struct *t = new->thread; new->thread = NULL;
kthread_stop(t);
put_task_struct(t);
}
if (new->secondary && new->secondary->thread) {
struct task_struct *t = new->secondary->thread; new->secondary->thread = NULL;
kthread_stop(t);
put_task_struct(t);
}
out_mput:
module_put(desc->owner);
return ret;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tiantao2012/article/details/78957472

[html] view plain copy

 
  1. int setup_irq(unsigned int irq, struct irqaction *act)用于设置irq对应的irqaction.
  2. 其使用的例程如下:
  3. struct irq_domain * __init __init_i8259_irqs(struct device_node *node)
  4. {
  5. struct irq_domain *domain;
  6. insert_resource(&ioport_resource, &pic1_io_resource);
  7. insert_resource(&ioport_resource, &pic2_io_resource);
  8. init_8259A(0);
  9. domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0,
  10. &i8259A_ops, NULL);
  11. if (!domain)
  12. panic("Failed to add i8259 IRQ domain");
  13. setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
  14. return domain;
  15. }
  16. 其源码分析如下:
  17. int setup_irq(unsigned int irq, struct irqaction *act)
  18. {
  19. int retval;
  20. struct irq_desc *desc = irq_to_desc(irq);
  21. #中断描述为null,或者设置了_IRQ_PER_CPU_DEVID 标志的话,则直接退出
  22. if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
  23. return -EINVAL;
  24. retval = irq_chip_pm_get(&desc->irq_data);
  25. if (retval < 0)
  26. return retval;
  27. #核心代码,设置irq对应的irqaction *act
  28. retval = __setup_irq(irq, desc, act);
  29. if (retval)
  30. irq_chip_pm_put(&desc->irq_data);
  31. return retval;
  32. }
  33. static int
  34. __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
  35. {
  36. struct irqaction *old, **old_ptr;
  37. unsigned long flags, thread_mask = 0;
  38. int ret, nested, shared = 0;
  39. #中断描述符为null,则退出
  40. if (!desc)
  41. return -EINVAL;
  42. #没有设置irq_data.chip,所以irq_data.chip 会等于no_irq_chip。这属于异常case ,退出.
  43. if (desc->irq_data.chip == &no_irq_chip)
  44. return -ENOSYS;
  45. #增加这个模块的引用计数
  46. if (!try_module_get(desc->owner))
  47. return -ENODEV;
  48. #更新struct irqaction *new 中的irq number
  49. new->irq = irq;
  50. /*
  51. * If the trigger type is not specified by the caller,
  52. * then use the default for this interrupt.
  53. */
  54. #没有设置中断触发类型的话,则用默认值.
  55. if (!(new->flags & IRQF_TRIGGER_MASK))
  56. new->flags |= irqd_get_trigger_type(&desc->irq_data);
  57. /*
  58. * Check whether the interrupt nests into another interrupt
  59. * thread.
  60. */
  61. #检查这里是否是中断嵌套,正常情况下irq_chip 基本都不支持中断嵌套
  62. nested = irq_settings_is_nested_thread(desc);
  63. if (nested) {
  64. if (!new->thread_fn) {
  65. ret = -EINVAL;
  66. goto out_mput;
  67. }
  68. /*
  69. * Replace the primary handler which was provided from
  70. * the driver for non nested interrupt handling by the
  71. * dummy function which warns when called.
  72. */
  73. new->handler = irq_nested_primary_handler;
  74. } else {
  75. #这里检查是否为这个中断设置一个thread,也就是说是否支持中断线程化
  76. if (irq_settings_can_thread(desc)) {
  77. ret = irq_setup_forced_threading(new);
  78. if (ret)
  79. goto out_mput;
  80. }
  81. }
  82. /*
  83. * Create a handler thread when a thread function is supplied
  84. * and the interrupt does not nest into another interrupt
  85. * thread.
  86. */
  87. #在没有支持中断嵌套且用户用设置中断线程的情况下,这里会创建一个中断线程
  88. if (new->thread_fn && !nested) {
  89. ret = setup_irq_thread(new, irq, false);
  90. if (ret)
  91. goto out_mput;
  92. #中断线程化时是否支持第二个线程。如果支持的话,再创建一个中断线程.
  93. if (new->secondary) {
  94. ret = setup_irq_thread(new->secondary, irq, true);
  95. if (ret)
  96. goto out_thread;
  97. }
  98. }
  99. /*
  100. * Drivers are often written to work w/o knowledge about the
  101. * underlying irq chip implementation, so a request for a
  102. * threaded irq without a primary hard irq context handler
  103. * requires the ONESHOT flag to be set. Some irq chips like
  104. * MSI based interrupts are per se one shot safe. Check the
  105. * chip flags, so we can avoid the unmask dance at the end of
  106. * the threaded handler for those.
  107. */
  108. #有设置oneshot 标志的话,则清掉这个标志.
  109. if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
  110. new->flags &= ~IRQF_ONESHOT;
  111. /*
  112. * Protects against a concurrent __free_irq() call which might wait
  113. * for synchronize_irq() to complete without holding the optional
  114. * chip bus lock and desc->lock.
  115. */
  116. mutex_lock(&desc->request_mutex);
  117. /*
  118. * Acquire bus lock as the irq_request_resources() callback below
  119. * might rely on the serialization or the magic power management
  120. * functions which are abusing the irq_bus_lock() callback,
  121. */
  122. chip_bus_lock(desc);
  123. /* First installed action requests resources. */
  124. #中断描述符的action为null的话,则通过irq_request_resources 来申请中断资源.
  125. if (!desc->action) {
  126. ret = irq_request_resources(desc);
  127. if (ret) {
  128. pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
  129. new->name, irq, desc->irq_data.chip->name);
  130. goto out_bus_unlock;
  131. }
  132. }
  133. /*
  134. * The following block of code has to be executed atomically
  135. * protected against a concurrent interrupt and any of the other
  136. * management calls which are not serialized via
  137. * desc->request_mutex or the optional bus lock.
  138. */
  139. raw_spin_lock_irqsave(&desc->lock, flags);
  140. old_ptr = &desc->action;
  141. old = *old_ptr;
  142. #如果这个中断号对应的中断描述符中的action 不为null,说明这个中断号之前可能已经申请过中断了
  143. #这里同样可以得出结论,同一个中断好,可以重复申请中断,但是可能会继承前一次的中断触发类型.
  144. if (old) {
  145. /*
  146. * Can't share interrupts unless both agree to and are
  147. * the same type (level, edge, polarity). So both flag
  148. * fields must have IRQF_SHARED set and the bits which
  149. * set the trigger type must match. Also all must
  150. * agree on ONESHOT.
  151. */
  152. unsigned int oldtype;
  153. /*
  154. * If nobody did set the configuration before, inherit
  155. * the one provided by the requester.
  156. */
  157. if (irqd_trigger_type_was_set(&desc->irq_data)) {
  158. oldtype = irqd_get_trigger_type(&desc->irq_data);
  159. } else {
  160. oldtype = new->flags & IRQF_TRIGGER_MASK;
  161. irqd_set_trigger_type(&desc->irq_data, oldtype);
  162. }
  163. if (!((old->flags & new->flags) & IRQF_SHARED) ||
  164. (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||
  165. ((old->flags ^ new->flags) & IRQF_ONESHOT))
  166. goto mismatch;
  167. /* All handlers must agree on per-cpuness */
  168. if ((old->flags & IRQF_PERCPU) !=
  169. (new->flags & IRQF_PERCPU))
  170. goto mismatch;
  171. /* add new interrupt at end of irq queue */
  172. do {
  173. /*
  174. * Or all existing action->thread_mask bits,
  175. * so we can find the next zero bit for this
  176. * new action.
  177. */
  178. thread_mask |= old->thread_mask;
  179. old_ptr = &old->next;
  180. old = *old_ptr;
  181. } while (old);
  182. shared = 1;
  183. }
  184. /*
  185. * Setup the thread mask for this irqaction for ONESHOT. For
  186. * !ONESHOT irqs the thread mask is 0 so we can avoid a
  187. * conditional in irq_wake_thread().
  188. */
  189. if (new->flags & IRQF_ONESHOT) {
  190. /*
  191. * Unlikely to have 32 resp 64 irqs sharing one line,
  192. * but who knows.
  193. */
  194. if (thread_mask == ~0UL) {
  195. ret = -EBUSY;
  196. goto out_unlock;
  197. }
  198. /*
  199. * The thread_mask for the action is or'ed to
  200. * desc->thread_active to indicate that the
  201. * IRQF_ONESHOT thread handler has been woken, but not
  202. * yet finished. The bit is cleared when a thread
  203. * completes. When all threads of a shared interrupt
  204. * line have completed desc->threads_active becomes
  205. * zero and the interrupt line is unmasked. See
  206. * handle.c:irq_wake_thread() for further information.
  207. *
  208. * If no thread is woken by primary (hard irq context)
  209. * interrupt handlers, then desc->threads_active is
  210. * also checked for zero to unmask the irq line in the
  211. * affected hard irq flow handlers
  212. * (handle_[fasteoi|level]_irq).
  213. *
  214. * The new action gets the first zero bit of
  215. * thread_mask assigned. See the loop above which or's
  216. * all existing action->thread_mask bits.
  217. */
  218. new->thread_mask = 1UL << ffz(thread_mask);
  219. } else if (new->handler == irq_default_primary_handler &&
  220. !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {
  221. /*
  222. * The interrupt was requested with handler = NULL, so
  223. * we use the default primary handler for it. But it
  224. * does not have the oneshot flag set. In combination
  225. * with level interrupts this is deadly, because the
  226. * default primary handler just wakes the thread, then
  227. * the irq lines is reenabled, but the device still
  228. * has the level irq asserted. Rinse and repeat....
  229. *
  230. * While this works for edge type interrupts, we play
  231. * it safe and reject unconditionally because we can't
  232. * say for sure which type this interrupt really
  233. * has. The type flags are unreliable as the
  234. * underlying chip implementation can override them.
  235. */
  236. pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n",
  237. irq);
  238. ret = -EINVAL;
  239. goto out_unlock;
  240. }
  241. #非共享中断
  242. if (!shared) {
  243. #初始化一个等待队列,这个等待队列包含在中断描述符中
  244. init_waitqueue_head(&desc->wait_for_threads);
  245. /* Setup the type (level, edge polarity) if configured: */
  246. if (new->flags & IRQF_TRIGGER_MASK) {
  247. ret = __irq_set_trigger(desc,
  248. new->flags & IRQF_TRIGGER_MASK);
  249. if (ret)
  250. goto out_unlock;
  251. }
  252. /*
  253. * Activate the interrupt. That activation must happen
  254. * independently of IRQ_NOAUTOEN. request_irq() can fail
  255. * and the callers are supposed to handle
  256. * that. enable_irq() of an interrupt requested with
  257. * IRQ_NOAUTOEN is not supposed to fail. The activation
  258. * keeps it in shutdown mode, it merily associates
  259. * resources if necessary and if that's not possible it
  260. * fails. Interrupts which are in managed shutdown mode
  261. * will simply ignore that activation request.
  262. */
  263. #激活这个中断
  264. ret = irq_activate(desc);
  265. if (ret)
  266. goto out_unlock;
  267. desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
  268. IRQS_ONESHOT | IRQS_WAITING);
  269. irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
  270. #是不是percpu中断
  271. if (new->flags & IRQF_PERCPU) {
  272. irqd_set(&desc->irq_data, IRQD_PER_CPU);
  273. irq_settings_set_per_cpu(desc);
  274. }
  275. if (new->flags & IRQF_ONESHOT)
  276. desc->istate |= IRQS_ONESHOT;
  277. /* Exclude IRQ from balancing if requested */
  278. #不用设置irq balance
  279. if (new->flags & IRQF_NOBALANCING) {
  280. irq_settings_set_no_balancing(desc);
  281. irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
  282. }
  283. #开始中断
  284. if (irq_settings_can_autoenable(desc)) {
  285. irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
  286. } else {
  287. /*
  288. * Shared interrupts do not go well with disabling
  289. * auto enable. The sharing interrupt might request
  290. * it while it's still disabled and then wait for
  291. * interrupts forever.
  292. */
  293. WARN_ON_ONCE(new->flags & IRQF_SHARED);
  294. /* Undo nested disables: */
  295. desc->depth = 1;
  296. }
  297. } else if (new->flags & IRQF_TRIGGER_MASK) {
  298. unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;
  299. unsigned int omsk = irqd_get_trigger_type(&desc->irq_data);
  300. if (nmsk != omsk)
  301. /* hope the handler works with current  trigger mode */
  302. pr_warn("irq %d uses trigger mode %u; requested %u\n",
  303. irq, omsk, nmsk);
  304. }
  305. *old_ptr = new;
  306. #设置power相关
  307. irq_pm_install_action(desc, new);
  308. /* Reset broken irq detection when installing new handler */
  309. desc->irq_count = 0;
  310. desc->irqs_unhandled = 0;
  311. /*
  312. * Check whether we disabled the irq via the spurious handler
  313. * before. Reenable it and give it another chance.
  314. */
  315. if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {
  316. desc->istate &= ~IRQS_SPURIOUS_DISABLED;
  317. __enable_irq(desc);
  318. }
  319. raw_spin_unlock_irqrestore(&desc->lock, flags);
  320. chip_bus_sync_unlock(desc);
  321. mutex_unlock(&desc->request_mutex);
  322. irq_setup_timings(desc, new);
  323. /*
  324. * Strictly no need to wake it up, but hung_task complains
  325. * when no hard interrupt wakes the thread up.
  326. */
  327. # 如果有中断线程的话,则wakeup线程
  328. if (new->thread)
  329. wake_up_process(new->thread);
  330. if (new->secondary)
  331. wake_up_process(new->secondary->thread);
  332. #注册irq在proc中的接口
  333. register_irq_proc(irq, desc);
  334. new->dir = NULL;
  335. register_handler_proc(irq, new);
  336. return 0;
  337. mismatch:
  338. if (!(new->flags & IRQF_PROBE_SHARED)) {
  339. pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n",
  340. irq, new->flags, new->name, old->flags, old->name);
  341. #ifdef CONFIG_DEBUG_SHIRQ
  342. dump_stack();
  343. #endif
  344. }
  345. ret = -EBUSY;
  346. #一下都是异常case
  347. out_unlock:
  348. raw_spin_unlock_irqrestore(&desc->lock, flags);
  349. if (!desc->action)
  350. irq_release_resources(desc);
  351. out_bus_unlock:
  352. chip_bus_sync_unlock(desc);
  353. mutex_unlock(&desc->request_mutex);
  354. out_thread:
  355. if (new->thread) {
  356. struct task_struct *t = new->thread;
  357. new->thread = NULL;
  358. kthread_stop(t);
  359. put_task_struct(t);
  360. }
  361. if (new->secondary && new->secondary->thread) {
  362. struct task_struct *t = new->secondary->thread;
  363. new->secondary->thread = NULL;
  364. kthread_stop(t);
  365. put_task_struct(t);
  366. }
  367. out_mput:
  368. module_put(desc->owner);
  369. return ret;
  370. }

中断API之setup_irq【转】的更多相关文章

  1. Linux kernel的中断子系统之(五):驱动申请中断API

    返回目录:<ARM-Linux中断系统>. 总结:二重点区分了抢占式内核和非抢占式内核的区别:抢占式内核可以在内核空间进行抢占,通过对中断处理进行线程化可以提高Linux内核实时性. 三介 ...

  2. Linux中断 - 驱动申请中断API

    一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的驱动的时候,如何向Linux Kernel中的中断子系统注册中断处理函数?为了理解注册中断的接口,必须了解一些中断线程化(threa ...

  3. Linux kernel中断子系统之(五):驱动申请中断API【转】

    转自:http://www.wowotech.net/linux_kenrel/request_threaded_irq.html 一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的 ...

  4. GPIO口及中断API函数【转】

    本文转载自:http://blog.sina.com.cn/s/blog_a6559d9201015vx9.htmlG #include <linux/gpio.h> // 标准 GPIO ...

  5. 中断API之enable_irq

    void enable_irq(unsigned int irq) 用于使能一个irq. void disable_irq(unsigned int irq)则用于禁止一个irq 其使用的例程如下: ...

  6. 非常好!!!Linux源代码阅读——中断【转】

    Linux源代码阅读——中断 转自:http://home.ustc.edu.cn/~boj/courses/linux_kernel/2_int.html 目录 为什么要有中断 中断的作用 中断的处 ...

  7. Intel 80x86 Linux Kernel Interrupt(中断)、Interrupt Priority、Interrupt nesting、Prohibit Things Whthin CPU In The Interrupt Off State

    目录 . 引言 . Linux 中断的概念 . 中断处理流程 . Linux 中断相关的源代码分析 . Linux 硬件中断 . Linux 软中断 . 中断优先级 . CPU在关中断状态下编程要注意 ...

  8. 基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(1)

    作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台 tiny4412 ADK Linux-4.9 概述 前面几篇博文列举了在有设备树的时候,gpio中断的 ...

  9. ARM-Linux中断系统

    1.前言 了解Linux中断子系统,同时也需要了解ARM体系结构中断处理流程:在熟悉整个软硬件架构和流程基础上,才能对流程进行细化,然后找出问题的瓶颈.<2. 梳理中断处理子系统> 但是所 ...

随机推荐

  1. raid5 / raid5e / raid5ee的性能对比及其数据恢复原理

    RAID 5 是一种存储性能.数据安全和存储成本兼顾的存储解决方案. RAID 5可以理解为是RAID 0和RAID 1的折中方案.RAID 5可以为系统提供数据安全保障,但保障程度要比Mirror低 ...

  2. nyoj 孪生素数

    孪生素数问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 写一个程序,找出给出素数范围内的所有孪生素数的组数.一般来说,孪生素数就是指两个素数距离为2,近的不能再 ...

  3. fabric.js和高级画板

    本文介绍fabric.js框架使用,以及使用fabricjs打造一个高级画板程序. 高级画板功能介绍 全局绘制颜色选择 护眼模式.网格模式切换 自由绘制 画箭头 画直线 画虚线 画圆/椭圆/矩形/直角 ...

  4. appiun滑动的简单封装

    import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.test ...

  5. C#微信公众号——本地调试

    测试微信,因为要与微信服务器进行交互,所以必须要是外网地址,实现本地调试首先需要解决的问题就是外网问题,这个我前面的文章有介绍,这里就不再详细介绍了,网址http://www.cnblogs.com/ ...

  6. Python系列-python函数

    函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己创建函数,这 ...

  7. "共振式”项目管理

    "共振式”项目管理--是我第一个提出的吗?:) 脑子里突然想到项目管理的一些事情,然后想到项目其实是有节奏的,项目中的人员其实如果找到了这个节奏,踏准了节奏,一切将是顺风顺水. 刚准备动笔时 ...

  8. Django--ORM基本操作

    一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pr ...

  9. .NET Core 2.1 Preview 2发布 - April 10, 2018

    我们今天宣布发布 .NET Core 2.1 Preview 2.这也是我们在接下来的两到三个月内接近最终发布的版本,该版本现已准备好进行广泛的测试.我们希望您有任何反馈意见. ASP.NET Cor ...

  10. __new__方法首先调用并返回一个实例化对象

    >>> class CapStr(str): def __new__(cls,string): string = string.upper() return str.__new__( ...