在ARM FIQ中断上,我们保留了一些仅供FIQ使用的寄存器,这些寄存器是“保存状态”的便捷方法,例如FIQ调用之间的数据传输。

目前,我正在从FIQ触发一些GPIO引脚,并且它按预期工作。设置FIQ处理程序时,我将指针传递给数据寄存器,这些数据寄存器已使用ioremap映射。工作代码如下所示:

//Driver initialization:
static char* dout0;
static char* din0;
...
static int driver_probe(struct platform_device *pdev)
{
struct pt_regs regs;
...
dout0 = ioremap(HW_PINCTRL_DOUT0, 0xffff);
din0  = ioremap(HW_PINCTRL_DIN0, 0xffff);
...
regs.ARM_r8 = (long) dout0;
regs.ARM_r9 = (long) din0;
set_fiq_regs(&regs);
...

//In the FIQ handler:
LDR r12, [r8]
ORR r12, r12, #0x20 /* set pin 5 high in dout0 register */
STR r12, [r8]

上面的代码按预期执行,在执行FIQ处理程序后将pin 5设置为高。

对于更复杂的操作,我想准备一个结构,该结构将保存数据指针和其他处理相关数据,包括更多到不同寄存器的映射-并将其传递给FIQ处理程序。但是,在将以上代码迁移到此时,那里已经出了问题。

我修改了上面的代码,看起来像这样
//In Driver:
struct fiq_processing {
    char* din0;
    char* dout0;
};

static fiq_processing * pdata; //Pointer to our processing data structure

...
static int driver_probe(struct platform_device *pdev)
{
struct pt_regs regs;
pdata = kmalloc(sizeof(*pdata), GFP_KERNEL); //Allocate memory for struct
printk("Size of the data struct %d \n", sizeof(*pdata)); //I get "8" as the size
...
pdata->din0  = ioremap(HW_PINCTRL_DIN0, 0xffff);
pdata->dout0 = ioremap(HW_PINCTRL_DOUT0, 0xffff);
...
regs.ARM_r8 = (long) pdata;
set_fiq_regs(&regs);
...

//In the FIQ handler:
#define OFFSET_DIN0 0x0
#define OFFSET_DOUT0 0x4 //We know size is 8, so offset for dout is half from that
...
LDR r12, [r8, #OFFSET_DOUT0]
ORR r12, r12, #0x20 /* set pin 5 high in dout0 register */
STR r12, [r8, #OFFSET_DOUT0] /* This will do nothing ? */

在为结构分配了内存并映射了寄存器指针之后,我将pdata结构的地址传递给FIQ处理程序。
在FIQ处理程序中,我有din0dout0的偏移量,我认为它们分别是0x00x4(从8的结构大小中减去)。

但是由于某种原因,现在我的FIQ无法再将输出引脚设置为高电平-我无法弄清楚我在这里做错了什么。
我在这里计算偏移量错误吗?或者调用STR r12, [r8, #OFFSET_DOUT0]不正确吗?
实际的FIQ更长一些(它读取输入状态,并从输入状态创建一些条件),但是即使现在基本位设置也似乎失败了。

最佳答案

情况1

regs.ARM_r8 = (long) dout0;
set_fiq_regs(&regs);

...
//In the FIQ handler:
LDR r12, [r8]
ORR r12, r12, #0x20 /* set pin 5 high in dout0 register */
STR r12, [r8]

此处r8中的值是内存映射的I/O寄存器的地址。取消引用它会从正确的位置读取。

情况二
struct fiq_processing {
    char* din0;
    char* dout0;
};
static fiq_processing * pdata; //Pointer to our processing data structure
pdata->din0  = ioremap(HW_PINCTRL_DIN0, 0xffff);
pdata->dout0 = ioremap(HW_PINCTRL_DOUT0, 0xffff);
...
//In the FIQ handler:
LDR r12, [r8, #OFFSET_DOUT0]
ORR r12, r12, #0x20 /* set pin 5 high in dout0 register */
STR r12, [r8, #OFFSET_DOUT0] /* This will do nothing ? */

在这种情况下,您已经获取了GPIO Controller 的地址,并且正在对该地址进行ORR编码!您需要再次取消引用。
LDR r11, [r8, #OFFSET_DOUT0]  # Get address of controller
LDR R12, [R11]                # Get current I/O value.
ORR r12, r12, #0x20           # Set pin 5 high in dout0 register */
STR r12, [r11]                # Write it out.

关于linux-kernel - 从FIQ中断处理程序访问内核驱动程序数据失败,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18690715/

10-11 15:34