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

嵌入式板卡USART RTS引脚控制与lirc_serial内核模块移植问题

解决BayTrail平台上基于MMIO串口的红外发射内核模块移植问题

先给你梳理下核心问题的原因和可行的简便方案:

1. request_mem_region失败&ioremap数据异常的本质原因

你遇到的问题核心是资源冲突:dw-apb-uart驱动是内核内置模块,所以lsmod看不到,已经抢占了0x90a0c000这个MMIO区域。内核的资源管理机制会阻止重复申请同一硬件资源,所以request_mem_region必然失败;而直接跳过申请步骤做ioremap,会和正在运行的uart驱动产生寄存器读写冲突,导致数据输出混乱,这种操作非常危险,绝对不能继续。

2. ioremap_nocache与request_mem_region的正确调用顺序

正确的流程是:

  • 先调用request_mem_region申请目标内存区域,确认内核未将其分配给其他驱动;
  • 申请成功后,再调用ioremap_nocache完成物理地址到虚拟地址的映射;
  • 使用完毕后,先执行iounmap释放映射,再调用release_mem_region归还资源。

你之前的调用顺序完全颠倒了,再加上区域已被占用,第一步就失败了,后续操作自然无效。

3. 不卸载现有驱动,控制RTS引脚的简便方案

既然dw-apb-uart已经接管了串口,我们完全可以复用它的硬件控制接口,不需要重新操作寄存器。针对4.9内核,推荐两种实用方式:

方式一:通过tty设备接口直接控制RTS

内核提供了tty设备的标准化控制接口,可以直接设置RTS电平,步骤如下:

// 打开ttyS0设备
struct tty_struct *tty = tty_open_by_path("/dev/ttyS0", O_RDWR | O_NONBLOCK);
if (IS_ERR(tty)) {
    // 处理错误逻辑
    return PTR_ERR(tty);
}

tty_lock(tty); // 加锁避免并发冲突
// 获取对应的uart_port结构体(4.9内核中tty的driver_data指向uart_port)
struct uart_port *port = tty->driver_data;

// 设置RTS为高电平
uart_set_mctrl(port, TIOCM_RTS);
udelay(500); // 红外脉冲延时,根据协议调整时长
// 设置RTS为低电平
uart_set_mctrl(port, 0);

tty_unlock(tty);
tty_kref_put(tty); // 关闭设备

方式二:直接操作8250寄存器(基于现有uart_port)

如果你需要更底层的控制,可以直接调用8250驱动的寄存器读写函数,同样基于已有的uart_port:

// 读取Modem控制寄存器(MCR)
unsigned char mcr = port->serial_in(port, UART_MCR);
// 置位RTS(MCR的第1位)
mcr |= UART_MCR_RTS;
port->serial_out(port, UART_MCR, mcr);
udelay(500);
// 清除RTS位
mcr &= ~UART_MCR_RTS;
port->serial_out(port, UART_MCR, mcr);

这种方式和方式一本质相同,但更直接,前提是你对8250的寄存器定义有一定了解。

4. 红外发射时序实现注意事项

红外发射需要精准的电平脉冲时序,内核中可以用udelay(微秒级)或者hrtimer(更高精度)来实现:

  • 避免在中断上下文中使用长延时,优先用hrtimer调度时序;
  • 操作RTS的频率不要超过硬件支持范围,防止硬件异常。

总结

最简便的方案就是复用现有dw-apb-uart驱动的控制接口,不需要重新映射寄存器或者卸载驱动,既安全又节省开发时间。完全没必要移植serdev或者实现复杂的线路规程,直接通过tty设备接口控制RTS就能满足红外发射的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:18:19