Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c00650c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  i2c: I2C bus multiplexer driver pca954x
  i2c: Multiplexed I2C bus core support
  i2c: Use a separate mutex for userspace client lists
  i2c: Make i2c_default_probe self-sufficient
  i2c: Drop dummy variable
  i2c: Move adapter locking helpers to i2c-core
  V4L/DVB: Use custom I2C probing function mechanism
  i2c: Add support for custom probe function
  i2c-dev: Use memdup_user
  i2c-dev: Remove unnecessary kmalloc casts
parents 26df0766 7f528135
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
	strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
						   normal_i2c);
						   normal_i2c, NULL);
	i2c_put_adapter(i2c_adap);
	(...)
}
+13 −0
Original line number Diff line number Diff line
@@ -47,6 +47,19 @@ config I2C_CHARDEV
	  This support is also available as a module.  If so, the module 
	  will be called i2c-dev.

config I2C_MUX
	tristate "I2C bus multiplexing support"
	depends on EXPERIMENTAL
	help
	  Say Y here if you want the I2C core to support the ability to
	  handle multiplexed I2C bus topologies, by presenting each
	  multiplexed segment as a I2C adapter.

	  This support is also available as a module.  If so, the module
	  will be called i2c-mux.

source drivers/i2c/muxes/Kconfig

config I2C_HELPER_AUTO
	bool "Autoselect pertinent helper modules"
	default y
+2 −1
Original line number Diff line number Diff line
@@ -6,7 +6,8 @@ obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C)		+= i2c-core.o
obj-$(CONFIG_I2C_SMBUS)		+= i2c-smbus.o
obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
obj-y				+= algos/ busses/
obj-$(CONFIG_I2C_MUX)		+= i2c-mux.o
obj-y				+= algos/ busses/ muxes/

ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
EXTRA_CFLAGS += -DDEBUG
+118 −40
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
   All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
   SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
   Jean Delvare <khali@linux-fr.org> */
   Jean Delvare <khali@linux-fr.org>
   Mux support by Rodolfo Giometti <giometti@enneenne.com> and
   Michael Lawnick <michael.lawnick.ext@nsn.com> */

#include <linux/module.h>
#include <linux/kernel.h>
@@ -423,12 +425,88 @@ static int __i2c_check_addr_busy(struct device *dev, void *addrp)
	return 0;
}

