驅動程式 - Linux Device Driver (LDD) - 使用範例 - Assembly (ARM) - Tasklet



tasklet也是屬於softirq的一種,差別在於執行順序是排在softirq後面且不會有重複進入問題(reentrant),加上不是靜態編譯,因此,不需要特別修改Kernel就可以使用,因此,是一種相當適合應用在高優先級別的延遲處理機制,當然,高優先級別的機制是不適合處理太過耗時的東西,這點還是需要特別注意

使用步驟:

1. tasklet_init()
2. _test_and_set_bit()
3. __tasklet_schedule()
4. tasklet_kill()

ldd.S

    .global init_module
    .global cleanup_module

    .equ BUTTON,              27
    .equ IRQF_TRIGGER_RISING, 1
    .equ TASKLET_STATE_SCHED, 0
    .equ TASKLET_STATE_RUN,   1

    .section .modinfo, "ae"
__UNIQUE_ID_0: .asciz "license=GPL"
__UNIQUE_ID_1: .asciz "author=Steward Fu"
__UNIQUE_ID_2: .asciz "description=Linux Driver"

    .equ tasklet.next,  0
    .equ tasklet.state, 4
    .equ tasklet.count, 8
    .equ tasklet.func,  12
    .equ tasklet.data,  16

    .struct 0
tasklet_s:
    i0: .struct . + 4
    i1: .struct . + 4
    i2: .struct . + 4
    i3: .struct . + 4
    i4: .struct . + 4
tasklet_e:
tasklet_l = tasklet_e - tasklet_s

    .section .data
btn_irq:  .dcb 4
irq_name: .asciz "gpio_irq"
task_msg: .asciz "tasklet_handler\n"
mytask:   .space tasklet_l

    .align 2
    .section .text
tasklet_handler:
    push {lr}
    ldr r0, =task_msg
    bl printk
    pop {pc}

irq_handler:
    push {lr}
    mov r0, #TASKLET_STATE_SCHED
    ldr r1, =mytask
    add r1, #tasklet.state
    bl _test_and_set_bit
    cmp r0, #0
    bne irq_exit
    ldr r0, =mytask
    bl __tasklet_schedule
irq_exit:
    mov r0, #1
    pop {pc}

init_module:
    push {r4, r5, lr}

    ldr r0, =mytask
    ldr r1, =tasklet_handler
    mov r2, #0
    bl tasklet_init

    mov r0, #BUTTON
    bl gpio_to_desc
    bl gpiod_to_irq
    ldr r1, =btn_irq
    str r0, [r1]

    ldr r1, =irq_handler
    mov r2, #0
    mov r3, #IRQF_TRIGGER_RISING
    ldr r4, =irq_name
    mov r5, #0
    push {r4, r5}
    bl request_threaded_irq
    pop {r4, r5}

    mov r0, #0
    pop {r4, r5, pc}

cleanup_module:
    push {lr}
    ldr r0, =btn_irq
    ldr r0, [r0]
    mov r1, #0
    bl free_irq
    ldr r0, =mytask
    bl tasklet_kill
    pop {pc}
    .end

init_module: 設定GPIO中斷以及tasklet延遲處理副程式
irq_handler: 安排一個tasklet延遲處理
tasklet_handler: 列印字串
cleanup_module: 釋放中斷資源以及刪除tasklet

完成

# tasklet_handler