Skip to content

Commit 3cfe39b

Browse files
hkallweitWolfram Sang
authored andcommitted
i2c: Replace list-based mechanism for handling userspace-created clients
Similar to the list of auto-detected clients, we can also replace the list of userspace-created clients with flagging such client devices. Signed-off-by: Heiner Kallweit <[email protected]> [wsa: fixed description of the new flag; reordered new code in 'device_store' to have single exit point; fixed whitespace errors; folded cleanup patch into this one] Signed-off-by: Wolfram Sang <[email protected]>
1 parent 56a5066 commit 3cfe39b

File tree

2 files changed

+23
-45
lines changed

2 files changed

+23
-45
lines changed

drivers/i2c/i2c-core-base.c

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,21 +1293,28 @@ new_device_store(struct device *dev, struct device_attribute *attr,
12931293
info.flags |= I2C_CLIENT_SLAVE;
12941294
}
12951295

1296+
info.flags |= I2C_CLIENT_USER;
1297+
12961298
client = i2c_new_client_device(adap, &info);
12971299
if (IS_ERR(client))
12981300
return PTR_ERR(client);
12991301

1300-
/* Keep track of the added device */
1301-
mutex_lock(&adap->userspace_clients_lock);
1302-
list_add_tail(&client->detected, &adap->userspace_clients);
1303-
mutex_unlock(&adap->userspace_clients_lock);
13041302
dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
13051303
info.type, info.addr);
13061304

13071305
return count;
13081306
}
13091307
static DEVICE_ATTR_WO(new_device);
13101308

1309+
static int __i2c_find_user_addr(struct device *dev, void *addrp)
1310+
{
1311+
struct i2c_client *client = i2c_verify_client(dev);
1312+
unsigned short addr = *(unsigned short *)addrp;
1313+
1314+
return client && client->flags & I2C_CLIENT_USER &&
1315+
i2c_encode_flags_to_addr(client) == addr;
1316+
}
1317+
13111318
/*
13121319
* And of course let the users delete the devices they instantiated, if
13131320
* they got it wrong. This interface can only be used to delete devices
@@ -1322,7 +1329,7 @@ delete_device_store(struct device *dev, struct device_attribute *attr,
13221329
const char *buf, size_t count)
13231330
{
13241331
struct i2c_adapter *adap = to_i2c_adapter(dev);
1325-
struct i2c_client *client, *next;
1332+
struct device *child_dev;
13261333
unsigned short addr;
13271334
char end;
13281335
int res;
@@ -1338,28 +1345,19 @@ delete_device_store(struct device *dev, struct device_attribute *attr,
13381345
return -EINVAL;
13391346
}
13401347

1348+
mutex_lock(&core_lock);
13411349
/* Make sure the device was added through sysfs */
1342-
res = -ENOENT;
1343-
mutex_lock_nested(&adap->userspace_clients_lock,
1344-
i2c_adapter_depth(adap));
1345-
list_for_each_entry_safe(client, next, &adap->userspace_clients,
1346-
detected) {
1347-
if (i2c_encode_flags_to_addr(client) == addr) {
1348-
dev_info(dev, "%s: Deleting device %s at 0x%02hx\n",
1349-
"delete_device", client->name, client->addr);
1350-
1351-
list_del(&client->detected);
1352-
i2c_unregister_device(client);
1353-
res = count;
1354-
break;
1355-
}
1350+
child_dev = device_find_child(&adap->dev, &addr, __i2c_find_user_addr);
1351+
if (child_dev) {
1352+
i2c_unregister_device(i2c_verify_client(child_dev));
1353+
put_device(child_dev);
1354+
} else {
1355+
dev_err(dev, "Can't find userspace-created device at %#x\n", addr);
1356+
count = -ENOENT;
13561357
}
1357-
mutex_unlock(&adap->userspace_clients_lock);
1358+
mutex_unlock(&core_lock);
13581359

1359-
if (res < 0)
1360-
dev_err(dev, "%s: Can't find device in list\n",
1361-
"delete_device");
1362-
return res;
1360+
return count;
13631361
}
13641362
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
13651363
delete_device_store);
@@ -1530,8 +1528,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
15301528
adap->locked_flags = 0;
15311529
rt_mutex_init(&adap->bus_lock);
15321530
rt_mutex_init(&adap->mux_lock);
1533-
mutex_init(&adap->userspace_clients_lock);
1534-
INIT_LIST_HEAD(&adap->userspace_clients);
15351531

15361532
/* Set default timeout to 1 second if not already set */
15371533
if (adap->timeout == 0)
@@ -1722,7 +1718,6 @@ static int __unregister_dummy(struct device *dev, void *dummy)
17221718
void i2c_del_adapter(struct i2c_adapter *adap)
17231719
{
17241720
struct i2c_adapter *found;
1725-
struct i2c_client *client, *next;
17261721

17271722
/* First make sure that this adapter was ever added */
17281723
mutex_lock(&core_lock);
@@ -1735,18 +1730,6 @@ void i2c_del_adapter(struct i2c_adapter *adap)
17351730

17361731
i2c_acpi_remove_space_handler(adap);
17371732

1738-
/* Remove devices instantiated from sysfs */
1739-
mutex_lock_nested(&adap->userspace_clients_lock,
1740-
i2c_adapter_depth(adap));
1741-
list_for_each_entry_safe(client, next, &adap->userspace_clients,
1742-
detected) {
1743-
dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
1744-
client->addr);
1745-
list_del(&client->detected);
1746-
i2c_unregister_device(client);
1747-
}
1748-
mutex_unlock(&adap->userspace_clients_lock);
1749-
17501733
/* Detach any active clients. This can't fail, thus we do not
17511734
* check the returned value. This is a two-pass process, because
17521735
* we can't remove the dummy devices during the first pass: they

include/linux/i2c.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,6 @@ struct i2c_driver {
313313
* @dev: Driver model device node for the slave.
314314
* @init_irq: IRQ that was set at initialization
315315
* @irq: indicates the IRQ generated by this device (if any)
316-
* @detected: member of an i2c_driver.clients list or i2c-core's
317-
* userspace_devices list
318316
* @slave_cb: Callback when I2C slave mode of an adapter is used. The adapter
319317
* calls it to pass on slave events to the slave driver.
320318
* @devres_group_id: id of the devres group that will be created for resources
@@ -333,6 +331,7 @@ struct i2c_client {
333331
#define I2C_CLIENT_HOST_NOTIFY 0x40 /* We want to use I2C host notify */
334332
#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
335333
#define I2C_CLIENT_AUTO 0x100 /* client was auto-detected */
334+
#define I2C_CLIENT_USER 0x200 /* client was userspace-created */
336335
#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */
337336
/* Must match I2C_M_STOP|IGNORE_NAK */
338337

@@ -344,7 +343,6 @@ struct i2c_client {
344343
struct device dev; /* the device structure */
345344
int init_irq; /* irq set at initialization */
346345
int irq; /* irq issued by device */
347-
struct list_head detected;
348346
#if IS_ENABLED(CONFIG_I2C_SLAVE)
349347
i2c_slave_cb_t slave_cb; /* callback for slave mode */
350348
#endif
@@ -750,9 +748,6 @@ struct i2c_adapter {
750748
char name[48];
751749
struct completion dev_released;
752750

753-
struct mutex userspace_clients_lock;
754-
struct list_head userspace_clients;
755-
756751
struct i2c_bus_recovery_info *bus_recovery_info;
757752
const struct i2c_adapter_quirks *quirks;
758753

0 commit comments

Comments
 (0)