首页 > 其他分享 >基于mdev实现adb热插拔(@STM32MP157D+fusb302)

基于mdev实现adb热插拔(@STM32MP157D+fusb302)

时间:2023-11-19 21:55:44浏览次数:38  
标签:adbd STM32MP157D 热插拔 echo -- adb mdev command usb

关键词:fusb302、uevent、mdev、adbd等等。

1 fusb302关于USB插拔检测,以及增加uevent事件

fsusb302支持USB Power Delivery协议(USB Power Delivery),支持识别各种USB设备和对应的状态。

fusb302支持DRP(Dual Role Power)、DFP(Downstream Facing Port)、UFP(Upstream Facing Port)。

参考《PD快充 - fusb302驱动调试笔记》。

fusb302通过I2C进行控制,驱动主体如下:

fusb30x_driver
    ->fusb30x_probe
        ->devm_regmap_init_i2c--注册基于i2c的regmap。
        ->fusb_initialize_gpio--fusb302所使用到的gpio初始化。
->fusb302_work_func--在中断处理函数中,调度work执行此处理函数。
      ->state_machine_typec--维护状态机,根据状态机执行操作。 ->devm_request_threaded_irq--注册中断处理函数。 ->cc_interrupt_handler--将之前创建创建的work键入workqueue进行处理。

 在fusb302进行一系列初始化后,主要靠中断驱动进行状态机切换。

当驱动执行platform_fusb_notify时,在判断plugged in后发送add uevent到用户空间;当判断plugged out后发送remove uevent到用户空间。

用户空间mdev匹配i2c设备发出的uevent后,调用start_stop_adbd脚本进行adbd任务的启动和停止。

@@ -301,6 +301,11 @@ static void platform_fusb_notify(struct fusb30x_chip *chip)
             ufp = true;
             usb_ss = true;
         }
+
+        if(plugged)
+            kobject_uevent(&chip->dev->kobj, KOBJ_ADD);
+        else
+            kobject_uevent(&chip->dev->kobj, KOBJ_REMOVE);

另外:发送uevent时间放在dwc2 otg部分处理似乎更合适。

2 mdev代码解析

之前有关于mdev的分析《Linux uevent分析、用户接收uevent以及mdev分析》,重新简单分析如下:

mdev_main
  ->getopt32-仅支持s/d/f三个选项。
  ->create_and_bind_to_netlink--读取内核的UEVENT消息。
  ->initial_scan--在mdev第一次启动时,主动遍历/sys/dev下的目录,调用fileAction/dirAction创建文件和目录。
  ->open_mdev_log--创建保存log的文件mdev.log。
  ->daemon_loop--mdev作为daemon的主要循环逻辑,循环读取kernel uevent,并进行处理。
    ->safe_read--阻塞读取kernel uevent字串。
    ->process_action--处理读取到的kernel uevent字串。
      ->keywords--仅支持add/remove两个action关键词。
      ->make_device--执行匹配,创建设备,执行命令的主要函数。

 在mdev第一次启动或后续读取到kernel uevent字串后,调用make_device创建设备、执行命令。

static void make_device(char *device_name, char *path, int operation)
{
    int major, minor, type, len;
    char *path_end = path + strlen(path);
...
#if ENABLE_FEATURE_MDEV_CONF
    G.rule_idx = 0; /* restart from the beginning (think mdev -s) */
#endif
    for (;;) {
        const char *str_to_match;
        regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
        char *command;
        char *alias;
        char aliaslink = aliaslink; /* for compiler */
        char *node_name;
        const struct rule *rule;

        str_to_match = device_name;

        rule = next_rule();--根据/etc/mdev.conf创建匹配规则。

#if ENABLE_FEATURE_MDEV_CONF--根据device_name和rule进行匹配,然后根据operation执行命令。
...
 rule_matches:
        dbg2("rule matched, line %d", G.parser ? G.parser->lineno : -1);
#endif
        /* Build alias name */
        alias = NULL;
        if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) {
            aliaslink = rule->ren_mov[0];
            if (aliaslink == '!') {--!不创建设备。
...
            }
            else if (aliaslink == '>' || aliaslink == '=') {--如果path是个目录(比如drivers/),则将设备节点移动到目录下;如果path是个名称,则将设备节点重命名为这个名称。
...
            }
        }

        command = NULL;
        IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;)--获取匹配后的命令,如果不为空则执行命令。
        if (command) {
            if ((command[0] == '@' && operation == OP_add)--仅在action为add时,执行@开始的命令。
             || (command[0] == '$' && operation == OP_remove)--仅在action为remove时,执行$开始的命令。
             || (command[0] == '*')--其他action执行*开始的命令。
            ) {
                command++;
            } else {
                command = NULL;
            }
        }
        dbg3("command:'%s'", command);

        /* "Execute" the line we found */
        node_name = device_name;
        if (ENABLE_FEATURE_MDEV_RENAME && alias) {
            node_name = alias = build_alias(alias, device_name);
            dbg3("alias2:'%s'", alias);
        }

        if (operation == OP_add && major >= 0) {--在执行命令之前创建设备。
...
        }

        if (ENABLE_FEATURE_MDEV_EXEC && command) {
            /* setenv will leak memory, use putenv/unsetenv/free */
            char *s = xasprintf("%s=%s", "MDEV", node_name);
            putenv(s);
            dbg1("running: %s", command);
            if (system(command) == -1)--匹配后执行命令。
                bb_perror_msg("can't run '%s'", command);
            bb_unsetenv_and_free(s);
        }

        if (operation == OP_remove && major >= -1) {--在执行命令之后删除文件链接。
...
        }
