of_platform_device_create

struct platform_device *of_platform_device_create(struct device_node *np,
                        const char *bus_id,
                        struct device *parent)
{
    return of_platform_device_create_pdata(np, bus_id, NULL, parent);
}

static struct platform_device *of_platform_device_create_pdata(
                    struct device_node *np,
                    const char *bus_id,
                    void *platform_data,
                    struct device *parent)
{
    struct platform_device *dev;

    if (!of_device_is_available(np) ||
        of_node_test_and_set_flag(np, OF_POPULATED))
        return NULL;

    dev = of_device_alloc(np, bus_id, parent);
    if (!dev)
        goto err_clear_flag;

    dev->dev.bus = &platform_bus_type;
    dev->dev.platform_data = platform_data;
    of_msi_configure(&dev->dev, dev->dev.of_node);

    if (of_device_add(dev) != 0) {
        platform_device_put(dev);
        goto err_clear_flag;
    }

    return dev;

err_clear_flag:
    of_node_clear_flag(np, OF_POPULATED);
    return NULL;
}


struct platform_device *of_device_alloc(struct device_node *np,
                  const char *bus_id,
                  struct device *parent)
{
    struct platform_device *dev;
    int rc, i, num_reg = 0, num_irq;
    struct resource *res, temp_res;

    dev = platform_device_alloc("", PLATFORM_DEVID_NONE);
    if (!dev)
        return NULL;

    /* count the io and irq resources */
    while (of_address_to_resource(np, num_reg, &temp_res) == 0)
        num_reg++;
    num_irq = of_irq_count(np);

    /* Populate the resource table */
    if (num_irq || num_reg) {
        res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
        if (!res) {
            platform_device_put(dev);
            return NULL;
        }

        dev->num_resources = num_reg + num_irq;
        dev->resource = res;
        for (i = 0; i < num_reg; i++, res++) {
            rc = of_address_to_resource(np, i, res);
            WARN_ON(rc);
        }
        if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
            pr_debug("not all legacy IRQ resources mapped for %s\n",
                 np->name);
    }

    dev->dev.of_node = of_node_get(np);
    dev->dev.fwnode = &np->fwnode;
    dev->dev.parent = parent ? : &platform_bus;

    if (bus_id)
        dev_set_name(&dev->dev, "%s", bus_id);
    else
        of_device_make_bus_id(&dev->dev);

    return dev;
}

int of_address_to_resource(struct device_node *dev, int index,
               struct resource *r)
{
    const __be32    *addrp;
    u64        size;
    unsigned int    flags;
    const char    *name = NULL;

    addrp = of_get_address(dev, index, &size, &flags);
    if (addrp == NULL)
        return -EINVAL;

    /* Get optional "reg-names" property to add a name to a resource */
    of_property_read_string_index(dev, "reg-names",    index, &name);

    return __of_address_to_resource(dev, addrp, size, flags, name, r);
}

const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
            unsigned int *flags)
{
    const __be32 *prop;
    unsigned int psize;
    struct device_node *parent;
    struct of_bus *bus;
    int onesize, i, na, ns;

    /* Get parent & match bus type */
    parent = of_get_parent(dev);
    if (parent == NULL)
        return NULL;
    bus = of_match_bus(parent);
    bus->count_cells(dev, &na, &ns);
    of_node_put(parent);
    if (!OF_CHECK_ADDR_COUNT(na))
        return NULL;

    /* Get "reg" or "assigned-addresses" property */
    prop = of_get_property(dev, bus->addresses, &psize);
    if (prop == NULL)
        return NULL;
    psize /= 4;

    onesize = na + ns;
    for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
        if (i == index) {
            if (size)
                *size = of_read_number(prop + na, ns);
            if (flags)
                *flags = bus->get_flags(prop);
            return prop;
        }
    return NULL;
}

static void of_bus_default_count_cells(struct device_node *dev,
                       int *addrc, int *sizec)
{
    if (addrc)
        *addrc = of_n_addr_cells(dev);
    if (sizec)
        *sizec = of_n_size_cells(dev);
}

int of_n_addr_cells(struct device_node *np)
{
    u32 cells;

    do {
        if (np->parent)
            np = np->parent;
        if (!of_property_read_u32(np, "#address-cells", &cells))
            return cells;
    } while (np->parent);
    /* No #address-cells property for the root node */
    return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
}

int of_n_size_cells(struct device_node *np)
{
    u32 cells;

    do {
        if (np->parent)
            np = np->parent;
        if (!of_property_read_u32(np, "#size-cells", &cells))
            return cells;
    } while (np->parent);
    /* No #size-cells property for the root node */
    return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
}


