Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fadb85e3 authored by Colin Cross's avatar Colin Cross
Browse files

ueventd: track platform device uevents to parse block device names

The mmc block devices on panda boards use a platform device called
omap/omap_hsmmc.0.  The number of path entries in the uevent after
the platform device is unknown, and the number of path entries in
the platform device is unknown, so the only way to determine how
many entries make up the platform device is to compare against
a list of platform devices.

Add a list of platform devices that have been registered, and
iterate through it to determine the platform device portion of
a block device uevent.

Change-Id: I1480bc6429172ca6997d548787be3863ce062472
parent eb5ba830
Loading
Loading
Loading
Loading
+88 −10
Original line number Diff line number Diff line
@@ -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);
    }