From patchwork Wed Jul 23 12:55:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 372929 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 1A47A140174 for ; Wed, 23 Jul 2014 23:01:04 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E0AD0A7406; Wed, 23 Jul 2014 14:59:42 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id IsVNUPvPkB2K; Wed, 23 Jul 2014 14:59:42 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 0D94BA7479; Wed, 23 Jul 2014 14:57:33 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8B9DFA7560 for ; Wed, 23 Jul 2014 14:56:32 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0Ptv-zBNvFKl for ; Wed, 23 Jul 2014 14:56:27 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-yh0-f73.google.com (mail-yh0-f73.google.com [209.85.213.73]) by theia.denx.de (Postfix) with ESMTPS id 5DFC1A75CA for ; Wed, 23 Jul 2014 14:55:56 +0200 (CEST) Received: by mail-yh0-f73.google.com with SMTP id f73so200695yha.0 for ; Wed, 23 Jul 2014 05:55:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ktM0QvDC4xGrrMIT9aCKGJHbjEApa924GPosVgdVP2o=; b=kGal76Wv/945ciEA5ETX04Nq6/CDNTf/HR0Mp3RgxnhsTOFKKZFGxzTxBWLzewq1Fm 7uWZPHReJYIwLkiaoXeozZjmSu10uatSLIy99nyoHp9RVj64+ZNqQ4fDuJ5er8K30pbf KXaHQzYdBt+LAV+LWANwCSrCgCfryN791MC4ohh4ZhBp0y9X66UEg09QPA2/FP4tGM/m Y4+t/5DlUOnM0xbXwNoPMF+XRcw0hpTpqXqLFNUQm8pCI0oQ+GaoTyoOiSkUypPlnmnj mLiT+/5fp8gXTuHQMqe814W9oHcjp6DMDZ5qppp1DoE8UDRt0ecfF2n3JuNaPNKXe4Bh kwGQ== X-Gm-Message-State: ALoCoQlvd+XxDZEYwb4pKT4BML3pxsFTt8uRv5489xgEfbhp+RNWXiCfF4zQeqg8/SEu7jZF3Tjk X-Received: by 10.236.123.68 with SMTP id u44mr17368585yhh.19.1406120155528; Wed, 23 Jul 2014 05:55:55 -0700 (PDT) Received: from corp2gmr1-1.hot.corp.google.com (corp2gmr1-1.hot.corp.google.com [172.24.189.92]) by gmr-mx.google.com with ESMTPS id y50si391414yhk.4.2014.07.23.05.55.55 for (version=TLSv1.1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 23 Jul 2014 05:55:55 -0700 (PDT) Received: from kaki.bld.corp.google.com (kaki.bld.corp.google.com [172.29.216.32]) by corp2gmr1-1.hot.corp.google.com (Postfix) with ESMTP id 58E2D31C269; Wed, 23 Jul 2014 05:55:55 -0700 (PDT) Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id 15D7A22047D; Wed, 23 Jul 2014 06:55:55 -0600 (MDT) From: Simon Glass To: U-Boot Mailing List Date: Wed, 23 Jul 2014 06:55:19 -0600 Message-Id: <1406120124-9373-25-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 2.0.0.526.g5318336 In-Reply-To: <1406120124-9373-1-git-send-email-sjg@chromium.org> References: <1406120124-9373-1-git-send-email-sjg@chromium.org> Subject: [U-Boot] [PATCH v3 24/29] dm: Add functions to access a device's children X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Devices can have childen that can be addressed by a simple index, the sequence number or a device tree offset. Add functions to access a child in each of these ways. The index is typically used as a fallback when the sequence number is not available. For example we may use a serial UART with sequence number 0 as the console, but if no UART has sequence number 0, then we can fall back to just using the first UART (index 0). The device tree offset function is useful for buses, where they want to locate one of their children. The device tree can be scanned to find the offset of each child, and that offset can then find the device. Signed-off-by: Simon Glass --- Changes in v3: None Changes in v2: None doc/driver-model/README.txt | 3 +- drivers/core/device.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ include/dm/device.h | 58 ++++++++++++++++++++++++++++ test/dm/bus.c | 46 ++++++++++++++++++++++ 4 files changed, 199 insertions(+), 1 deletion(-) diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt index a2b6122..59ef05c 100644 --- a/doc/driver-model/README.txt +++ b/doc/driver-model/README.txt @@ -95,13 +95,14 @@ are provided in test/dm. To run them, try: You should see something like this: <...U-Boot banner...> - Running 18 driver model tests + Running 19 driver model tests Test: dm_test_autobind Test: dm_test_autoprobe Test: dm_test_bus_children Device 'd-test': seq 3 is in use by 'b-test' Device 'c-test@0': seq 0 is in use by 'a-test' Device 'c-test@1': seq 1 is in use by 'd-test' + Test: dm_test_bus_children_funcs Test: dm_test_children Test: dm_test_fdt Device 'd-test': seq 3 is in use by 'b-test' diff --git a/drivers/core/device.c b/drivers/core/device.c index 848ce3b..74bb5f0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -376,3 +376,96 @@ void *dev_get_priv(struct udevice *dev) return dev->priv; } + +static int device_get_device_tail(struct udevice *dev, int ret, + struct udevice **devp) +{ + if (ret) + return ret; + + ret = device_probe(dev); + if (ret) + return ret; + + *devp = dev; + + return 0; +} + +int device_get_child(struct udevice *parent, int index, struct udevice **devp) +{ + struct udevice *dev; + + list_for_each_entry(dev, &parent->child_head, sibling_node) { + if (!index--) + return device_get_device_tail(dev, 0, devp); + } + + return -ENODEV; +} + +int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq, + bool find_req_seq, struct udevice **devp) +{ + struct udevice *dev; + + *devp = NULL; + if (seq_or_req_seq == -1) + return -ENODEV; + + list_for_each_entry(dev, &parent->child_head, sibling_node) { + if ((find_req_seq ? dev->req_seq : dev->seq) == + seq_or_req_seq) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + +int device_get_child_by_seq(struct udevice *parent, int seq, + struct udevice **devp) +{ + struct udevice *dev; + int ret; + + *devp = NULL; + ret = device_find_child_by_seq(parent, seq, false, &dev); + if (ret == -ENODEV) { + /* + * We didn't find it in probed devices. See if there is one + * that will request this seq if probed. + */ + ret = device_find_child_by_seq(parent, seq, true, &dev); + } + return device_get_device_tail(dev, ret, devp); +} + +int device_find_child_by_of_offset(struct udevice *parent, int of_offset, + struct udevice **devp) +{ + struct udevice *dev; + + *devp = NULL; + + list_for_each_entry(dev, &parent->child_head, sibling_node) { + if (dev->of_offset == of_offset) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + +int device_get_child_by_of_offset(struct udevice *parent, int seq, + struct udevice **devp) +{ + struct udevice *dev; + int ret; + + *devp = NULL; + ret = device_find_child_by_of_offset(parent, seq, &dev); + return device_get_device_tail(dev, ret, devp); +} diff --git a/include/dm/device.h b/include/dm/device.h index 9077490..3f0f711 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -169,6 +169,18 @@ void *dev_get_platdata(struct udevice *dev); void *dev_get_priv(struct udevice *dev); /** + * device_get_child() - Get the child of a device by index + * + * Returns the numbered child, 0 being the first. This does not use + * sequence numbers, only the natural order. + * + * @dev: Parent device to check + * @index: Child index + * @devp: Returns pointer to device + */ +int device_get_child(struct udevice *parent, int index, struct udevice **devp); + +/** * device_find_child_by_seq() - Find a child device based on a sequence * * This searches for a device with the given seq or req_seq. @@ -190,4 +202,50 @@ void *dev_get_priv(struct udevice *dev); int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq, bool find_req_seq, struct udevice **devp); +/** + * device_get_child_by_seq() - Get a child device based on a sequence + * + * If an active device has this sequence it will be returned. If there is no + * such device then this will check for a device that is requesting this + * sequence. + * + * The device is probed to activate it ready for use. + * + * @parent: Parent device + * @seq: Sequence number to find (0=first) + * @devp: Returns pointer to device (there is only one per for each seq) + * Set to NULL if none is found + * @return 0 if OK, -ve on error + */ +int device_get_child_by_seq(struct udevice *parent, int seq, + struct udevice **devp); + +/** + * device_find_child_by_of_offset() - Find a child device based on FDT offset + * + * Locates a child device by its device tree offset. + * + * @parent: Parent device + * @of_offset: Device tree offset to find + * @devp: Returns pointer to device if found, otherwise this is set to NULL + * @return 0 if OK, -ve on error + */ +int device_find_child_by_of_offset(struct udevice *parent, int of_offset, + struct udevice **devp); + +/** + * device_get_child_by_of_offset() - Get a child device based on FDT offset + * + * Locates a child device by its device tree offset. + * + * The device is probed to activate it ready for use. + * + * @parent: Parent device + * @of_offset: Device tree offset to find + * @devp: Returns pointer to device if found, otherwise this is set to NULL + * @return 0 if OK, -ve on error + */ +int device_get_child_by_of_offset(struct udevice *parent, int seq, + struct udevice **devp); + #endif diff --git a/test/dm/bus.c b/test/dm/bus.c index cfb9934..08a4725 100644 --- a/test/dm/bus.c +++ b/test/dm/bus.c @@ -61,3 +61,49 @@ static int dm_test_bus_children(struct dm_test_state *dms) return 0; } DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test our functions for accessing children */ +static int dm_test_bus_children_funcs(struct dm_test_state *dms) +{ + const void *blob = gd->fdt_blob; + struct udevice *bus, *dev; + int node; + + ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); + + /* device_get_child() */ + ut_assertok(device_get_child(bus, 0, &dev)); + ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev)); + ut_assertok(device_get_child_by_seq(bus, 5, &dev)); + ut_assert(dev->flags & DM_FLAG_ACTIVATED); + ut_asserteq_str("c-test@5", dev->name); + + /* Device with sequence number 0 should be accessible */ + ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev)); + ut_assertok(device_find_child_by_seq(bus, 0, true, &dev)); + ut_assert(!(dev->flags & DM_FLAG_ACTIVATED)); + ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev)); + ut_assertok(device_get_child_by_seq(bus, 0, &dev)); + ut_assert(dev->flags & DM_FLAG_ACTIVATED); + + /* There is no device with sequence number 2 */ + ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev)); + ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev)); + ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev)); + + /* Looking for something that is not a child */ + node = fdt_path_offset(blob, "/junk"); + ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev)); + node = fdt_path_offset(blob, "/d-test"); + ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev)); + + /* Find a valid child */ + node = fdt_path_offset(blob, "/some-bus/c-test@1"); + ut_assertok(device_find_child_by_of_offset(bus, node, &dev)); + ut_assert(!(dev->flags & DM_FLAG_ACTIVATED)); + ut_assertok(device_get_child_by_of_offset(bus, node, &dev)); + ut_assert(dev->flags & DM_FLAG_ACTIVATED); + + return 0; +} +DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);