请问comquter: callout 问题?

我有一个疑问关于callout:假如写了一个gpio的callout,是不是直接放到…/startup/目录里内核就可以调用了,它是怎么被内核知道在哪里的呢?我的想法是,写一个callout_gpio.c 文件,在init_intrinfo.c里的const static struct startup_intrinfo intrs[]后面加一个结构体说明GPIO的中断(如MX27里),然后就算把GPIO的中断挂上去了?这样做了之后系统是不是就可以响应PIO的中断了呢?就是不清楚callout在系统里处于什么样的位置,在main里面一来就有一个函数add_callout_array(callouts, sizeof(callouts));,但没能理解。能解答一下吗?谢谢了 :cry:

参照callout_interrupt_mx21_gpio.S,依样画了一个 :laughing: ,但对有些地方还是不清楚,麻烦请帮我看一下,谢谢:
/*

  • MC9328MX21 specific GPIO interrupt callouts.
  • interrupt_id_* and interrupt_eoi_* are copied and intermixed with other
  • kernel code during initialisation.
  • They do not follow normal calling conventions, and must fall through
  • to the end, rather than attempting to perform a return instruction.
  • The INTR_GENFLAG_* bits in the intrinfo_entry defines which of the
  • following values can be loaded on entry to these code fragments:
  • r5 - holds the syspageptr (INTR_GENFLAG_SYSPAGE set)
  • r6 - holds the intrinfo_entry pointer (INTR_GENFLAG_INTRINFO set)
  • r7 - holds the interrupt mask count (INTR_GENFLAG_INTRMASK set)
  • The interrupt_id_* routine returns the (controller-relative) level in r4
    */

#include “callout.ah”
#include <arm/at91sam9263.h>



/*


  • Patch callout code (for GPIO)
  • On entry:
  • r0 - physical address of syspage
  • r1 - virtual address of syspage
  • r2 - offset from start of syspage to start of the callout routine
  • r3 - offset from start of syspage to read/write data used by callout

/
interrupt_patch_gpio:
stmdb sp!, {r4, lr}
ldr r1, [sp, #8]
ldr r1, [r1]
add r4, r0, r2 /
address of callout routine */

/*

  • Map interrupt controller registers
    /
    mov r0, #0x200这个参数不知道是什么作用,我暂时为200,PIOA对应的空间为0x200 /
    size of GPIO registers */
    bl callout_io_map

/*

  • Patch the callout routine
    /
    CALLOUT_PATCH r4, r0, r1, r2, ip
    ldmia sp!, {r4, pc}


    /

  • Identify GPIO interrupt source.
  • Returns interrupt number in r4

/
CALLOUT_START(interrupt_id_at9263_gpio, 0, interrupt_patch_gpio)
/

  • Get the interrupt controller base address (patched)
    */
    mov ip, #0x000000ff
    orr ip, ip, #0x0000ff00
    orr ip, ip, #0x00ff0000
    orr ip, ip, #0xff000000 这不是让ip=0xffffffff了么?怎么会得到基地址呢?
    mov r5, #0

2:
cmp r5, #0x80 /* Scan Port A to Port F */但AT91里是PA-PE所以原来的0xa0变成0x80
bgt 1f

