2
在Linux內核驅動程序,我想無限重複序列如下:Linux內核驅動程序:IRQ觸發或超時
- 在時間T,硬件IRQ啓用
- 時間T和T之間+「大約」15ms,如果IRQ被觸發,則可以達到IRQ回調。我說周圍因爲我沒有使用RT內核,如果它是14或16ms,那很好。在IRQ回調中,我需要寫下get cpu_clock(0)並調用wake_up_interruptible。超時需要被終止。整個過程需要在5ms內重新開始。
- 如果通過T +「大約」15ms,IRQ沒有被觸發,我需要執行一些其他代碼。那麼應該禁用IRQ。整個過程需要在5ms內重新開始。
因此,通過T +「大約」20ms,在最壞的情況下,整個過程需要重新開始。
請注意,如果IRQ在18ms處被物理觸發,太糟糕了,「我錯過了火車」。我將在下一個序列中捕獲另一個硬件觸發器。
測試時,我是做沿着下面的僞代碼的東西:
INIT_DELAYED_WORK(&priv->work, driver_work);
INIT_DELAYED_WORK(&priv->timeout, driver_timeout);
request_irq(priv->irq, driver_interrupt, IRQF_TRIGGER_RISING, "my_irq", priv);
則:
queue_delayed_work(priv->workq, &priv->work, 0ms);
static void driver_work(struct work_struct *work) {
queue_delayed_work(priv->workq, &priv->timeout, 15ms);
priv->interruptCalled = 0;
enable_irq(priv->irq);
}
然後:
static irqreturn_t driver_interrupt(int irq, void *_priv) {
disable_irq_nosync(priv->irq);
priv->interruptCalled = 1;
cancel_delayed_work(&priv->timeout);
priv->stamp = cpu_clock(0);
wake_up_interruptible(&driver_wait);
queue_delayed_work(priv->workq, &priv->work, 5ms);
return IRQ_HANDLED;
}
和:
static void driver_timeout(struct work_struct *work) {
if (priv->interruptCalled == 0) {
disable_irq_nosync(priv->irq);
//Do other small cleanup
queue_delayed_work(priv->workq, &priv->work, 5ms);
}
}
我想寫一個健壯但簡單的驅動程序。這是一個適當的實施?我怎樣才能改進這個實現?
cancel_delayed_work不時產生「WARNING:at kernel/timer.c:1061 del_timer_sync + 0x44/0x64()」。我怎樣才能避免這種情況? – gregoiregentil 2013-02-10 18:27:41
此警告對應於WARN_ON(in_irq());看起來從irq上下文刪除定時器並不是一個好主意。 – gregoiregentil 2013-02-10 18:34:58
我已經把「cancel_delayed_work(&priv-> timeout);」作爲「driver_work」的第一行。沒有更多的警告,我認爲邏輯沒有被破壞,因爲即使在IRQ被觸發的情況下,即使超時被觸發,priv-> interruptCalled'也會保護'。 – gregoiregentil 2013-02-10 19:03:10