static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
/* walk up mux tree */
static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr)
{
	return device_for_each_child(&adapter->dev, &addr,
	int result;

	result = device_for_each_child(&adapter->dev, &addr,
					__i2c_check_addr_busy);

	if (!result && i2c_parent_is_i2c_adapter(adapter))
		result = i2c_check_mux_parents(
				    to_i2c_adapter(adapter->dev.parent), addr);

	return result;
}

/* recurse down mux tree */
static int i2c_check_mux_children(struct device *dev, void *addrp)
{
	int result;

	if (dev->type == &i2c_adapter_type)
		result = device_for_each_child(dev, addrp,
						i2c_check_mux_children);
	else
		result = __i2c_check_addr_busy(dev, addrp);

	return result;
}

static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
{
	int result = 0;

	if (i2c_parent_is_i2c_adapter(adapter))
		result = i2c_check_mux_parents(
				    to_i2c_adapter(adapter->dev.parent), addr);

	if (!result)
		result = device_for_each_child(&adapter->dev, &addr,
						i2c_check_mux_children);

	return result;
}

/**
 * i2c_lock_adapter - Get exclusive access to an I2C bus segment
 * @adapter: Target I2C bus segment
 */
void i2c_lock_adapter(struct i2c_adapter *adapter)
{
	if (i2c_parent_is_i2c_adapter(adapter))
		i2c_lock_adapter(to_i2c_adapter(adapter->dev.parent));
	else
		rt_mutex_lock(&adapter->bus_lock);
}
EXPORT_SYMBOL_GPL(i2c_lock_adapter);

/**
 * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
 * @adapter: Target I2C bus segment
 */
static int i2c_trylock_adapter(struct i2c_adapter *adapter)
{
	if (i2c_parent_is_i2c_adapter(adapter))
		return i2c_trylock_adapter(to_i2c_adapter(adapter->dev.parent));
	else
		return rt_mutex_trylock(&adapter->bus_lock);
}

/**
 * i2c_unlock_adapter - Release exclusive access to an I2C bus segment
 * @adapter: Target I2C bus segment
 */
void i2c_unlock_adapter(struct i2c_adapter *adapter)
{
	if (i2c_parent_is_i2c_adapter(adapter))
		i2c_unlock_adapter(to_i2c_adapter(adapter->dev.parent));
	else
		rt_mutex_unlock(&adapter->bus_lock);
}
EXPORT_SYMBOL_GPL(i2c_unlock_adapter);

/**
 * i2c_new_device - instantiate an i2c device
 * @adap: the adapter managing the device
@@ -633,9 +711,9 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
		return -EINVAL;

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

@@ -674,7 +752,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,

	/* Make sure the device was added through sysfs */
	res = -ENOENT;
	i2c_lock_adapter(adap);
	mutex_lock(&adap->userspace_clients_lock);
	list_for_each_entry_safe(client, next, &adap->userspace_clients,
				 detected) {
		if (client->addr == addr) {
@@ -687,7 +765,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
			break;
		}
	}
	i2c_unlock_adapter(adap);
	mutex_unlock(&adap->userspace_clients_lock);

	if (res < 0)
		dev_err(dev, "%s: Can't find device in list\n",
@@ -714,10 +792,11 @@ static const struct attribute_group *i2c_adapter_attr_groups[] = {
	NULL
};

static struct device_type i2c_adapter_type = {
struct device_type i2c_adapter_type = {
	.groups		= i2c_adapter_attr_groups,
	.release	= i2c_adapter_dev_release,
};
EXPORT_SYMBOL_GPL(i2c_adapter_type);

#ifdef CONFIG_I2C_COMPAT
static struct class_compat *i2c_adapter_compat_class;
@@ -760,7 +839,7 @@ static int __process_new_adapter(struct device_driver *d, void *data)

static int i2c_register_adapter(struct i2c_adapter *adap)
{
	int res = 0, dummy;
	int res = 0;

	/* Can't register until after driver model init */
	if (unlikely(WARN_ON(!i2c_bus_type.p))) {
@@ -769,6 +848,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
	}

	rt_mutex_init(&adap->bus_lock);
	mutex_init(&adap->userspace_clients_lock);
	INIT_LIST_HEAD(&adap->userspace_clients);

	/* Set default timeout to 1 second if not already set */
@@ -801,8 +881,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)

	/* Notify drivers */
	mutex_lock(&core_lock);
	dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
				 __process_new_adapter);
	bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
	mutex_unlock(&core_lock);

	return 0;
@@ -975,7 +1054,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
		return res;

	/* Remove devices instantiated from sysfs */
	i2c_lock_adapter(adap);
	mutex_lock(&adap->userspace_clients_lock);
	list_for_each_entry_safe(client, next, &adap->userspace_clients,
				 detected) {
		dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
@@ -983,7 +1062,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
		list_del(&client->detected);
		i2c_unregister_device(client);
	}
	i2c_unlock_adapter(adap);
	mutex_unlock(&adap->userspace_clients_lock);

	/* Detach any active clients. This can't fail, thus we do not
	   checking the returned value. */
@@ -1238,12 +1317,12 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
#endif

		if (in_atomic() || irqs_disabled()) {
			ret = rt_mutex_trylock(&adap->bus_lock);
			ret = i2c_trylock_adapter(adap);
			if (!ret)
				/* I2C activity is ongoing. */
				return -EAGAIN;
		} else {
			rt_mutex_lock(&adap->bus_lock);
			i2c_lock_adapter(adap);
		}

		/* Retry automatically on arbitration loss */
@@ -1255,7 +1334,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
			if (time_after(jiffies, orig_jiffies + adap->timeout))
				break;
		}
		rt_mutex_unlock(&adap->bus_lock);
		i2c_unlock_adapter(adap);

		return ret;
	} else {
@@ -1350,13 +1429,17 @@ static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr)
				     I2C_SMBUS_BYTE_DATA, &dummy);
	else
#endif
	if ((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50
	 || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
				     I2C_SMBUS_BYTE, &dummy);
	else
	if (!((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50)
	 && i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0,
				     I2C_SMBUS_QUICK, NULL);
	else if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE))
		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
				     I2C_SMBUS_BYTE, &dummy);
	else {
		dev_warn(&adap->dev, "No suitable probing method supported\n");
		err = -EOPNOTSUPP;
	}

	return err >= 0;
}
@@ -1437,16 +1520,6 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
	if (!(adapter->class & driver->class))
		goto exit_free;

	/* Stop here if the bus doesn't support probing */
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE)) {
		if (address_list[0] == I2C_CLIENT_END)
			goto exit_free;

		dev_warn(&adapter->dev, "Probing not supported\n");
		err = -EOPNOTSUPP;
		goto exit_free;
	}

	for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
		dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
			"addr 0x%02x\n", adap_id, address_list[i]);
