点击“硬核王同学”,选择“关注/点赞”
福利干货第一时间送达
大家好,我是硬核王同学。
前提条件:成功添加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. /include/linux/mmc/host.h 这个头文件提供了MMC主机操作的接口和数据结构的定义,驱动程序可以根据需要实现这些回调函数来完成对MMC主机的控制和操作。
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 ------
如果觉得有用请点个免费的赞
您的支持就是我最大的动力,这对我很重要!!!