Merge "ueventd: track platform device uevents to parse block device names"

This commit is contained in:
Colin Cross 2011-03-31 17:01:26 -07:00 committed by Android (Google) Code Review
commit ab0c4e0356
1 changed files with 88 additions and 10 deletions

View File

@ -97,8 +97,15 @@ struct perm_node {
struct listnode plist;
};
struct platform_node {
char *name;
int name_len;
struct listnode list;
};
static list_declare(sys_perms);
static list_declare(dev_perms);
static list_declare(platform_names);
int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid, unsigned int gid,
@ -212,6 +219,68 @@ static void make_device(const char *path,
setegid(AID_ROOT);
}
static void add_platform_device(const char *name)
{
int name_len = strlen(name);
struct listnode *node;
struct platform_node *bus;
list_for_each_reverse(node, &platform_names) {
bus = node_to_item(node, struct platform_node, list);
if ((bus->name_len < name_len) &&
(name[bus->name_len] == '/') &&
!strncmp(name, bus->name, bus->name_len))
/* subdevice of an existing platform, ignore it */
return;
}
INFO("adding platform device %s\n", name);
bus = calloc(1, sizeof(struct platform_node));
bus->name = strdup(name);
bus->name_len = name_len;
list_add_tail(&platform_names, &bus->list);
}
/*
* given a name that may start with a platform device, find the length of the
* platform device prefix. If it doesn't start with a platform device, return
* 0.
*/
static const char *find_platform_device(const char *name)
{
int name_len = strlen(name);
struct listnode *node;
struct platform_node *bus;
list_for_each_reverse(node, &platform_names) {
bus = node_to_item(node, struct platform_node, list);
if ((bus->name_len < name_len) &&
(name[bus->name_len] == '/') &&
!strncmp(name, bus->name, bus->name_len))
return bus->name;
}
return NULL;
}
static void remove_platform_device(const char *name)
{
struct listnode *node;
struct platform_node *bus;
list_for_each_reverse(node, &platform_names) {
bus = node_to_item(node, struct platform_node, list);
if (!strcmp(name, bus->name)) {
INFO("removing platform device %s\n", name);
free(bus->name);
list_remove(node);
free(bus);
return;
}
}
}
#if LOG_UEVENTS
static inline suseconds_t get_usecs(void)
@ -332,7 +401,7 @@ err:
static char **parse_platform_block_device(struct uevent *uevent)
{
const char *driver;
const char *device;
const char *path;
char *slash;
int width;
@ -352,16 +421,14 @@ static char **parse_platform_block_device(struct uevent *uevent)
/* Drop "/devices/platform/" */
path = uevent->path;
driver = path + 18;
slash = strchr(driver, '/');
if (!slash)
goto err;
width = slash - driver;
if (width <= 0)
device = path + 18;
device = find_platform_device(device);
if (!device)
goto err;
snprintf(link_path, sizeof(link_path), "/dev/block/platform/%.*s",
width, driver);
INFO("found platform device %s\n", device);
snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
@ -421,6 +488,16 @@ static void handle_device(const char *action, const char *devpath,
}
}
static void handle_platform_device_event(struct uevent *uevent)
{
const char *name = uevent->path + 18; /* length of /devices/platform/ */
if (!strcmp(uevent->action, "add"))
add_platform_device(name);
else if (!strcmp(uevent->action, "remove"))
remove_platform_device(name);
}
static const char *parse_device_name(struct uevent *uevent, unsigned int len)
{
const char *name;
@ -461,7 +538,6 @@ static void handle_block_device_event(struct uevent *uevent)
handle_device(uevent->action, devpath, uevent->path, 1,
uevent->major, uevent->minor, links);
}
static void handle_generic_device_event(struct uevent *uevent)
@ -537,6 +613,8 @@ static void handle_device_event(struct uevent *uevent)
if (!strncmp(uevent->subsystem, "block", 5)) {
handle_block_device_event(uevent);
} else if (!strncmp(uevent->subsystem, "platform", 8)) {
handle_platform_device_event(uevent);
} else {
handle_generic_device_event(uevent);
}