我想检查 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 卡时,会为子系统模块发送以下事件: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
活动中添加/删除?还是有其他方法可以检查设备是否可用(请记住分区问题)?
欢迎任何关于改进设备属性迭代或获取通知的方法的建议。
PS而且我不能使用libusb
:)。