/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
-/* The devfs code is contributed by Philipp Matthias Hahn
- <pmhahn@titan.lahn.de> */
-
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
+#include <linux/platform_device.h>
#include <asm/uaccess.h>
static struct i2c_client i2cdev_client_template;
struct i2c_dev {
int minor;
struct i2c_adapter *adap;
- struct class_device class_dev;
- struct completion released; /* FIXME, we need a class_device_unregister() */
+ struct class_device *class_dev;
};
#define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)
#define I2C_MINORS 256
static struct i2c_dev *i2c_dev_array[I2C_MINORS];
-static spinlock_t i2c_dev_array_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(i2c_dev_array_lock);
-struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
+static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
struct i2c_dev *i2c_dev;
return i2c_dev;
}
-struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
+static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev = NULL;
{
struct i2c_dev *i2c_dev;
- i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL);
+ i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
return ERR_PTR(-ENOMEM);
- memset(i2c_dev, 0x00, sizeof(*i2c_dev));
spin_lock(&i2c_dev_array_lock);
if (i2c_dev_array[adap->nr]) {
spin_unlock(&i2c_dev_array_lock);
}
-static ssize_t show_dev(struct class_device *class_dev, char *buf)
-{
- struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
- return print_dev_t(buf, MKDEV(I2C_MAJOR, i2c_dev->minor));
-}
-static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
-
static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
{
- struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
+ struct i2c_dev *i2c_dev = i2c_dev_get_by_minor(MINOR(class_dev->devt));
+
+ if (!i2c_dev)
+ return -ENODEV;
return sprintf(buf, "%s\n", i2c_dev->adap->name);
}
static CLASS_DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
return ret;
}
-int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+static int i2cdev_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = (struct i2c_client *)file->private_data;
struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_smbus_ioctl_data data_arg;
union i2c_smbus_data temp;
struct i2c_msg *rdwr_pa;
- u8 **data_ptrs;
+ u8 __user **data_ptrs;
int i,datasize,res;
unsigned long funcs;
- dev_dbg(&client->adapter->dev, "i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
- iminor(inode),cmd, arg);
+ dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
+ cmd, arg);
switch ( cmd ) {
case I2C_SLAVE:
sizeof(rdwr_arg)))
return -EFAULT;
- /* Put an arbritrary limit on the number of messages that can
+ /* Put an arbitrary limit on the number of messages that can
* be sent at once */
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
return -EFAULT;
}
- data_ptrs = (u8 **) kmalloc(rdwr_arg.nmsgs * sizeof(u8 *),
- GFP_KERNEL);
+ data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
if (data_ptrs == NULL) {
kfree(rdwr_pa);
return -ENOMEM;
res = -EINVAL;
break;
}
- data_ptrs[i] = rdwr_pa[i].buf;
+ 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;
.release = i2cdev_release,
};
-static void release_i2c_dev(struct class_device *dev)
-{
- struct i2c_dev *i2c_dev = to_i2c_dev(dev);
- complete(&i2c_dev->released);
-}
-
-static struct class i2c_dev_class = {
- .name = "i2c-dev",
- .release = &release_i2c_dev,
-};
+static struct class *i2c_dev_class;
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
- int retval;
+ struct device *dev;
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
- devfs_mk_cdev(MKDEV(I2C_MAJOR, i2c_dev->minor),
- S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i2c_dev->minor);
- dev_dbg(&adap->dev, "Registered as minor %d\n", i2c_dev->minor);
+ pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+ adap->name, i2c_dev->minor);
/* register this i2c device with the driver core */
i2c_dev->adap = adap;
- if (adap->dev.parent == &platform_bus)
- i2c_dev->class_dev.dev = &adap->dev;
- else
- i2c_dev->class_dev.dev = adap->dev.parent;
- i2c_dev->class_dev.class = &i2c_dev_class;
- snprintf(i2c_dev->class_dev.class_id, BUS_ID_SIZE, "i2c-%d", i2c_dev->minor);
- retval = class_device_register(&i2c_dev->class_dev);
- if (retval)
+ dev = &adap->dev;
+ i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL,
+ MKDEV(I2C_MAJOR, i2c_dev->minor),
+ dev, "i2c-%d", i2c_dev->minor);
+ if (!i2c_dev->class_dev)
goto error;
- class_device_create_file(&i2c_dev->class_dev, &class_device_attr_dev);
- class_device_create_file(&i2c_dev->class_dev, &class_device_attr_name);
+ class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
return 0;
error:
return_i2c_dev(i2c_dev);
kfree(i2c_dev);
- return retval;
+ return -ENODEV;
}
static int i2cdev_detach_adapter(struct i2c_adapter *adap)
if (!i2c_dev)
return -ENODEV;
- init_completion(&i2c_dev->released);
- devfs_remove("i2c/%d", i2c_dev->minor);
return_i2c_dev(i2c_dev);
- class_device_unregister(&i2c_dev->class_dev);
- wait_for_completion(&i2c_dev->released);
+ class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, i2c_dev->minor));
kfree(i2c_dev);
- dev_dbg(&adap->dev, "Adapter unregistered\n");
+ pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
return 0;
}
return 0;
}
-static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
- void *arg)
-{
- return -1;
-}
-
static struct i2c_driver i2cdev_driver = {
- .owner = THIS_MODULE,
- .name = "dev_driver",
+ .driver = {
+ .name = "dev_driver",
+ },
.id = I2C_DRIVERID_I2CDEV,
- .flags = I2C_DF_NOTIFY,
.attach_adapter = i2cdev_attach_adapter,
.detach_adapter = i2cdev_detach_adapter,
.detach_client = i2cdev_detach_client,
- .command = i2cdev_command,
};
static struct i2c_client i2cdev_client_template = {
.name = "I2C /dev entry",
- .id = 1,
.addr = -1,
.driver = &i2cdev_driver,
};
printk(KERN_INFO "i2c /dev entries driver\n");
- if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
- printk(KERN_ERR "i2c-dev.o: unable to get major %d for i2c bus\n",
- I2C_MAJOR);
- return -EIO;
- }
- devfs_mk_dir("i2c");
- class_register(&i2c_dev_class);
- if ((res = i2c_add_driver(&i2cdev_driver))) {
- printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n");
- devfs_remove("i2c");
- unregister_chrdev(I2C_MAJOR,"i2c");
- return res;
- }
+ res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
+ if (res)
+ goto out;
+
+ i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
+ if (IS_ERR(i2c_dev_class))
+ goto out_unreg_chrdev;
+
+ res = i2c_add_driver(&i2cdev_driver);
+ if (res)
+ goto out_unreg_class;
+
return 0;
+
+out_unreg_class:
+ class_destroy(i2c_dev_class);
+out_unreg_chrdev:
+ unregister_chrdev(I2C_MAJOR, "i2c");
+out:
+ printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
+ return res;
}
static void __exit i2c_dev_exit(void)
{
i2c_del_driver(&i2cdev_driver);
- class_unregister(&i2c_dev_class);
- devfs_remove("i2c");
+ class_destroy(i2c_dev_class);
unregister_chrdev(I2C_MAJOR,"i2c");
}