int of_irq_count(struct device_node *dev)
{
    struct of_phandle_args irq;
    int nr = 0;

    while (of_irq_parse_one(dev, nr, &irq) == 0)
        nr++;

    return nr;
}


/**
 * of_irq_parse_one - Resolve an interrupt for a device
 * @device: the device whose interrupt is to be resolved
 * @index: index of the interrupt to resolve
 * @out_irq: structure of_irq filled by this function
 *
 * This function resolves an interrupt for a node by walking the interrupt tree,
 * finding which interrupt controller node it is attached to, and returning the
 * interrupt specifier that can be used to retrieve a Linux IRQ number.
 */
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
{
    struct device_node *p;
    const __be32 *addr;
    u32 intsize;
    int i, res;

    pr_debug("of_irq_parse_one: dev=%pOF, index=%d\n", device, index);

    /* OldWorld mac stuff is "special", handle out of line */
    if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
        return of_irq_parse_oldworld(device, index, out_irq);

    /* Get the reg property (if any) */
    addr = of_get_property(device, "reg", NULL);

    /* Try the new-style interrupts-extended first */
    res = of_parse_phandle_with_args(device, "interrupts-extended",
                    "#interrupt-cells", index, out_irq);
    if (!res)
        return of_irq_parse_raw(addr, out_irq);

    /* Look for the interrupt parent. */
    p = of_irq_find_parent(device);
    if (p == NULL)
        return -EINVAL;

    /* Get size of interrupt specifier */
    if (of_property_read_u32(p, "#interrupt-cells", &intsize)) {
        res = -EINVAL;
        goto out;
    }

    pr_debug(" parent=%pOF, intsize=%d\n", p, intsize);

    /* Copy intspec into irq structure */
    out_irq->np = p;
    out_irq->args_count = intsize;
    for (i = 0; i < intsize; i++) {
        res = of_property_read_u32_index(device, "interrupts",
                         (index * intsize) + i,
                         out_irq->args + i);
        if (res)
            goto out;
    }

    pr_debug(" intspec=%d\n", *out_irq->args);


    /* Check if there are any interrupt-map translations to process */
    res = of_irq_parse_raw(addr, out_irq);
 out:
    of_node_put(p);
    return res;
}

int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
        int nr_irqs)
{
    int i;

    for (i = 0; i < nr_irqs; i++, res++)
        if (of_irq_to_resource(dev, i, res) <= 0)
            break;

    return i;
}

int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
{
    int irq = of_irq_get(dev, index);

    if (irq < 0)
        return irq;

    /* Only dereference the resource if both the
     * resource and the irq are valid. */
    if (r && irq) {
        const char *name = NULL;

        memset(r, 0, sizeof(*r));
        /*
         * Get optional "interrupt-names" property to add a name
         * to the resource.
         */
        of_property_read_string_index(dev, "interrupt-names", index,
                          &name);

        r->start = r->end = irq;
        r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq));
        r->name = name ? name : of_node_full_name(dev);
    }

    return irq;
}

`device_create_file()`函数是在设备驱动程序中创建一个sysfs文件节点的函数。在Linux内核中,sysfs是一个虚拟文件系统,它允许内核和用户空间之间进行通信。sysfs文件系统中的每一个文件都是一个内核对象的属性,可以通过读写这些属性来控制和监视内核对象的状态。 `device_create_file()`函数需要三个参数:设备结构体(struct device *)、指向属性结构体(struct attribute *)的指针,以及sysfs文件节点名字的字符串。 以下是使用`device_create_file()`函数创建设备文件的示例代码: ```c #include <linux/device.h> static struct attribute my_attr = { .name = "my_attribute", .mode = S_IRUSR | S_IWUSR, }; static ssize_t my_attribute_show(struct device *dev, struct device_attribute *attr, char *buf) { // 读取属性值并将其写入到缓冲区buf中 } static ssize_t my_attribute_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { // 将从buf中读取的属性值写入到设备中 } static DEVICE_ATTR(my_attribute, S_IRUSR | S_IWUSR, my_attribute_show, my_attribute_store); static int my_device_probe(struct platform_device *pdev) { // 创建设备节点 device_create_file(&pdev->dev, &dev_attr_my_attribute); return 0; } static int my_device_remove(struct platform_device *pdev) { // 删除设备节点 device_remove_file(&pdev->dev, &dev_attr_my_attribute); return 0; } ``` 在上面的代码中,我们定义了一个名为`my_attr`的属性结构体,并使用`DEVICE_ATTR()`宏将其转换为设备属性。然后,在设备的probe函数中使用`device_create_file()`函数创建设备文件`my_attribute`,在设备的remove函数中使用`device_remove_file()`函数删除该文件。在设备属性的`show`和`store`函数中,我们可以实现对设备属性的读写操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值