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 操作步骤
- 编译模块:
make - 加载模块:
insmod usb_slave_notify.ko - 查看加载日志:
dmesg | grep "USB slave connect notify" - 运行用户态监听程序:编译后直接执行即可
6. 常见问题排查
- 中断注册失败:检查
IRQF_SHARED标志是否正确,或原有USB驱动是否禁止共享中断。 - 状态检测失效:核对手册中的寄存器偏移和状态位定义,必要时通过
devmem工具直接读取寄存器验证。 - 用户态无通知:检查sysfs节点是否存在(
ls /sys/kernel/usb_slave_notify),或poll事件是否设置正确。
内容的提问来源于stack exchange,提问作者Ajita
相关产品推荐
相关产品推荐

