驱动代码添加判断TF卡speed_class上报事件

点击“硬核王同学”,选择“关注/点赞” 

福利干货第一时间送达

大家好,我是硬核王同学。

前提条件:成功添加TF卡额外信息speed_class并打印 (可阅读这篇:内核如何添加读取SD卡额外信息(以ssr/speed-class为例)?

当我们想要上报某一个事件,可以说使用延迟工作队列—— delayed_work进行上报

在 Linux 内核中,delayed_work 是一种用于延迟执行的工作队列机制。工作队列是一种异步执行任务的机制,允许将任务添加到队列中,等待处理器的空闲时刻来执行。 delayed_work 是基于工作队列的一种实现,它允许在特定的延迟时间后执行工作任务。当一个延迟工作被添加到队列中时,内核会在指定的延迟时间后将该工作排队等待执行。 delayed_work 在 Linux 内核中使用非常广泛,特别是在需要延迟执行的场景中。它可以用于各种用途,如定时任务、定时器、延迟回调函数等。通过使用 delayed_work,开发人员可以轻松地实现延迟执行的功能,并在必要时进行动态调度和管理。

1.首先在 /include/linux/mmc/host.h的mmc_host 中添加一个延迟工作队列成员notify_sc:

  1. 1. /include/linux/mmc/host.h 这个头文件提供了MMC主机操作的接口和数据结构的定义,驱动程序可以根据需要实现这些回调函数来完成对MMC主机的控制和操作。

  2. 2.struct mmc_host 是描述MMC(MultiMediaCard)主机的数据结构,通过struct mmc_host,驱动程序可以访问和操作MMC主机的各种属性和状态,与MMC卡进行通信和控制。

/include/linux/mmc/host.h

@@ -399,6 +399,7 @@ struct mmc_host {
 #endif
 
        struct delayed_work     notify_err;
+       struct delayed_work     notify_sc;
 
        unsigned long           private[0] ____cacheline_aligned;
 };


2.在drivers/mmc/core/host.c添加我们要使用的延迟工作队列和对应的函数mmc_notify_sc_work:

1. drivers/mmc/core/host.c 提供了MMC子系统中MMC主机控制器的核心功能和操作的实现。它是实现MMC主机控制器驱动的重要代码文件。2. INIT_DELAYED_WORK(&host->notify_sc, mmc_notify_sc_work) 是一个用于初始化一个延迟工作(Delayed Work)的宏。

在MMC(MultiMediaCard)子系统中,当插入或拔出MMC卡时,需要通知系统进行相应的处理。为了以异步的方式在系统空闲时执行这些卡状态变化的处理任务,可以使用延迟工作。3. void mmc_notify_sc_work(struct work_struct *work) 是一个用于处理MMC(MultiMediaCard)子系统中卡状态改变通知的工作函数。作为INIT_DELAYED_WORK宏中的一个参数被调用。

  • /drivers/mmc/core/host.c
    
    @@ -310,6 +310,7 @@ int mmc_of_parse(struct mmc_host *host)
     EXPORT_SYMBOL(mmc_of_parse);
     
     void mmc_notify_err_work(struct work_struct *work);
    +void mmc_notify_sc_work(struct work_struct *work);
     
    
    @@ -357,6 +358,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
            init_waitqueue_head(&host->wq);
            INIT_DELAYED_WORK(&host->detect, mmc_rescan);
            INIT_DELAYED_WORK(&host->notify_err, mmc_notify_err_work);
    +       INIT_DELAYED_WORK(&host->notify_sc, mmc_notify_sc_work);
     #ifdef CONFIG_PM
            host->pm_notify.notifier_call = mmc_pm_notify;
     #endif

3.在/drivers/mmc/core/sd.c添加mmc_notify_sc_work函数实现:

1. mmc_notify_sc_err是一个静态函数,用于发送一个内核事件来通知出现了 SC 错误。

2. mmc_notify_sc_work是一个工作队列的回调函数,用于处理错误通知的工作。

  • /drivers/mmc/core/sd.c
    
    @@ -1262,6 +1262,51 @@ static const struct mmc_bus_ops mmc_sd_ops = {
     };
    +static void mmc_notify_sc_err(struct mmc_host *host)
    +{
    +       unsigned int sc;
    +       char *envp[3];
    +
    +       sc = UNSTUFF_BITS(host->card->raw_ssr, 440 - 384, 8);
    +
    +       envp[0] = "SD_INIT=class_err";
    +
    +       switch (sc) {
    +                case 1:
    +                       envp[1] = "SD_CLASS=1";
    +            break;
    +        case 2:
    +                       envp[1] = "SD_CLASS=2";
    +            break;
    +        case 3:
    +                       envp[1] = "SD_CLASS=3";
    +            break;
    +               case 4:
    +                       envp[1] = "SD_CLASS=4";
    +            break;
    +        default:
    +                       envp[1] = "SD_CLASS=err";
    +       }
    +
    +       envp[2] = NULL;
    +
    +       kobject_uevent_env(&host->parent->kobj, KOBJ_CHANGE, envp);
    +       printk("mmc notify sc error\n");
    +       return ;
    +}
    +
    +void mmc_notify_sc_work(struct work_struct *work)
    +{
    +
    +       struct delayed_work *delayed = container_of(work, struct delayed_work, work);
    +       struct mmc_host *host = container_of(delayed, struct mmc_host, notify_sc);
    +
    +       if (host) {
    +               mmc_notify_sc_err(host);
    +       }       
    +       return ;
    +}
    +
    
    @@ -1361,6 +1405,9 @@ int mmc_attach_sd(struct mmc_host *host)
                    goto remove_card;
     
            mmc_claim_host(host);
    +
    +       schedule_delayed_work(&host->notify_sc, err_delay * HZ);
    +
            return 0;
     
     remove_card:

最终通过kobject_uevent_env函数上报事件~

4.查看kobject_uevent_env函数上报事件内容

这里我们在应用层运行个小程序检测uevent时间上报就可以啦

可以用这个Android.mk编译生成所使用的小应用

PlugIn2.cpp是我们的主程序,放在安卓项目中的XXX(安卓项目名称)/vendor/XXX/apps/testPlugIn下

Android.mk:

# Copyright 2006 The Android Open Source Project

LOCAL_PATH:= $(call my-dir)
export ADAPTER_INC_DIR := vendor/sprd/modules/sl_client/include
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional 

LOCAL_SRC_FILES:= \
       PlugIn2.cpp \

LOCAL_C_INCLUDES += $(ADAPTER_INC_DIR) \

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \

ifeq ($(PLATFORM_VERSION),$(filter $(PLATFORM_VERSION),4.4 4.4.1 4.4.2 4.4.3 4.4.4))
include external/stlport/libstlport.mk
endif

LOCAL_MODULE:= PlugIn2

include $(BUILD_EXECUTABLE)

PlugIn2.cpp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/netlink.h>
#include <sys/prctl.h>

#define UEVENT_BUFFER_SIZE 2048
static const char *sd_dev = "/devices/platform/soc/soc:ap-ahb/20300000.sdio/mmc_host/mmc0/mmc0";
static const char *sd_bus = "/devices/platform/soc/soc:ap-ahb/20300000.sdio";

typedef struct {
    const char *action;
    const char *path;
    const char *subsystem;
    const char *firmware;
    int major;
    int minor;
    const char *init;
    const char *sc;
} plugin_event;

static void parse_event(const char *msg, plugin_event * pevent)
{
    pevent->action = "";
    pevent->path = "";
    pevent->subsystem = "";
    pevent->firmware = "";
    pevent->major = -1;
    pevent->minor = -1;
    pevent->init = "";
    pevent->sc = "";
    
    while (*msg) 
    {
        if (!strncmp(msg, "ACTION=", 7)) {
            msg += 7;
            pevent->action = msg;
        } else if (!strncmp(msg, "DEVPATH=", 8)) {
            msg += 8;
            pevent->path = msg;
        } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
            msg += 10;
            pevent->subsystem = msg;
        } else if (!strncmp(msg, "FIRMWARE=", 9)) {
            msg += 9;
            pevent->firmware = msg;
        } else if (!strncmp(msg, "MAJOR=", 6)) {
            msg += 6;
            pevent->major = atoi(msg);
        } else if (!strncmp(msg, "MINOR=", 6)) {
            msg += 6;
            pevent->minor = atoi(msg);
        } else if (!strncmp(msg, "SD_INIT=", 8)) {
            msg += 8;
            pevent->init = msg;
        } else if (!strncmp(msg, "SD_CLASS=", 9)) {
            msg += 9;
            pevent->sc = msg;
        }
        while(*msg++);
    }
}

