123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- // SPDX-License-Identifier: GPL-2.0
- /**
- * Device connections
- *
- * Copyright (C) 2018 Intel Corporation
- * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
- */
- #include <linux/device.h>
- static DEFINE_MUTEX(devcon_lock);
- static LIST_HEAD(devcon_list);
- /**
- * device_connection_find_match - Find physical connection to a device
- * @dev: Device with the connection
- * @con_id: Identifier for the connection
- * @data: Data for the match function
- * @match: Function to check and convert the connection description
- *
- * Find a connection with unique identifier @con_id between @dev and another
- * device. @match will be used to convert the connection description to data the
- * caller is expecting to be returned.
- */
- void *device_connection_find_match(struct device *dev, const char *con_id,
- void *data,
- void *(*match)(struct device_connection *con,
- int ep, void *data))
- {
- const char *devname = dev_name(dev);
- struct device_connection *con;
- void *ret = NULL;
- int ep;
- if (!match)
- return NULL;
- mutex_lock(&devcon_lock);
- list_for_each_entry(con, &devcon_list, list) {
- ep = match_string(con->endpoint, 2, devname);
- if (ep < 0)
- continue;
- if (con_id && strcmp(con->id, con_id))
- continue;
- ret = match(con, !ep, data);
- if (ret)
- break;
- }
- mutex_unlock(&devcon_lock);
- return ret;
- }
- EXPORT_SYMBOL_GPL(device_connection_find_match);
- extern struct bus_type platform_bus_type;
- extern struct bus_type pci_bus_type;
- extern struct bus_type i2c_bus_type;
- extern struct bus_type spi_bus_type;
- static struct bus_type *generic_match_buses[] = {
- &platform_bus_type,
- #ifdef CONFIG_PCI
- &pci_bus_type,
- #endif
- #ifdef CONFIG_I2C
- &i2c_bus_type,
- #endif
- #ifdef CONFIG_SPI_MASTER
- &spi_bus_type,
- #endif
- NULL,
- };
- /* This tries to find the device from the most common bus types by name. */
- static void *generic_match(struct device_connection *con, int ep, void *data)
- {
- struct bus_type *bus;
- struct device *dev;
- for (bus = generic_match_buses[0]; bus; bus++) {
- dev = bus_find_device_by_name(bus, NULL, con->endpoint[ep]);
- if (dev)
- return dev;
- }
- /*
- * We only get called if a connection was found, tell the caller to
- * wait for the other device to show up.
- */
- return ERR_PTR(-EPROBE_DEFER);
- }
- /**
- * device_connection_find - Find two devices connected together
- * @dev: Device with the connection
- * @con_id: Identifier for the connection
- *
- * Find a connection with unique identifier @con_id between @dev and
- * another device. On success returns handle to the device that is connected
- * to @dev, with the reference count for the found device incremented. Returns
- * NULL if no matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a
- * connection was found but the other device has not been enumerated yet.
- */
- struct device *device_connection_find(struct device *dev, const char *con_id)
- {
- return device_connection_find_match(dev, con_id, NULL, generic_match);
- }
- EXPORT_SYMBOL_GPL(device_connection_find);
- /**
- * device_connection_add - Register a connection description
- * @con: The connection description to be registered
- */
- void device_connection_add(struct device_connection *con)
- {
- mutex_lock(&devcon_lock);
- list_add_tail(&con->list, &devcon_list);
- mutex_unlock(&devcon_lock);
- }
- EXPORT_SYMBOL_GPL(device_connection_add);
- /**
- * device_connections_remove - Unregister connection description
- * @con: The connection description to be unregistered
- */
- void device_connection_remove(struct device_connection *con)
- {
- mutex_lock(&devcon_lock);
- list_del(&con->list);
- mutex_unlock(&devcon_lock);
- }
- EXPORT_SYMBOL_GPL(device_connection_remove);
|