gpt4 book ai didi

c - 如何获取 SD 卡事件的通知?

转载 作者:IT王子 更新时间:2023-10-29 00:59:09 26 4
gpt4 key购买 nike

我想检查 SD 卡是否存在,并接收 SD 卡添加/移除通知。

到目前为止,我已经使用了 libudev,并且制作了一个用于监听 SD 卡事件的小应用程序。

代码如下:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <errno.h>
#include <sys/time.h> //debug -> remove me

#include <libudev.h>

#define ADD_FILTER "add"
#define REMOVE_FILTER "remove"
#define SUBSYSTEM_FILTER "block"
#define ATTR_FILTER "ID_MODEL"
#define SD_ATTR_VALUE "SD_MMC"
#define ATTR_ACTIVE_SD "ID_PART_TABLE_TYPE"

static bool isDeviceSD(struct udev_device *device);
static bool isDevPresent(struct udev *device);
static void print_device(struct udev_device *device, const char *source); //for debugging -> remove me
static bool s_bSD_present;

int main()
{
struct udev *udev;
struct udev_monitor *udev_monitor = NULL;
fd_set readfds;
s_bSD_present = false;

udev = udev_new();
if (udev == NULL)
{
printf("udev_new FAILED \n");
return 1;
}

s_bSD_present = isDevPresent(udev);
if(s_bSD_present)
{
printf("+++SD is plugged in \n");
}
else
{
printf("---SD is not plugged in \n");
}

udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
if (udev_monitor == NULL) {
printf("udev_monitor_new_from_netlink FAILED \n");
return 1;
}

//add some filters
if( udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, SUBSYSTEM_FILTER, NULL) < 0 )
{
printf("udev_monitor_filter_add_match_subsystem_devtype FAILED \n");
return 1;
}

if (udev_monitor_enable_receiving(udev_monitor) < 0)
{
printf("udev_monitor_enable_receiving FAILED \n");
return 1;
}

while (1) {
printf("Polling for new data... \n");

int fdcount = 0;

FD_ZERO(&readfds);

if (udev_monitor != NULL)
{
FD_SET(udev_monitor_get_fd(udev_monitor), &readfds);
}

fdcount = select(udev_monitor_get_fd(udev_monitor)+1, &readfds, NULL, NULL, NULL);
if (fdcount < 0)
{
if (errno != EINTR)
printf("Error receiving uevent message\n");
continue;
}

if ((udev_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds))
{
struct udev_device *device;

device = udev_monitor_receive_device(udev_monitor);
if (device == NULL)
continue;

//check the action
const char* szAction = udev_device_get_action(device);
if( strcmp(szAction, ADD_FILTER) == 0)
{
if( !s_bSD_present && isDeviceSD(device) )
{
s_bSD_present = true;
printf("+++SD has been plugged in \n");
}
}
else if( strcmp(szAction, REMOVE_FILTER) == 0 )
{
if( s_bSD_present && isDeviceSD(device) )
{
s_bSD_present = false;
printf("---SD has been removed \n");
}
}

udev_device_unref(device);
}
}

return 0;
}

static bool isDeviceSD(struct udev_device *device)
{
bool retVal = false;
struct udev_list_entry *list_entry = 0;
struct udev_list_entry* model_entry = 0;
struct udev_list_entry* active_sd_entry = 0;

list_entry = udev_device_get_properties_list_entry(device);
model_entry = udev_list_entry_get_by_name(list_entry, ATTR_FILTER);
if( 0 != model_entry )
{
const char* szModelValue = udev_list_entry_get_value(model_entry);
active_sd_entry = udev_list_entry_get_by_name(list_entry, ATTR_ACTIVE_SD);
if(strcmp(szModelValue, SD_ATTR_VALUE) == 0 && active_sd_entry != 0)
{
printf("Device is SD \n");
retVal = true;

//print_device(device, "UDEV");
}
}
return retVal;
}


static bool isDevPresent(struct udev *device)
{
bool retVal = false;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *dev_list_entry;

enumerate = udev_enumerate_new(device);
udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_FILTER);
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);

