Day 14 - Event-driven GPIO Driver¶
🎯 Goal¶
Transform a simple GPIO driver into an event-driven character device with:
- Interrupt-based input handling
- Software debounce (deferred work)
- Event queue (ring buffer)
- Blocking / non-blocking read
- poll/select support
🧠 Key Concepts¶
1. Event-driven vs State-driven¶
| Type | Behavior |
|---|---|
| State device | Read returns current status |
| Event device | Read returns one event |
👉 This driver is now an event stream device
2. IRQ Top Half + Bottom Half¶
Top Half (ISR)¶
- Must be fast
- No sleeping
- Only schedule work
Bottom Half (Delayed Work)¶
- Runs in process context
- Can sleep
- Handles debounce + event generation
3. Software Debounce¶
- Delay processing using
delayed_work - Only report stable state change
4. Ring Buffer (Event Queue)¶
- FIFO queue
- Single producer (worker)
- Single consumer (read)
Full condition¶
👉 Drop event if full
5. Blocking Read (wait queue)¶
Behavior:
- No event → sleep
- Event arrives → wake up
6. Non-blocking Read¶
7. poll / select support¶
Return:
8. Removal Safety¶
Reader behavior:
- Wake up
- Return
-ENODEV
9. Event Semantics¶
- Each read = one event
- Not snapshot
- Continuous stream
🔄 Data Flow¶
IRQ
↓
ISR (top half)
↓
delayed_work
↓
debounce + event push
↓
ring buffer
↓
wake_up_interruptible()
↓
read() / poll()
⚠️ Design Decisions¶
Why not lock-free?¶
- Only 1 producer + 1 consumer
- mutex is simple and safe
- lock-free not necessary here
Why READ_ONCE?¶
- Avoid compiler reordering
- Safe lockless check
Why not kfifo?¶
- Custom ring buffer is sufficient
- Learning purpose
📌 Summary¶
Day14 upgrades the driver to:
- Interrupt-driven
- Event-based
- User-space friendly (poll/select)
- Production-like design