...
    } /* for (;;) */
}

3 mdev.conf配置

当fusb302驱动检测到USB插拔后,启动start_stop_adbd脚本进行处理,参数为$ACTION。

$DEVPATH=/devices/platform/soc/40012000.i2c/i2c-0/0-0022 root:root 666 */usr/bin/start_stop_adbd $ACTION

4 start_stop_adbd 脚本

start_stop_adbd对add执行do_start,对remove执行do_stop。

#!/bin/sh

gadget=gadget
DAEMON="adbd"
PIDFILE="/var/run/$DAEMON.pid"
ADBD_ARGS=""

do_start(){
    # 挂载configs文件系统。
    #has_mount=$(mount -l | grep /sys/kernel/config)
    #if [[ -z  $has_mount ]];then
    #    mount -t configfs none /sys/kernel/config
    #fi
    cd /sys/kernel/config/usb_gadget

    # 进入usb_gadget,创建gadget目录后系统自动创建usb gadget相关的内容。
    if [[ ! -d ${gadget} ]]; then
        mkdir ${gadget}
    fi
    cd ${gadget}

    # 设置EP0 Packet最大值。
    echo "64" > bMaxPacketSize0
    # 设置USB协议版本USB2.0,Device版本号为0x0100。
    echo 0x0200 > bcdUSB
    echo 0x0100 > bcdDevice

    # 定义产品的VendorID和ProductID。
    echo "0x09D9"  > idVendor
    echo "0x0502" > idProduct

    # 0x409对应en-us,表示后续string类型的语言。
    if [[ ! -d strings/0x409 ]]; then
        mkdir strings/0x409
    fi

    # 将开发商、产品和序列号字符串写入内核。
    echo "76543210" > strings/0x409/serialnumber
    echo "STM"  > strings/0x409/manufacturer
    echo "STM32MP157"  > strings/0x409/product

    # 创建一个USB配置实例。
    if [[ ! -d configs/config.1 ]]; then
        mkdir configs/config.1
    fi

    # 设备从总线获取的最大电流mA。
    echo 120 > configs/config.1/MaxPower

    # 定义配置描述符使用的字符串。
    if [[ ! -d configs/config.1/strings/0x409 ]]; then
        mkdir configs/config.1/strings/0x409
    fi

    echo "STMCfg" > configs/config.1/strings/0x409/configuration

    # 按照FUNC.INSTANCE格式创建功能实例。需要注意的是,一个功能如果有多个实例的话,扩展名必须用数字编号。
    if [[ ! -d functions/ffs.adb ]]; then
        mkdir functions/ffs.adb
    fi

    # 分配一个usb_function并加入到func_list中。后续绑定驱动到UDC时需要。
        if [[ ! -d configs/config.1/ffs.adb ]]; then
        ln -s functions/ffs.adb configs/config.1
    fi

    if [[ ! -d /dev/usb-ffs ]]; then
        mkdir /dev/usb-ffs
    fi
    if [[ ! -d /dev/usb-ffs/adb ]]; then
        mkdir /dev/usb-ffs/adb
    fi

    # 挂载adb设备functionfs文件系统到/dev/usb-ffs/adb,出现ep0/1/2,给adbd使用。
        if [[ ! -f /dev/usb-ffs/adb/ep0 ]]; then
        mount -t functionfs adb /dev/usb-ffs/adb
        else
            echo "Please use stop or restart."
                exit 0
    fi

    #adbd &
    start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/usr/bin/$DAEMON" -- -n $ADBD_ARGS
        status=$?
    if [ $status -eq 0 ]; then
        echo "Start adbd: OK"
    else
        echo "Start adbd: FAIL"
    fi
    sleep 0.3s

    # 将gadget驱动注册到UDC上,插上USB线到电脑上,电脑就会枚举USB设备。
    udc_name=$(ls /sys/class/udc)
    #echo UDC:$udc_name
    echo "$udc_name" > UDC
}

