/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module. ButIhaveusedsomuchofhisoriginalcodeandideasthatitseems
only fair to recognize him as co-author -- Frodo */
/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
if (!client || client->addr != *(unsignedint *)addrp) return0;
return dev->driver ? -EBUSY : 0;
}
/* walk up mux tree */ staticint i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
{ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); int result;
result = device_for_each_child(&adapter->dev, &addr, i2cdev_check); if (!result && parent)
result = i2cdev_check_mux_parents(parent, addr);
return result;
}
/* recurse down mux tree */ staticint 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 inthatitconsidersanaddresswitharegistereddevice,butno
driver bound to it, as NOT busy. */ staticint i2cdev_check_addr(struct i2c_adapter *adapter, unsignedint addr)
{ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); int result = 0;
if (parent)
result = i2cdev_check_mux_parents(parent, addr);
if (!result)
result = device_for_each_child(&adapter->dev, &addr,
i2cdev_check_mux_children);
return result;
}
static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, unsigned nmsgs, struct i2c_msg *msgs)
{
u8 __user **data_ptrs; int i, res;
/* Adapter must support I2C transfers */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -EOPNOTSUPP;
res = 0; for (i = 0; i < nmsgs; i++) { /* Limit the size of the message to a sane amount */ if (msgs[i].len > 8192) {
res = -EINVAL; break;
}
data_ptrs[i] = (u8 __user *)msgs[i].buf;
msgs[i].buf = memdup_user(data_ptrs[i], msgs[i].len); if (IS_ERR(msgs[i].buf)) {
res = PTR_ERR(msgs[i].buf); break;
} /* memdup_user allocates with GFP_KERNEL, so DMA is ok */
msgs[i].flags |= I2C_M_DMA_SAFE;
msgs[i].len = msgs[i].buf[0];
}
} if (res < 0) { int j; for (j = 0; j < i; ++j)
kfree(msgs[j].buf);
kfree(data_ptrs); return res;
}
res = i2c_transfer(client->adapter, msgs, nmsgs); while (i-- > 0) { if (res >= 0 && (msgs[i].flags & I2C_M_RD)) { if (copy_to_user(data_ptrs[i], msgs[i].buf,
msgs[i].len))
res = -EFAULT;
}
kfree(msgs[i].buf);
}
kfree(data_ptrs); return res;
}
static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
u8 read_write, u8 command, u32 size, union i2c_smbus_data __user *data)
{ union i2c_smbus_data temp = {}; int datasize, res;
if ((size != I2C_SMBUS_BYTE) &&
(size != I2C_SMBUS_QUICK) &&
(size != I2C_SMBUS_BYTE_DATA) &&
(size != I2C_SMBUS_WORD_DATA) &&
(size != I2C_SMBUS_PROC_CALL) &&
(size != I2C_SMBUS_BLOCK_DATA) &&
(size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
(size != I2C_SMBUS_I2C_BLOCK_DATA) &&
(size != I2C_SMBUS_BLOCK_PROC_CALL)) {
dev_dbg(&client->adapter->dev, "size out of range (%x) in ioctl I2C_SMBUS.\n",
size); return -EINVAL;
} /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
so the check is valid if size==I2C_SMBUS_QUICK too. */ if ((read_write != I2C_SMBUS_READ) &&
(read_write != I2C_SMBUS_WRITE)) {
dev_dbg(&client->adapter->dev, "read_write out of range (%x) in ioctl I2C_SMBUS.\n",
read_write); return -EINVAL;
}
/* Note that command values are always valid! */
if ((size == I2C_SMBUS_QUICK) ||
((size == I2C_SMBUS_BYTE) &&
(read_write == I2C_SMBUS_WRITE))) /* These are special: we do not use data */ return i2c_smbus_xfer(client->adapter, client->addr,
client->flags, read_write,
command, size, NULL);
if (data == NULL) {
dev_dbg(&client->adapter->dev, "data is NULL pointer in ioctl I2C_SMBUS.\n"); return -EINVAL;
}
adap = i2c_get_adapter(minor); if (!adap) return -ENODEV;
/* This creates an anonymous i2c_client, which may later be *pointedtosomeaddressusingI2C_SLAVEorI2C_SLAVE_FORCE. * *Thisclientis**NEVERREGISTERED**withthedrivermodel *orI2Ccorecode!!Itjustholdsprivatecopiesofaddressing *informationandmaybeaPECflag.
*/
client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) {
i2c_put_adapter(adap); return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c"); if (res) goto out;
res = class_register(&i2c_dev_class); if (res) goto out_unreg_chrdev;
/* Keep track of adapters which will be added or removed later */
res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); if (res) goto out_unreg_class;
/* Bind to already existing adapters right away */
i2c_for_each_dev(NULL, i2c_dev_attach_adapter);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.16Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-30)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.