美文网首页
我该如何抛弃对 rmmod ftdi_sio 的使用

我该如何抛弃对 rmmod ftdi_sio 的使用

作者: Mum_Chen | 来源:发表于2018-11-22 13:19 被阅读0次

    使用场景描述 (是什么)

    这篇记录主要针对如何在linux下更加简单的使用ftdi2xx的动态链接库.
    在近期的工作中我需要频繁地使用FTDI的设备(ftdi232)进行SPI的读写操作. 每次在调用自己的程序之前都需要按照官方的建议执行以下操作:

    lsmod | grep ftdi
    rmmod ftdi_sio
    

    在调试过程中拔插设备的操作十分常见, 以至于每天都要输入上述的命令无数次. 为了完成我当一个咸鱼的梦想, 我在今天花费了一些时间研究了一下, 如何从这段烦人的命令中寻获解脱.

    既然拥有一个实现咸鱼化的伟大梦想, 我对解决方案有着以下要求:

    • 摆脱对rmmod的使用
    • 摆脱对sudo命令的使用
    • 我希望能在使用FTDI232芯片的同时, 不影响到其他设备的使用

    需要着重说明, 最后一点是过往使用中的另一个痛点: 其实使用ftdi芯片的设备不在少数. 在我的工作环境中还有另外两种设备会使用到ftdi的芯片: 一个是xilinx artix 7 FPGA, 另一个是一条做工优秀和外面那些地摊货不一样的蓝色串口线.

    每次需要同时使用ftdi232和其中一个设备时, rmmod ftdi_sio这条命令就十分的令人感到绝望. 系统中所有依赖于ftdi_sio驱动的其他驱动, 都会因为依赖不满足也无法工作.

    解决方案 (怎么办)

    话不多说, 其实已经说了很多, 亮方案.

    新建一个叫85-unbind-ftdi.rules的文件. 这里我想补上一句, udev的规则不能分行真的很治愈强迫症:)

    ACTION=="add", ATTRS{idVendor}=="0403", MODE:="666"
    ACTION=="add", ATTRS{idVendor}=="0403", ATTR{interface}=="Single RS232-HS", RUN+="/bin/sh -c '/bin/echo $kernel > /sys/bus/usb/drivers/ftdi_sio/unbind'"
    

    然后将文件按照需求放入目录/run/udev/rules.d或者/etc/udev/rules.d中. 为此我写了一个简陋的Makefile.

    unbind_ftdi:
        mkdir -p /run/udev/rules.d
        cp 85-unbind-ftdi.rules /run/udev/rules.d/
    
    unbind_ftdi_persisted:
        mkdir -p /etc/udev/rules.d
        cp 85-unbind-ftdi.rules /etc/udev/rules.d/
    

    注: 上述文件运行于在ubuntu 18.04

    所用知识点的汇总 (为什么)

    接下来的内容是以备未来魔改之需而记录的知识点.┗|`O′|┛ 嗷~~

    rules 文件解析

    上面的文件85-unbind-ftdi.rules中的内容是一组udev的规则. 在设备发生某些行为的时候, 会根据相应的规则进行相应的匹配, 然后执行某些命令.

    • 上述规则主要生效于新增设备时.
    • 第一条规则是赋予文件666的权限, 让我免于遭受sudo的折磨.
    • 第二条规则是只筛选出我特别针对的设备, 然后执行unbind, 让我在梦幻中解决烦恼.

    文件名的前缀85-表示规则的序列, 越大的序列越靠后执行, 99那岂不是更美滋滋, 但是我就不.

    makefile 文件解析

    udev的这套系统中, 相关文件可以存放在 /lib/udev, /etc/udev/run/udev 目录下.lib目录下存放的是操作系统所需要的规则; etc目录下存放的是后期加入的规则; run目录下存放的是runtime的规则. 所以如果想要持久化, 那就把写好的文件放到etc目录下, 如果只想要本次开机使用, 那就放到run目录下.

    unbind命令

    对于之前ftdi官方推荐的rmmod ftdi_sio, 我只能说这种做法十分的暴力, 其实使用unbind就足够了.
    通过lsusb -t找到设备对应的节点, 然后执行echo ${dev_path} > /sys/bus/usb/drivers/ftdi_sio/unbind.
    对应usb设备可以在/sys/bus/usb/devices目录下找到.

    $ lsusb  -t
        # snip ...
    /:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 480M
        |__ Port 1: Dev 10, If 0, Class=Vendor Specific Class, Driver=ftdi_sio, 480M
        # snip ...
    $ sudo sh -c "echo 3-1:1.0 > /sys/bus/usb/drivers/ftdi_sio/unbind"
    $ lsusb  -t
        # snip ...
    /:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 480M
        |__ Port 1: Dev 10, If 0, Class=Vendor Specific Class, Driver=, 480M
        # snip ...
    

    udev 及 udev rule

    我看了一圈, 关于udev rule最直观的教程就在本地. 可以通过man udev查看udev的介绍和规则的具体内容. 然后可以进入/lib/udev/rules.d目录下, 查阅系统自带的规则, 学习一下先进的科学与技术. 还有就是这个链接也十分的不错, 有介绍 udevadm 的使用.

    上面的规则是怎么攒出来的

    通过 udevadm info -a ${usb_sysfs_path} 查看每个设备的所有属性. 下面是我所使用设备s的部分属性.

    1. ftdi232
      looking at device '/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0':
        KERNEL=="3-1:1.0"
        SUBSYSTEM=="usb"
        DRIVER=="ftdi_sio"
        ATTR{authorized}=="1"
        ATTR{bAlternateSetting}==" 0"
        ATTR{bInterfaceClass}=="ff"
        ATTR{bInterfaceNumber}=="00"
        ATTR{bInterfaceProtocol}=="ff"
        ATTR{bInterfaceSubClass}=="ff"
        ATTR{bNumEndpoints}=="02"
        ATTR{interface}=="Single RS232-HS"
        ATTR{supports_autosuspend}=="1"
        # snip
        # ...
    
    1. xilinx FPGA
      looking at device '/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0':
        KERNEL=="3-1:1.0"
        SUBSYSTEM=="usb"
        DRIVER=="ftdi_sio"
        ATTR{authorized}=="1"
        ATTR{bAlternateSetting}==" 0"
        ATTR{bInterfaceClass}=="ff"
        ATTR{bInterfaceNumber}=="00"
        ATTR{bInterfaceProtocol}=="ff"
        ATTR{bInterfaceSubClass}=="ff"
        ATTR{bNumEndpoints}=="02"
        ATTR{interface}=="Digilent USB Device"
        ATTR{supports_autosuspend}=="1"
        # snip
        # ...
    
    1. UART
      looking at device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2.4/1-1.2.4:1.0':
        KERNEL=="1-1.2.4:1.0"
        SUBSYSTEM=="usb"
        DRIVER=="ftdi_sio"
        ATTR{authorized}=="1"
        ATTR{bAlternateSetting}==" 0"
        ATTR{bInterfaceClass}=="ff"
        ATTR{bInterfaceNumber}=="00"
        ATTR{bInterfaceProtocol}=="ff"
        ATTR{bInterfaceSubClass}=="ff"
        ATTR{bNumEndpoints}=="02"
        ATTR{interface}=="FT232R USB UART"
        ATTR{supports_autosuspend}=="1"
        # snip
        # ...
    

    经过多方筛选, 最终ATTR{interface}获得桂冠作为筛选目标设备的属性. 在实际工作中, 任何可用于筛选的条件只要能满足需求都具备可行性.

    其中规则内的$kernel变量即为属性KERNEL. 可以观察到, 在目前的情况下, 此属性恰好可以作为unbind的参数直接进行使用.

    如何调试udev

    在ubuntu 18.04 上, 直接添加规则就能实时生效, 不需要特别执行udevadm control --reload.
    可以使用 udevadm test ${usb_sysfs_path} 偷偷地观察代码有没有被运行.

    一些更新

    • bug: 在ubuntu 18.04环境下, udev的规则在(apt update)之后才能生效.

    相关文章

      网友评论

          本文标题:我该如何抛弃对 rmmod ftdi_sio 的使用

          本文链接:https://www.haomeiwen.com/subject/kgnhqqtx.html