You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IMX8MM平台USB slave检测中断自定义并行ISR实现求助

实现IMX8MM USB Slave连接中断的并行ISR及用户态通知

1. 明确中断核心信息

从/proc/interrupts给出的58: 0 0 0 0 GICv3 72 Level 32e40000.usb可以确定:

  • Linux内核中断编号:58
  • 硬件中断号:72
  • 触发类型:Level(电平触发)
  • 对应设备基地址:32e40000.usb(IMX8MM的USB OTG控制器)

2. 并行ISR实现思路

Linux内核支持为同一中断注册多个共享ISR,只要每个ISR通过返回值区分是否处理当前中断:返回IRQ_NONE表示不处理,返回IRQ_HANDLED表示处理完成。我们可以注册额外ISR监听USB slave连接事件,不干扰原有驱动的正常工作。

3. 具体代码实现

3.1 内核模块代码(实现共享ISR+用户态通知)

#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/bitops.h>

#define USB_OTG_BASE 0x32e40000
#define USB_OTG_GSTS_OFFSET 0x14  // 需参考IMX8MM手册确认实际偏移
#define USB_CONNECT_BIT BIT(0)     // 需参考手册确认连接状态对应位

static int usb_slave_irq = 58;
static atomic_t usb_connected = ATOMIC_INIT(0);
static struct kobject *usb_notify_kobj;

static irqreturn_t usb_slave_connect_isr(int irq, void *dev_id) {
    void __iomem *usb_base = ioremap(USB_OTG_BASE, 0x1000);
    if (!usb_base) {
        return IRQ_NONE;
    }

    u32 status = readl(usb_base + USB_OTG_GSTS_OFFSET);
    iounmap(usb_base);

    // 判断是否为连接/断开事件
    if (status & USB_CONNECT_BIT) {
        if (atomic_read(&usb_connected) != 1) {
            atomic_set(&usb_connected, 1);
            sysfs_notify(&usb_notify_kobj->kobj, NULL, "usb_connected");
        }
        return IRQ_HANDLED;
    } else {
        if (atomic_read(&usb_connected) != 0) {
            atomic_set(&usb_connected, 0);
            sysfs_notify(&usb_notify_kobj->kobj, NULL, "usb_connected");
        }
        return IRQ_NONE;
    }
}

static ssize_t usb_connected_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) {
    return sprintf(buf, "%d\n", atomic_read(&usb_connected));
}

static struct kobj_attribute usb_connected_attr = __ATTR_RO(usb_connected);

static int __init usb_slave_notify_init(void) {
    int ret;

    // 注册共享中断
    ret = request_irq(usb_slave_irq, usb_slave_connect_isr, IRQF_SHARED, 
                     "usb_slave_connect_notify", &usb_connected);
    if (ret) {
        pr_err("Failed to request IRQ %d: %d\n", usb_slave_irq, ret);
        return ret;
    }

    // 创建sysfs节点用于用户态通知
    usb_notify_kobj = kobject_create_and_add("usb_slave_notify", kernel_kobj);
    if (!usb_notify_kobj) {
        free_irq(usb_slave_irq, &usb_connected);
        pr_err("Failed to create kobject\n");
        return -ENOMEM;
    }

    ret = sysfs_create_file(usb_notify_kobj, &usb_connected_attr.attr);
    if (ret) {
        kobject_put(usb_notify_kobj);
        free_irq(usb_slave_irq, &usb_connected);
        pr_err("Failed to create sysfs file\n");
        return ret;
    }

    pr_info("USB slave connect notify module loaded\n");
    return 0;
}

static void __exit usb_slave_notify_exit(void) {
    sysfs_remove_file(usb_notify_kobj, &usb_connected_attr.attr);
    kobject_put(usb_notify_kobj);
    free_irq(usb_slave_irq, &usb_connected);
    pr_info("USB slave connect notify module unloaded\n");
}

module_init(usb_slave_notify_init);
module_exit(usb_slave_notify_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IMX8MM USB Slave Connect Notify Module");

3.2 关键注意事项

  • 寄存器信息核对:代码中USB_OTG_GSTS_OFFSET和USB_CONNECT_BIT需严格参考IMX8MM官方手册(IMX8MMRM)确认,避免因寄存器偏移或位定义错误导致检测失效。
  • 共享中断规范:非目标事件必须返回IRQ_NONE,确保原有USB驱动的ISR能正常处理其他中断事件。
  • 基地址验证:可通过/sys/bus/platform/devices/32e40000.usb/resource确认USB控制器的实际基地址是否与代码中USB_OTG_BASE一致。

4. 用户态监听代码示例

通过poll机制监听sysfs节点的状态变化,实现实时通知:

#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <errno.h>

int main() {
    int fd = open("/sys/kernel/usb_slave_notify/usb_connected", O_RDONLY);
    if (fd < 0) {
        perror("Failed to open sysfs file");
        return -1;
    }

    struct pollfd pfd = {
        .fd = fd,
        .events = POLLPRI | POLLERR
    };

    char buf[10];
    while (1) {
        int ret = poll(&pfd, 1, -1);
        if (ret < 0) {
            if (errno == EINTR) continue;
            perror("poll failed");
            close(fd);
            return -1;
        }

        if (pfd.revents & POLLPRI) {
            lseek(fd, 0, SEEK_SET);
            ssize_t read_len = read(fd, buf, sizeof(buf)-1);
            if (read_len > 0) {
                buf[read_len] = '\0';
                printf("USB connection status: %s", buf);
            }
        }
    }

    close(fd);
    return 0;
}

5. 编译与加载

5.1 内核模块编译Makefile

obj-m += usb_slave_notify.o
KERNELDIR := /path/to/imx8mm/linux/kernel  # 替换为你的IMX8MM内核源码路径
PWD := $(shell pwd)
default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) clean

5.2 操作步骤

  1. 编译模块:make
  2. 加载模块:insmod usb_slave_notify.ko
  3. 查看加载日志:dmesg | grep "USB slave connect notify"
  4. 运行用户态监听程序:编译后直接执行即可

6. 常见问题排查

  • 中断注册失败:检查IRQF_SHARED标志是否正确,或原有USB驱动是否禁止共享中断。
  • 状态检测失效:核对手册中的寄存器偏移和状态位定义,必要时通过devmem工具直接读取寄存器验证。
  • 用户态无通知:检查sysfs节点是否存在(ls /sys/kernel/usb_slave_notify),或poll事件是否设置正确。

内容的提问来源于stack exchange,提问作者Ajita

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 02:20:57