@@ -1461,18 +1534,23 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
	return err;
}

int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr)
{
	return i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
			      I2C_SMBUS_QUICK, NULL) >= 0;
}
EXPORT_SYMBOL_GPL(i2c_probe_func_quick_read);

struct i2c_client *
i2c_new_probed_device(struct i2c_adapter *adap,
		      struct i2c_board_info *info,
		      unsigned short const *addr_list)
		      unsigned short const *addr_list,
		      int (*probe)(struct i2c_adapter *, unsigned short addr))
{
	int i;

	/* Stop here if the bus doesn't support probing */
	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) {
		dev_err(&adap->dev, "Probing not supported\n");
		return NULL;
	}
	if (!probe)
		probe = i2c_default_probe;

	for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
		/* Check address validity */
@@ -1490,7 +1568,7 @@ i2c_new_probed_device(struct i2c_adapter *adap,
		}

		/* Test address responsiveness */
		if (i2c_default_probe(adap, addr_list[i]))
		if (probe(adap, addr_list[i]))
			break;
	}

@@ -2002,7 +2080,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
	flags &= I2C_M_TEN | I2C_CLIENT_PEC;

	if (adapter->algo->smbus_xfer) {
		rt_mutex_lock(&adapter->bus_lock);
		i2c_lock_adapter(adapter);

		/* Retry automatically on arbitration loss */
		orig_jiffies = jiffies;
@@ -2016,7 +2094,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
				       orig_jiffies + adapter->timeout))
				break;
		}
		rt_mutex_unlock(&adapter->bus_lock);
		i2c_unlock_adapter(adapter);
	} else
		res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
					      command, protocol, data);
+46 −20
Original line number Diff line number Diff line
@@ -167,13 +167,9 @@ static ssize_t i2cdev_write(struct file *file, const char __user *buf,
	if (count > 8192)
		count = 8192;

	tmp = kmalloc(count, GFP_KERNEL);
	if (tmp == NULL)
		return -ENOMEM;
	if (copy_from_user(tmp, buf, count)) {
		kfree(tmp);
		return -EFAULT;
	}
	tmp = memdup_user(buf, count);
	if (IS_ERR(tmp))
		return PTR_ERR(tmp);

	pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
		iminor(file->f_path.dentry->d_inode), count);
@@ -193,12 +189,50 @@ static int i2cdev_check(struct device *dev, void *addrp)
	return dev->driver ? -EBUSY : 0;
}

/* walk up mux tree */
static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
{
	int result;

	result = device_for_each_child(&adapter->dev, &addr, i2cdev_check);

	if (!result && i2c_parent_is_i2c_adapter(adapter))
		result = i2cdev_check_mux_parents(
				    to_i2c_adapter(adapter->dev.parent), addr);

	return result;
}

/* recurse down mux tree */
static int i2cdev_check_mux_children(struct device *dev, void *addrp)
{
	int result;

	if (dev->type == &i2c_adapter_type)
		result = device_for_each_child(dev, addrp,
						i2cdev_check_mux_children);
	else
		result = i2cdev_check(dev, addrp);

	return result;
}

/* This address checking function differs from the one in i2c-core
   in that it considers an address with a registered device, but no
   driver bound to it, as NOT busy. */
static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
{
	return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
	int result = 0;

	if (i2c_parent_is_i2c_adapter(adapter))
		result = i2cdev_check_mux_parents(
				    to_i2c_adapter(adapter->dev.parent), addr);

	if (!result)
		result = device_for_each_child(&adapter->dev, &addr,
						i2cdev_check_mux_children);

	return result;
}

static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
@@ -219,9 +253,7 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
	if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
		return -EINVAL;

	rdwr_pa = (struct i2c_msg *)
		kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
		GFP_KERNEL);
	rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
	if (!rdwr_pa)
		return -ENOMEM;

@@ -247,15 +279,9 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
			break;
		}
		data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
		rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
		if (rdwr_pa[i].buf == NULL) {
			res = -ENOMEM;
			break;
		}
		if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
				   rdwr_pa[i].len)) {
				++i; /* Needs to be kfreed too */
				res = -EFAULT;
		rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
		if (IS_ERR(rdwr_pa[i].buf)) {
			res = PTR_ERR(rdwr_pa[i].buf);
			break;
		}
	}
Loading