at v4.20 3.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/** 3 * Device connections 4 * 5 * Copyright (C) 2018 Intel Corporation 6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> 7 */ 8 9#include <linux/device.h> 10 11static DEFINE_MUTEX(devcon_lock); 12static LIST_HEAD(devcon_list); 13 14/** 15 * device_connection_find_match - Find physical connection to a device 16 * @dev: Device with the connection 17 * @con_id: Identifier for the connection 18 * @data: Data for the match function 19 * @match: Function to check and convert the connection description 20 * 21 * Find a connection with unique identifier @con_id between @dev and another 22 * device. @match will be used to convert the connection description to data the 23 * caller is expecting to be returned. 24 */ 25void *device_connection_find_match(struct device *dev, const char *con_id, 26 void *data, 27 void *(*match)(struct device_connection *con, 28 int ep, void *data)) 29{ 30 const char *devname = dev_name(dev); 31 struct device_connection *con; 32 void *ret = NULL; 33 int ep; 34 35 if (!match) 36 return NULL; 37 38 mutex_lock(&devcon_lock); 39 40 list_for_each_entry(con, &devcon_list, list) { 41 ep = match_string(con->endpoint, 2, devname); 42 if (ep < 0) 43 continue; 44 45 if (con_id && strcmp(con->id, con_id)) 46 continue; 47 48 ret = match(con, !ep, data); 49 if (ret) 50 break; 51 } 52 53 mutex_unlock(&devcon_lock); 54 55 return ret; 56} 57EXPORT_SYMBOL_GPL(device_connection_find_match); 58 59extern struct bus_type platform_bus_type; 60extern struct bus_type pci_bus_type; 61extern struct bus_type i2c_bus_type; 62extern struct bus_type spi_bus_type; 63 64static struct bus_type *generic_match_buses[] = { 65 &platform_bus_type, 66#ifdef CONFIG_PCI 67 &pci_bus_type, 68#endif 69#ifdef CONFIG_I2C 70 &i2c_bus_type, 71#endif 72#ifdef CONFIG_SPI_MASTER 73 &spi_bus_type, 74#endif 75 NULL, 76}; 77 78/* This tries to find the device from the most common bus types by name. */ 79static void *generic_match(struct device_connection *con, int ep, void *data) 80{ 81 struct bus_type *bus; 82 struct device *dev; 83 84 for (bus = generic_match_buses[0]; bus; bus++) { 85 dev = bus_find_device_by_name(bus, NULL, con->endpoint[ep]); 86 if (dev) 87 return dev; 88 } 89 90 /* 91 * We only get called if a connection was found, tell the caller to 92 * wait for the other device to show up. 93 */ 94 return ERR_PTR(-EPROBE_DEFER); 95} 96 97/** 98 * device_connection_find - Find two devices connected together 99 * @dev: Device with the connection 100 * @con_id: Identifier for the connection 101 * 102 * Find a connection with unique identifier @con_id between @dev and 103 * another device. On success returns handle to the device that is connected 104 * to @dev, with the reference count for the found device incremented. Returns 105 * NULL if no matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a 106 * connection was found but the other device has not been enumerated yet. 107 */ 108struct device *device_connection_find(struct device *dev, const char *con_id) 109{ 110 return device_connection_find_match(dev, con_id, NULL, generic_match); 111} 112EXPORT_SYMBOL_GPL(device_connection_find); 113 114/** 115 * device_connection_add - Register a connection description 116 * @con: The connection description to be registered 117 */ 118void device_connection_add(struct device_connection *con) 119{ 120 mutex_lock(&devcon_lock); 121 list_add_tail(&con->list, &devcon_list); 122 mutex_unlock(&devcon_lock); 123} 124EXPORT_SYMBOL_GPL(device_connection_add); 125 126/** 127 * device_connections_remove - Unregister connection description 128 * @con: The connection description to be unregistered 129 */ 130void device_connection_remove(struct device_connection *con) 131{ 132 mutex_lock(&devcon_lock); 133 list_del(&con->list); 134 mutex_unlock(&devcon_lock); 135} 136EXPORT_SYMBOL_GPL(device_connection_remove);