void* PlugInProc(void* argv)
{
    int mSock = (int)argv;
    int len;
    char buf[UEVENT_BUFFER_SIZE * 2] = {0};

    while(1)
    {
        len = recv(mSock, &buf, sizeof(buf), 0);
        if(len == sizeof(buf))
            continue;
        buf[len] = '\0';
        buf[len+1] = '\0';

        plugin_event event;
        parse_event(buf, &event);
        printf("plugin:%s %s %s\n",event.subsystem,event.action,event.sc);

    }
    close(mSock);
    return 0;
}

static int NetLinkOpen()
{
    struct sockaddr_nl nladdr;
    int sz = 64 * 1024;
    int mSock;

    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid();
    nladdr.nl_groups = 0xffffffff;

    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0)
    {
        printf("Unable to create uevent socket: %s", strerror(errno));
        return -1;
    }

    if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0)
    {
        printf("Unable to set uevent socket options: %s", strerror(errno));
        return -1;
    }

    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
    {
        printf("Unable to bind uevent socket: %s", strerror(errno));
        return -1;
    }
    return mSock;
}

int main()
{
    int s = NetLinkOpen();
    if(s < 0)
        return -1;

    PlugInProc((void*)s);
    printf("success!\n");

    return 0;
}

输入命令:mm  进行编译

编译成功后可以看到在out的某个目录下

adb连接好设备,通过adb push 将程序转移到设备中

运行程序,插入sd卡,可以查看到TF卡speed_class上报事件!

------  END  ------

如果觉得有用请点个免费的赞

      您的支持就是我最大的动力,这对我很重要!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

硬核王同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值