udev_list_entry_foreach(dev_list_entry, devices)
{
struct udev_device *dev;
const char* dev_path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(device, dev_path);

if( true == isDeviceSD(dev) )
{
retVal = true;
udev_device_unref(dev);
break;
}

udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);

return retVal;
}


static void print_device(struct udev_device *device, const char *source)
{
struct timeval tv;
struct timezone tz;

gettimeofday(&tv, &tz);
printf("%-6s[%llu.%06u] %-8s %s (%s)\n",
source,
(unsigned long long) tv.tv_sec, (unsigned int) tv.tv_usec,
udev_device_get_action(device),
udev_device_get_devpath(device),
udev_device_get_subsystem(device));

struct udev_list_entry *list_entry;

udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
printf("%s=%s\n",
udev_list_entry_get_name(list_entry),
udev_list_entry_get_value(list_entry));
printf("\n");

}

此代码将获取 SD 卡添加/移除通知(以及 SD 的初始状态 - 插入/拔出)。然而,它更像是一种 hack,并不是在所有情况下都有效。

我目前使用设备的 ID_MODEL 属性并检查它是否为 SD_MMC - 用于 SD 卡。我现在只需要这种类型的卡,就足够了。

插入 SD 卡时,会为子系统 block 发送以下事件:每个分区有 2 个 change 事件和 1 个 add 事件。下面列出了事件属性:

<----- change event - subsystem block - disk type disk ----->

UDEV [1339412734.522055] change /devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd (block)
UDEV_LOG=3
ACTION=change
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd
SUBSYSTEM=block
DEVNAME=/dev/sdd
DEVTYPE=disk
SEQNUM=3168
ID_VENDOR=Generic-
ID_VENDOR_ENC=Generic-
ID_VENDOR_ID=0bda
ID_MODEL=SD_MMC
ID_MODEL_ENC=SD\x2fMMC\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
ID_MODEL_ID=0151
ID_REVISION=1.00
ID_SERIAL=Generic-_SD_MMC_20060413092100000-0:2
ID_SERIAL_SHORT=20060413092100000
ID_TYPE=disk
ID_INSTANCE=0:2
ID_BUS=usb
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_USB_DRIVER=usb-storage
ID_PATH=pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2
ID_PART_TABLE_TYPE=dos
UDISKS_PRESENTATION_NOPOLICY=0
UDISKS_PARTITION_TABLE=1
UDISKS_PARTITION_TABLE_SCHEME=mbr
UDISKS_PARTITION_TABLE_COUNT=2
MAJOR=8
MINOR=48
DEVLINKS=/dev/block/8:48 /dev/disk/by-id/usb-Generic-_SD_MMC_20060413092100000-0:2 /dev/disk/by-path/pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2

<----- add event partition 1 - subsystem block - disk type partition ----->

UDEV [1339412734.719107] add /devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd/sdd1 (block)
UDEV_LOG=3
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd/sdd1
SUBSYSTEM=block
DEVNAME=/dev/sdd1
DEVTYPE=partition
SEQNUM=3169
ID_VENDOR=Generic-
ID_VENDOR_ENC=Generic-
ID_VENDOR_ID=0bda
ID_MODEL=SD_MMC
ID_MODEL_ENC=SD\x2fMMC\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
ID_MODEL_ID=0151
ID_REVISION=1.00
ID_SERIAL=Generic-_SD_MMC_20060413092100000-0:2
ID_SERIAL_SHORT=20060413092100000
ID_TYPE=disk
ID_INSTANCE=0:2
ID_BUS=usb
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_USB_DRIVER=usb-storage
ID_PATH=pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2
ID_PART_TABLE_TYPE=dos
ID_FS_UUID=6343c7b9-92a9-4d8f-bdd8-893f1190f294
ID_FS_UUID_ENC=6343c7b9-92a9-4d8f-bdd8-893f1190f294
ID_FS_VERSION=1.0
ID_FS_TYPE=ext2
ID_FS_USAGE=filesystem
UDISKS_PRESENTATION_NOPOLICY=0
UDISKS_PARTITION=1
UDISKS_PARTITION_SCHEME=mbr
UDISKS_PARTITION_NUMBER=1
UDISKS_PARTITION_TYPE=0x83
UDISKS_PARTITION_SIZE=1006919680
UDISKS_PARTITION_SLAVE=/sys/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd
UDISKS_PARTITION_OFFSET=11618304
UDISKS_PARTITION_ALIGNMENT_OFFSET=0
MAJOR=8
MINOR=49
DEVLINKS=/dev/block/8:49 /dev/disk/by-id/usb-Generic-_SD_MMC_20060413092100000-0:2-part1 /dev/disk/by-path/pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2-part1 /dev/disk/by-uuid/6343c7b9-92a9-4d8f-bdd8-893f1190f294

