I2c-dev.c (drivers\i2c):module_init(i2c_dev_init);
/* ------------------------------------------------------------------------- */
/*
* module load/unload record keeping
*/
static int __init i2c_dev_init(void)
{
int res;
printk(KERN_INFO "i2c /dev entries driver\n");
res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);//注册设备号
if (res)
goto out;
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");//在/proc/devices下创建设备节点
if (IS_ERR(i2c_dev_class)) {//判断是否创建成功
res = PTR_ERR(i2c_dev_class);
goto out_unreg_chrdev;
}
/*跟踪适配器被添加或之后被删除 */
res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
if (res)
goto out_unreg_class;
/* 绑定到已经存在的适配器 */
i2c_for_each_dev(NULL, i2cdev_attach_adapter);
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;
}
res = register_chrdev(I2C_MAJOR, “i2c”, &i2cdev_fops);//注册设备号
#define I2C_MAJOR 89 /* Device major number */
static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}
将变量传递进来:
__register_chrdev(I2C_MAJOR, 0, 256, “i2c”,&i2cdev_fops);
/**
* __register_chrdev() - 创建并且注册一个占据一系列次设备号的cdev
* @major: 主设备号或者 0用于动态分配
* @baseminor:请求的一系列次设备号的第一个
* @count: 请求的次设备号的数目
* @name: 一系列设备的名字
* @fops: 与这个设备相关联的文件操作
*
* 如果@major == 0 这个函数将会动态的分配一个主设备号,然后返回具体的数字
*
* 如果 @major > 0 这个函数将会预留给设备一个给定的主设备号的
* 如果返回0表示成功
*
* 设备的名字和/dev下的设备名字没有关系。它仅仅是帮助追踪设备不同的所有者。如果你的模块名字
* 仅仅有一种类型,用这里定义的名字类型也是可以的。
*/
int __register_chrdev(unsigned int major, unsigned int baseminor,
unsigned int count, const char *name,
const struct file_operations *fops)
{
struct char_device_struct *cd;
struct cdev *cdev;
int err = -ENOMEM;
/*用特定的次设备号范围注册一个单独的主设备号*/
cd = __register_chrdev_region(major, baseminor, count, name);
if (IS_ERR(cd))
return PTR_ERR(cd);
/*分配一个cdev结构*/
cdev = cdev_alloc();
if (!cdev)
goto out2;
/*设置设备用户,文件操作指针,设备名称*/
cdev->owner = fops->owner;
cdev->ops = fops;
kobject_set_name(&cdev->kobj, "%s", name);
/*添加设备到系统中module结构体链表中,使之模块立即生效。此后文件操作,可以正常使用*/
err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
if (err)
goto out;
cd->cdev = cdev;
return major ? 0 : cd->major;
out:
kobject_put(&cdev->kobj);
out2:
kfree(__unregister_chrdev_region(cd->major, baseminor, count));
return err;
}
cdev_alloc用于分配一个cdev结构:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
重点看一下cdev_add这个函数:
/**
* cdev_add() - 给这个系统增加一个字符设备
* @p: 设备的cdev结构
* @dev:设备的第一个设备号
* @count: 这个设备指向的连续次设备号的数目
*/
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
p->count = count;
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}
int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
struct module *module, kobj_probe_t *probe,
int (*lock)(dev_t, void *), void *data)
{
unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
unsigned index = MAJOR(dev);
unsigned i;
struct probe *p;
if (n > 255)
n = 255;
p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);
if (p == NULL)
return -ENOMEM;
for (i = 0; i < n; i++, p++) {
p->owner = module;
p->get = probe;
p->lock = lock;
p->dev = dev;
p->range = range;
p->data = data;
}
mutex_lock(domain->lock);
for (i = 0, p -= n; i < n; i++, p++, index++) {
struct probe **s = &domain->probes[index % 255];
while (*s && (*s)->range < range)
s = &(*s)->next;
p->next = *s;
*s = p;
}
mutex_unlock(domain->lock);
return 0;
}