do_stop() {
    if [[ -d /sys/kernel/config/usb_gadget/${gadget}/UDC ]]; then
        echo "" > /sys/kernel/config/usb_gadget/${gadget}/UDC
    fi
    #killall adbd
        start-stop-daemon -K -q -p "$PIDFILE"
        status=$?
    if [ $status -eq 0 ]; then
        rm -rf "$PIDFILE"
        echo "Stop adbd: OK"
    else
        echo "Stop adbd: FAIL"
    fi
    if [[ -f /dev/usb-ffs/adb/ep0 ]]; then
        umount /dev/usb-ffs/adb
    fi
}

case $1 in
    start|add)
        do_start
        ;;
    stop|remove)
        do_stop
        ;;
    restart)
        do_stop
        do_start
        ;;
    *)
        echo "Usage: $0 (stop | start | restart)"
        ;;
esac

adbd更多参考《嵌入式Linux adbd实现概要梳理(基于STM32MP157D+Buildroot)》。

标签:adbd,STM32MP157D,热插拔,echo,--,adb,mdev,command,usb
From: https://www.cnblogs.com/arnoldlu/p/17839306.html

相关文章

  • 解决docker容器重启后adb连接手机重新授权问题
    安卓adb认证文件在~/.android目录下,在容器启动时将此目录作为数据卷持久化可以解决docker镜像重新编译后,需要在手机端重新点击授权的问题dockerrun-it-v/root/xxx/.android:/root/.androiddocker_image_name/bin/bash参数-v冒号前是宿主机目录,冒号后是容器目录。经测验......
  • 嵌入式Linux adbd实现概要梳理(基于STM32MP157D+Buildroot)
    关键词:USBGadget、dwc2、configfs、functionfs、adbd等等。基于STM32MP157D简单记录ADB实现的过程,涉及到USB、Gadget、configfs、functionfs、adbd、ADB协议等等。基于Buildroot2020.02.6编译adbd运行于设备,和PCWindows交互的简要框图:1Linux下USBGadget1.1Linux内核Gad......
  • Windows下如何快速移动MySQL/MariaDB数据库文件
    近期遇到一个要迁移数据库的问题,用户说不希望数据库文件存在于C盘。查了一下资料,这里做个总结。这个方法适用于MySQL和MariaDB。 步骤如下:1、停止数据库服务2、将数据库移动到需要迁移的路径3、修改安装路径data目录下的my.ini文件4、将 datadir=xxx改成需要迁移的路径5......
  • Windows环境下ADB调试——无线连接设备Wifi adb
    一、有线连接第一次连接设备,需要先用有线连接一次。然后运行查看设备:adbdevices如图,第一次没有连接设备,第二次连接了。(安卓设备需要已经开启开发者模式)二、设置tcp端口运行代码:adbtcpip5555 三、无线连接打开安卓设备,查看IP地址。运行代码:adbconnect10.2......
  • 单板热插拔方案
    单板热插拔芯片TITPS24711,最大到18V.防护原理检测Rsense两端电压小于25mv。 国产圣邦微SGM25711B同封装pinpin兼容的替代器件,检测原理相同。  其他国产型号杰华特JW7222其他国产型号长芯微新品LCM24711 ......
  • Android如何远程ADB连接以及相关适配
    https://juejin.cn/post/7198041490626576442 前言  ADB全称为AndroidDebugBridge,译为安卓调试桥。是一个命令行工具,主要用于调试设备。详细大家对这个是耳熟能详了。关于ADB的安装、使用、命令等都不是本文的重点,大家有兴趣可先去网上搜索学习一番。那么回归到本文的......
  • 脚本强制预置apk | adb install 方式
     使用场景:Android系统预置apk无法打开简单总结:脚本预置进android设备指定目录,预置方式还是通过device.mk;目标apk存放至代码随意目录下;执行脚本(此部分由init.r获取对脚本的读写权限)目标apk存放  以上Android.mk中的mkdir指令,作用是为了编译系统能够找到源代......
  • adb常用命令(持续更新)
    一、概述最近想研究scrcpy投屏神器的构建过程,里面涉及了不少的知识点,如:meson、ninja、phthon3脚本、shell脚本、gradle脚本(groovy)、adb常用命令等等而这篇就先回顾一下adb的常用命令二、常用命令介绍1.配置adb环境变量其实就是配置一下androidsdk的......
  • MariaDB(MySQL)的常用命令3 【使用通配符过滤】
    第8章使用通配符过滤LIKE操作符百分号(%)通配符(匹配多个字符,类似?)SELECT*FROMstudentsWHEREemailLIKE'%@163.com';-下划线(_)通配符(匹配单个字符,类似*)SELECT*FROMstudentsWHEREnameLIKE'张_';Tips:1.查找的字符串,可能是大小......
  • mysql/mariadb上建立新用户并设置远程连接
    mysql/mariadb上建立新用户并设置远程连接 没有做之前总觉得很麻烦,真的做下去了一边上网搜索一边做结果还是很简单的。。想来在LINUX下也是一样吧,最主要的就是之前的安装软件。。。2023年11月03日测试 ,用的mariadb11.1.2,服务器上安装好后命令行下连接 mysql-uroot......