Files
gk-sdk/sample/common/sample_comm_periph.c

393 lines
12 KiB
C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/select.h>
#include <sys/socket.h>
#include "sample_comm.h"
#include "sample_comm_periph.h"
#include "xmedia_sys.h"
// 最大设备名长度
#define MAX_DEVICE_NAME_LENGTH 256
#define MAX_NL_BUF_SIZE (1024 * 16)
#define MAX_SELECT_TIMEOUT (2 * 1000 * 1000)
// 查找设备的分区(返回分区号,如 p1)
static xmedia_s32 sdcard_find_partition(const xmedia_char *device_name, xmedia_char *partition)
{
DIR *dir;
struct dirent *entry;
xmedia_char path[MAX_DEVICE_NAME_LENGTH + 32] = {0};
xmedia_s32 found = 0;
snprintf(path, sizeof(path), "/sys/block/%s", device_name);
dir = opendir(path);
if (!dir) {
return XMEDIA_FAILURE;
}
while ((entry = readdir(dir)) != NULL) {
if (strncmp(entry->d_name, device_name, strlen(device_name)) == 0 &&
strstr(entry->d_name, "p") != NULL) {
strncpy(partition, entry->d_name, MAX_DEVICE_NAME_LENGTH);
found = 1;
break;
}
}
closedir(dir);
return found ? XMEDIA_SUCCESS : XMEDIA_FAILURE;
}
// 挂载设备
static xmedia_s32 mount_device(const xmedia_char *mount_point, const xmedia_char *device_path)
{
const xmedia_char *fstypes[] = {"vfat", "ext4", "ntfs", "auto", NULL};
// 创建挂载点目录(若不存在)
if (mkdir(mount_point, 0755) && errno != EEXIST) {
SAMPLE_ERR("mkdir failed: %s\n", strerror(errno));
return XMEDIA_FAILURE;
}
// 尝试挂载常见文件系统类型(按优先级)
for (xmedia_s32 i = 0; fstypes[i]; i++) {
if (mount(device_path, mount_point, fstypes[i], MS_NOATIME, NULL) == 0) {
SAMPLE_PRT("Mounted %s (%s) to %s\n", device_path, fstypes[i], mount_point);
return XMEDIA_SUCCESS;
}
}
// 所有类型尝试失败
SAMPLE_ERR("Failed to mount %s: %s\n", device_path, strerror(errno));
return XMEDIA_FAILURE;
}
static xmedia_bool device_driver_is_bind(const xmedia_char *device, const xmedia_char *driver)
{
xmedia_char path[256] = {'\0'};
snprintf(path, 256, "%s/%s", driver, device);
return (access(path, F_OK) == 0);
}
static xmedia_s32 device_attach_driver(const xmedia_char *device, const xmedia_char *driver)
{
xmedia_s32 s32Ret = XMEDIA_FAILURE;
xmedia_char path[256] = {'\0'};
xmedia_s32 fd = -1;
snprintf(path, sizeof(path), "%s/bind", driver);
fd = open(path, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) {
SAMPLE_ERR("[%s()] can't open %s because %s\n", __func__, driver, strerror(errno));
return XMEDIA_FAILURE;
}
//MEDIA_PRT("[%s()] start bind %s to %s\n", __func__, device, driver);
s32Ret = write(fd, device, strlen(device));
if (s32Ret < 0) {
SAMPLE_ERR("[%s()] bind %s to %s failed because %s\n", __func__, device, driver,strerror(errno));
close(fd);
return XMEDIA_FAILURE;
}
close(fd);
return XMEDIA_SUCCESS;
}
static xmedia_s32 device_detach_driver(const xmedia_char *device, const xmedia_char *driver)
{
xmedia_s32 s32Ret = XMEDIA_FAILURE;
xmedia_char path[256] = {'\0'};
xmedia_s32 fd = -1;
snprintf(path, sizeof(path), "%s/unbind", driver);
fd = open(path, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) {
SAMPLE_ERR("[%s()] can't open %s because %s\n", __func__, path, strerror(errno));
return XMEDIA_FAILURE;
}
//MEDIA_PRT("[%s()] start unbind %s from %s\n", __func__, device, driver);
s32Ret = write(fd, device, strlen(device));
if (s32Ret < 0) {
SAMPLE_ERR("[%s()] unbind %s from %s failed because %s\n", __func__, device, driver, strerror(errno));
close(fd);
return XMEDIA_FAILURE;
}
close(fd);
return XMEDIA_SUCCESS;
}
static xmedia_bool device_action_check(const xmedia_char *device, const xmedia_char *notice_str, xmedia_char *buf)
{
xmedia_char *action = XMEDIA_NULL;
xmedia_char *subsystem = XMEDIA_NULL;
xmedia_char *devtype = XMEDIA_NULL;
xmedia_char *field = buf;
if (strstr(device, "sdhci") != XMEDIA_NULL) {
if (strcmp(notice_str, "add") == 0) {
while (*field != '\0' && field < buf + MAX_NL_BUF_SIZE) {
if (strstr(field, "ACTION=")) {
action = field + strlen("ACTION=");
} else if (strstr(field, "SUBSYSTEM=")) {
subsystem = field + strlen("SUBSYSTEM=");
} else if (strstr(field, "DEVTYPE=")) {
devtype = field + strlen("DEVTYPE=");
}
while (*field != '\0') field++;
field++;
}
if (subsystem && strcmp(subsystem, "block") == 0 && devtype && strcmp(devtype, "disk") == 0) {
if (strcmp(action, notice_str) == 0) {
//SAMPLE_ERR("notice_str :%s success\n", notice_str);
return XMEDIA_TRUE;
}
}
} else if (strcmp(notice_str, "remove") == 0) {
while (*field != '\0' && field < buf + MAX_NL_BUF_SIZE) {
if (strstr(field, "ACTION=")) {
action = field + strlen("ACTION=");
} else if (strstr(field, "SUBSYSTEM=")) {
subsystem = field + strlen("SUBSYSTEM=");
}
while (*field != '\0') field++;
field++;
}
if (subsystem && strcmp(subsystem, "mmc_host") == 0) {
if (strcmp(action, notice_str) == 0) {
//SAMPLE_ERR("notice_str :%s success\n", notice_str);
return XMEDIA_TRUE;
}
}
}
}
return XMEDIA_FALSE;
}
xmedia_s32 sample_comm_periph_mount_sdcard(const xmedia_char* mount_path, xmedia_s32 timeout_ms)
{
DIR *block_dir;
struct dirent *entry;
xmedia_u64 start_time = 0;
xmedia_u64 end_time = 0;
xmedia_char partition[MAX_DEVICE_NAME_LENGTH] = {0};
xmedia_char device_path[MAX_DEVICE_NAME_LENGTH + 32] = {0};
xmedia_sys_get_cur_pts(&start_time);
LOOP_AGAIN:
block_dir = opendir("/sys/block");
if (!block_dir) {
SAMPLE_ERR("Failed to open /sys/block: %s\n", strerror(errno));
return XMEDIA_FAILURE;
}
while ((entry = readdir(block_dir)) != NULL) {
// 只处理 mmcblk 设备
if (strncmp(entry->d_name, "mmcblk", 6) != 0) {
continue;
}
// 查找分区
if (sdcard_find_partition(entry->d_name, partition) == 0) {
// 挂载分区(如 /dev/mmcblk0p1
snprintf(device_path, sizeof(device_path), "/dev/%s", partition);
if (mount_device(mount_path, device_path) == XMEDIA_SUCCESS) {
closedir(block_dir);
return XMEDIA_SUCCESS;
}
} else {
// 无分区,挂载整个设备(如 /dev/mmcblk1
snprintf(device_path, sizeof(device_path), "/dev/%s", entry->d_name);
if (mount_device(mount_path, device_path) == XMEDIA_SUCCESS) {
closedir(block_dir);
return XMEDIA_SUCCESS;
}
}
}
closedir(block_dir);
xmedia_sys_get_cur_pts(&end_time);
if(end_time - start_time < timeout_ms * 1000) {
usleep(50 * 1000);
SAMPLE_PRT("No SD card found, find again\n");
goto LOOP_AGAIN;
}
SAMPLE_ERR("No SD card found.\n");
return XMEDIA_FAILURE;
}
xmedia_s32 sample_comm_periph_umount_sdcard(const xmedia_char *mount_path)
{
const xmedia_s32 max_retries = 30;
xmedia_s32 retry_count = 0;
while (retry_count < max_retries) {
if (umount(mount_path) == 0) {
return XMEDIA_SUCCESS;
}
// 错误处理
switch (errno) {
case EBUSY:
SAMPLE_ERR("ERROR: %s is busy (retry %d/%d)\n",
mount_path, retry_count + 1, max_retries);
break;
case EINVAL:
SAMPLE_ERR("Error: %s not mounted or invalid path\n", mount_path);
return XMEDIA_FAILURE;
case EPERM:
SAMPLE_ERR("Error: Requires root privileges\n");
return XMEDIA_FAILURE;
default:
SAMPLE_ERR("Unmount failed: %s\n", strerror(errno));
return XMEDIA_FAILURE;
}
retry_count++;
usleep(10 * 1000);
}
SAMPLE_ERR("Error: Failed to unmount %s after %d attempts\n", mount_path, max_retries);
return XMEDIA_FAILURE;
}
xmedia_s32 sample_comm_periph_drv_bind(const xmedia_char *device, const xmedia_char *driver, const xmedia_char *notice_str)
{
xmedia_s32 s32Ret = 0;
xmedia_s32 fd = -1;
xmedia_char buf[MAX_NL_BUF_SIZE] = {'\0'};
fd_set read_set;
struct timeval timeout;
struct sockaddr_nl addr;
if (device_driver_is_bind(device, driver)) {
SAMPLE_ERR("[%s()] sdcard device already bind!\n", __func__);
return XMEDIA_SUCCESS;
}
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = 1;
addr.nl_pid = 0;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
if (fd < 0) {
SAMPLE_ERR("[%s()] Failed to open sdcard netlink because %s\n", __func__, strerror(errno));
return XMEDIA_FAILURE;
} else if (bind(fd, (struct sockaddr *)(&addr), sizeof(addr)) != 0) {
SAMPLE_ERR("[%s()] bind sdcard netlink addr failed because %s\n", __func__, strerror(errno));
goto FAILED;
}
FD_ZERO(&read_set);
FD_SET(fd, &read_set);
timeout.tv_sec = 0;
timeout.tv_usec = MAX_SELECT_TIMEOUT;
// bind sdcard
if (device_attach_driver(device, driver) != XMEDIA_SUCCESS) {
goto FAILED;
}
// wait for bind success
RETRY:
s32Ret = select(fd + 1, &read_set, NULL, NULL, &timeout);
if (s32Ret > 0) {
memset(&buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf));
buf[MAX_NL_BUF_SIZE - 1] = '\0';
if (device_action_check(device, notice_str, buf) == XMEDIA_TRUE) {
goto SUCCESS;
}
goto RETRY; // drop all message
} else {
SAMPLE_ERR("[%s()] select error %s\n", __func__, strerror(errno));
goto FAILED;
}
SUCCESS:
close(fd);
return XMEDIA_SUCCESS;
FAILED:
close(fd);
return XMEDIA_FAILURE;
}
xmedia_s32 sample_comm_periph_drv_unbind(const xmedia_char *device, const xmedia_char *driver, const xmedia_char *notice_str)
{
xmedia_s32 s32Ret = 0;
xmedia_s32 fd = -1;
xmedia_char buf[MAX_NL_BUF_SIZE] = {'\0'};
fd_set read_set;
struct timeval timeout;
struct sockaddr_nl addr;
if (!device_driver_is_bind(device, driver)) {
SAMPLE_ERR("[%s()] sdcard device already unbind!\n", __func__);
return XMEDIA_SUCCESS;
}
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = 1;
addr.nl_pid = 0;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
if (fd < 0) {
SAMPLE_ERR("[%s()] Failed to open sdcard netlink because %s\n", __func__, strerror(errno));
return XMEDIA_FAILURE;
} else if (bind(fd, (struct sockaddr *)(&addr), sizeof(addr)) != 0) {
SAMPLE_ERR("[%s()] bind sdcard netlink addr failed because %s\n", __func__, strerror(errno));
goto FAILED;
}
memset(&buf, 0, sizeof(buf));
FD_ZERO(&read_set);
FD_SET(fd, &read_set);
timeout.tv_sec = 0;
timeout.tv_usec = MAX_SELECT_TIMEOUT;
// unbind sdcard
if (device_detach_driver(device, driver) != XMEDIA_SUCCESS)
goto FAILED;
// wait for unbind success
RETRY:
s32Ret = select(fd + 1, &read_set, NULL, NULL, &timeout);
if (s32Ret > 0) {
memset(&buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf));
buf[MAX_NL_BUF_SIZE - 1] = '\0';
if (device_action_check(device, notice_str, buf) == XMEDIA_TRUE) {
goto SUCCESS;
}
goto RETRY; // drop all message
} else {
SAMPLE_ERR("[%s()] select error %s\n", __func__, strerror(errno));
goto FAILED;
}
SUCCESS:
close(fd);
return XMEDIA_SUCCESS;
FAILED:
close(fd);
return XMEDIA_FAILURE;
}