<----- add event partition 2 - subsystem block - disk type partition ----->

UDEV [1339412734.731338] add /devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd/sdd2 (block)
UDEV_LOG=3
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd/sdd2
SUBSYSTEM=block
DEVNAME=/dev/sdd2
DEVTYPE=partition
SEQNUM=3170
ID_VENDOR=Generic-
ID_VENDOR_ENC=Generic-
ID_VENDOR_ID=0bda
ID_MODEL=SD_MMC
ID_MODEL_ENC=SD\x2fMMC\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
ID_MODEL_ID=0151
ID_REVISION=1.00
ID_SERIAL=Generic-_SD_MMC_20060413092100000-0:2
ID_SERIAL_SHORT=20060413092100000
ID_TYPE=disk
ID_INSTANCE=0:2
ID_BUS=usb
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_USB_DRIVER=usb-storage
ID_PATH=pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2
ID_PART_TABLE_TYPE=dos
UDISKS_PRESENTATION_NOPOLICY=0
UDISKS_PARTITION=1
UDISKS_PARTITION_SCHEME=mbr
UDISKS_PARTITION_NUMBER=2
UDISKS_PARTITION_TYPE=0xda
UDISKS_PARTITION_SIZE=11618304
UDISKS_PARTITION_FLAGS=boot
UDISKS_PARTITION_SLAVE=/sys/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd
UDISKS_PARTITION_OFFSET=1022410752
UDISKS_PARTITION_ALIGNMENT_OFFSET=0
MAJOR=8
MINOR=50
DEVLINKS=/dev/block/8:50 /dev/disk/by-id/usb-Generic-_SD_MMC_20060413092100000-0:2-part2 /dev/disk/by-path/pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2-part2

change 事件中,我无法提取有关设备是添加还是删除的任何信息。我试图打开设备名称 \dev\sdd 但我没有权限,所以该选项落...

现在我只是检查分区的操作属性(add/remove)。

此版本的程序非常适用于具有分区的 SD 卡。当没有分区时,只有 change 事件被接收。

所以我的问题是:有什么方法可以检查媒体是否已从 change 事件中添加/删除?或者是否有其他方法来检查设备是否可用(记住分区问题)?

欢迎任何关于改进设备属性迭代或获取通知的方法的建议。

附言而且我不能使用 libusb :).

最佳答案

好的。所以我让它在没有分区的 SD 卡的 PC 上工作。

更新后的代码是这样的:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <errno.h>
#include <sys/time.h> //debug -> remove me
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <libudev.h>

#define ADD_FILTER "add"
#define REMOVE_FILTER "remove"
#define SUBSYSTEM_FILTER "block"
#define DEVTYPE_FILTER "disk"
#define ATTR_FILTER "ID_MODEL"
#define SD_ATTR_VALUE "SD_MMC"
#define ATTR_ADDED_DISK "UDISKS_PARTITION_TABLE" // attribute is available for "change" event when SD card is added (n/a when removed)

static bool isDeviceSD(struct udev_device *device); //checks if device is SD card (MMC)
static bool isDevPresent(struct udev *device); //checks if device is present (SD + added)
static bool isDeviceAdded(struct udev_device *device); //checks if device is added (presence of attribute ATTR_ADDED_DISK)
static void print_device(struct udev_device *device, const char *source); //for debugging -> remove me
static bool s_bSD_present;