/*

  • Read Interrupt Mask and Status
    */
    ldr r3, [ip, #AT91_PIO_IMR]
    ldr r2, [ip, #AT91_PIO_ISR]
    ands r2, r3, r2
    addeq r5, r5, #0x20
    addeq ip, ip, #0x200 在at91里,PA-PE之间的地址变化为0x200,于是修改这里?
    beq 2b

/*

  • Scan for first set bit
    */
    mov r4, #32
    mov r1, #1

0:
subs r4, r4, #1
blt 1f
tst r2, r1, lsl r4
beq 0b

/*

  • Mask the interrupt source
    */
    mov r1, r1, lsl r4
    bic r3, r3, r1
    str r3, [ip, #AT91_PIO_IMR]

/*

  • Clear interrupt status
    */
    str r1, [ip, #AT91_PIO_ISR]

add r4, r4, r5
1:
CALLOUT_END(interrupt_id_at9263_gpio)

对于下面的:
MASK
UNMASK
EIO
都没变化,改变了一下寄存器的名字。

但我还不能理解patch routines 的作用,帮助里只说了The patch code is run during execution of the startup program itself, so regular calls work as normal。但我不知道它是在哪里被startup 执行的,我把这个gpio.c的文件放到startup的lib里就可了还是需要在startup里的main里加上?
The purpose of the patch routines is to allow you to patch up the code with constants, access to RW data storage etc.它最后的结果是什么呢?是不是给对应的callout提供一个address of a patcher() routine,能不能讲一下其中的过程。非常感谢 :blush:

还有一个问题就是:
// GPIO interrupt (Port A to Port E) (64-256)
{ 32, // vector base 我设成32,这个数是不是任意指定,只要不比上级的值小就可以?
160, // number of vectors
4, // cascade vector这里在at91里PA=2,PB=3,PC-PE=4,就是说PIO口不是级连在同一个上一AIC中断号上的,如果想让PA,PB了加上,是不是需要再加在后面,但这个时候vecter base又怎么设置呢?
0, // CPU vector base
0, // CPU vector stride
0, // flags

{ 0, 0, &interrupt_id_at9263_gpio },
{ INTR_GENFLAG_LOAD_INTRMASK, 0, &interrupt_eoi_at9263_gpio },
&interrupt_mask_at9263_gpio, // mask callout
&interrupt_unmask_at9263_gpio, // unmask callout
0, // config callout
&AT91SAM9263_PIOA_BASE, 这个参数起什么作用? },
按这样的设置的话,PD4的中断号是不是就是32+100?

可是还是不能工作,现在的问题是:
o-pkt-v4 -d dm9000 ioport=0x30000000,irq=5,step=4,mac=0123456789ab -p tcpip
sloginfo里面是这样的
Jan 01 00:00:28 3 14 0 Using pseudo random generator. See “random” option
Jan 01 00:00:29 6 14 0 id = 90000a46
Jan 01 00:00:29 6 14 0 Fastether
看起来好像正常,用nicinfo也能查看到信息,但中断不对ping不通,网卡中断对应的是PD4
我的PD对应AIC中断号为4,如果改成irq=4,程序就死了。
我级连了在GPIO上的中断,加了如下的代码,及callout.s
{ 32, // vector base
160, // number of vectors
4, // cascade vector
0, // CPU vector base
0, // CPU vector stride
0, // flags

{ 0, 0, &interrupt_id_at9263_gpio },
{ INTR_GENFLAG_LOAD_INTRMASK, 0, &interrupt_eoi_at9263_gpio },
&interrupt_mask_at9263_gpio, // mask callout
&interrupt_unmask_at9263_gpio, // unmask callout
0, // config callout
&at9263_gpioa_base,
},
把中断号设成大于32后:
io-pkt-v4 -d dm9000 ioport=0x30000000,irq=35,step=4,mac=0123456789ab -p tcpip
Jan 01 00:08:19 3 14 0 Using pseudo random generator. See “random” option
Jan 01 00:08:19 6 14 0 id = 90000a46
Jan 01 00:08:20 6 14 0 Fastether
Jan 01 00:08:20 2 14 0 InterruptAttachEvent at “D:/ide-4.7-workspace/BSP-ATMEL-AT91SAM9263-EK-src/src/hardware/devn/dm9000/dm9000.c”:515: Invalid argument
Jan 01 00:08:20 2 14 0 shim: unable to init dll devn-dm9000.so: No such device
Jan 01 00:08:20 2 14 0 Unable to init devn-dm9000.so: Unknown error

我查看了一下,好像那个callout_interrupt_gio.S文件没有对应的.o文,之所以一调用大于32的中断就出错, 是不是因为对应的callout 有问题呢,是不是还没有把它加到程序里去呢,我只是把那个文件放到了startup下的与main一致的地方。