int main()
{
struct udev *udev;
struct udev_monitor *udev_monitor = NULL;
fd_set readfds;
s_bSD_present = false;

udev = udev_new();
if (udev == NULL)
{
printf("udev_new FAILED \n");
return 1;
}

if( isDevPresent(udev) )
{
s_bSD_present = true;
printf("+++SD is plugged in \n");
}
else
{
printf("---SD is not plugged in \n");
}

udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
if (udev_monitor == NULL) {
printf("udev_monitor_new_from_netlink FAILED \n");
return 1;
}

//add some filters
if( udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, SUBSYSTEM_FILTER, DEVTYPE_FILTER) < 0 )
{
printf("udev_monitor_filter_add_match_subsystem_devtype FAILED \n");
return 1;
}

if (udev_monitor_enable_receiving(udev_monitor) < 0)
{
printf("udev_monitor_enable_receiving FAILED \n");
return 1;
}

while (1) {
printf("Polling for new data... \n");

int fdcount = 0;

FD_ZERO(&readfds);

if (udev_monitor != NULL)
{
FD_SET(udev_monitor_get_fd(udev_monitor), &readfds);
}

fdcount = select(udev_monitor_get_fd(udev_monitor)+1, &readfds, NULL, NULL, NULL);
if (fdcount < 0)
{
if (errno != EINTR)
printf("Error receiving uevent message\n");
continue;
}

if ((udev_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds))
{
struct udev_device *device;

device = udev_monitor_receive_device(udev_monitor);
if (device == NULL)
continue;

//check presence
if( isDeviceSD(device) && isDeviceAdded(device) )
{
if(!s_bSD_present) //guard for double "change" events
{
s_bSD_present = true;
printf("+++SD has been plugged in \n");
}
}
else
{
if(s_bSD_present) //not needed -> just keeping consistency
{
s_bSD_present = false;
printf("---SD has been removed \n");
}
}

udev_device_unref(device);
}
}

return 0;
}

static bool isDeviceSD(struct udev_device *device)
{
bool retVal = false;
struct udev_list_entry *list_entry = 0;
struct udev_list_entry* model_entry = 0;

list_entry = udev_device_get_properties_list_entry(device);
model_entry = udev_list_entry_get_by_name(list_entry, ATTR_FILTER);
if( 0 != model_entry )
{
const char* szModelValue = udev_list_entry_get_value(model_entry);
if( strcmp( szModelValue, SD_ATTR_VALUE) == 0 )
{
//printf("Device is SD \n");
retVal = true;

//print_device(device, "UDEV");
}
}
return retVal;
}

static bool isDeviceAdded(struct udev_device *device)
{
bool retVal = false;
struct udev_list_entry *list_entry = 0;
struct udev_list_entry* added_disk_entry = 0;


list_entry = udev_device_get_properties_list_entry(device);
added_disk_entry = udev_list_entry_get_by_name(list_entry,/* "DEVNAME" */ ATTR_ADDED_DISK);
if( 0 != added_disk_entry )
{
retVal = true;
}
return retVal;
}


static bool isDevPresent(struct udev *device)
{
bool retVal = false;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *dev_list_entry;

enumerate = udev_enumerate_new(device);
udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_FILTER);
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);

udev_list_entry_foreach(dev_list_entry, devices)
{
struct udev_device *dev;
const char* dev_path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(device, dev_path);

if( isDeviceSD(dev) && isDeviceAdded(dev) )
{
retVal = true;
udev_device_unref(dev);
break;
}

udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);

return retVal;
}


static void print_device(struct udev_device *device, const char *source)
{
struct timeval tv;
struct timezone tz;

gettimeofday(&tv, &tz);
printf("%-6s[%llu.%06u] %-8s %s (%s)\n",
source,
(unsigned long long) tv.tv_sec, (unsigned int) tv.tv_usec,
udev_device_get_action(device),
udev_device_get_devpath(device),
udev_device_get_subsystem(device));

struct udev_list_entry *list_entry;

udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
printf("%s=%s\n",
udev_list_entry_get_name(list_entry),
udev_list_entry_get_value(list_entry));
printf("\n");

}

解决方案(仍然不是很明智)是检查一些只有在添加 SD 卡时才可用的属性(如 UDISKS_PARTITION_TABLE)。

这在 x86 上运行良好。

关于c - 如何获取 SD 卡事件的通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10979123/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com