i2c 驱动程序是否需要像任何其他字符设备驱动程序一样实现?
Does i2c driver need to be implemented just like any other character device driver?
我是 Linux 设备驱动程序的菜鸟,所以请多多包涵。我正在尝试实现一个 i2c 驱动程序(客户端)。这是我可以 insmod
、.probe
被调用(因为设备树条目)并且在 .probe 中我可以 read/write 到设备的地方。太好了。
但是我需要能够启动从用户空间到驱动程序的 read/writes。为了做到这一点,i2c 驱动程序的形状是否应该像任何其他字符设备驱动程序一样?意味着具有 file_operations
结构,因此用户空间可以 open
、close
、read
、write
和 ioctls
?
我问是因为在我见过的所有 i2c 客户端示例中,没有人实现了我提到的这些东西。我想知道他们是如何在没有设置 file_operations
结构的情况下从用户空间发起调用的。也许它是如此明显以至于没有人提到它,我不知道......我想知道是否因为 i2c 被称为平台设备驱动程序它不需要这个?如果有人可以确认这将帮助我重新猜测自己。
如果您明白我在问什么,请忽略其余部分。如果您对我的问题感到困惑,这里是对我所问内容的更具体解释:
我现在拥有的是:
static int device_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_data *data;
/* Check the functionality of the i2c-adapter for smbus byte read/write */
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
{
printk(KERN_ALERT "%s %d: device required i2c functionality is not supported\n", __func__, __LINE__);
return -ENODEV;
}
/* Allocate memory to hold the device data
* Using devm_kzalloc so do not have to worry about kfree */
data = devm_kzalloc(dev, sizeof(struct device_data), GFP_KERNEL);
if (dev == NULL)
{
printk(KERN_ALERT "%s %d: no memory\n", __func__, __LINE__);
return -ENOMEM;
}
/* Record the pointer to current client */
data->device_i2c_client = client;
/* Set the client's data field to point to device-specific data struct */
i2c_set_clientdata(client, data);
/* Add the device-specific data struct to our collection of device client devices */
device_data_tbl[id->driver_data] = data;
/* Do a read, test the access */
device_read();
return 0;
}
static int device_remove(struct i2c_client *client)
{
return 0;
}
int device_read(uint8_t device_device_id,
uint16_t const dev_reg_addr,
uint8_t *const read_val)
{
/* some read access */
}
static struct i2c_device_id device_idtable[] = {
{ "si5342", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, device_idtable);
static struct i2c_driver device_driver = {
.driver = {
.name = device_DRIVER_NAME,
.owner = THIS_MODULE
},
.id_table = device_idtable,
.probe = device_probe,
.remove = device_remove,
};
static int __init device_driver_init(void)
{
return i2c_add_driver(&device_driver);
}
module_init(device_driver_init);
static void __exit device_driver_exit(void)
{
return i2c_del_driver(&device_driver);
}
module_exit(device_driver_exit);
想知道是否需要在中添加以下元素
static struct file_operations oxdrv_fops =
{
.owner = THIS_MODULE,
.release = device_release,
.open = device_open,
.unlocked_ioctl = device_ioctl
};
/* Associated function definitions: device_open, device_ioctl, etc */
alloc_chrdev_region();
cdev_init();
我想我现在通过@Alexandre Belloni 的评论和阅读这组演示幻灯片更好地理解了设备驱动程序模型:http://free-electrons.com/doc/training/linux-kernel/linux-kernel-slides.pdf。相关幻灯片从第 221 页到第 236 页。
有 3 种类型的设备驱动程序:
- 字符
- 网络
- 阻止
但是,有特定的 "frameworks" 作为字符设备驱动程序的子类存在,它实现了相同类型设备驱动程序的公共部分。
例如,主板上用于硬件监控的温度传感器将在 hwmon 框架下注册 (https://www.kernel.org/doc/Documentation/hwmon/hwmon-kernel-api.txt)。您将实现 i2c probe
、read
、write
功能,而不是将它塑造成具有 file_operations struct
的字符设备,您只需要将其注册为 hwmon 设备: hwmon_device_register_with_groups()
。要暴露给用户空间,你需要使用 attributes
和你想要的暴露的 read/write 命令列表来构建你的 /sys/class/hwmon/hwmon*
目录(例如:从通道 1 读取温度,写入限制温度寄存器) .
构建内核时,select 您的设备 make menuconfig
以便与内核一起构建。有了这个,一旦你启动内核,设备就会出现在 /sys/class/hwmon/hwmon*
下,然后用户空间可以通过 sysfs 接口从设备 open
和 read
。
在这里看到一个很好的例子:http://lxr.free-electrons.com/source/drivers/hwmon/tmp421.c。或 hwmon 目录中的任何设备。
这就是我的困惑所在。正如@Alexandre Belloni 指出的那样,这些设备是在一个框架下注册的,因此不需要显式的字符设备驱动程序代码。对我来说情况并非如此,我认为我正在做的设备(时钟 PLL)没有合适的框架。因此,我将需要走一般路线并将其实现为字符设备。这也将允许我 load/unload 作为一个模块,而不是在内核启动期间自动加载它。
请随时纠正我犯的任何错误。我希望这对其他对编写 i2c 客户端感到困惑的人有所帮助。
我是 Linux 设备驱动程序的菜鸟,所以请多多包涵。我正在尝试实现一个 i2c 驱动程序(客户端)。这是我可以 insmod
、.probe
被调用(因为设备树条目)并且在 .probe 中我可以 read/write 到设备的地方。太好了。
但是我需要能够启动从用户空间到驱动程序的 read/writes。为了做到这一点,i2c 驱动程序的形状是否应该像任何其他字符设备驱动程序一样?意味着具有 file_operations
结构,因此用户空间可以 open
、close
、read
、write
和 ioctls
?
我问是因为在我见过的所有 i2c 客户端示例中,没有人实现了我提到的这些东西。我想知道他们是如何在没有设置 file_operations
结构的情况下从用户空间发起调用的。也许它是如此明显以至于没有人提到它,我不知道......我想知道是否因为 i2c 被称为平台设备驱动程序它不需要这个?如果有人可以确认这将帮助我重新猜测自己。
如果您明白我在问什么,请忽略其余部分。如果您对我的问题感到困惑,这里是对我所问内容的更具体解释:
我现在拥有的是:
static int device_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_data *data;
/* Check the functionality of the i2c-adapter for smbus byte read/write */
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
{
printk(KERN_ALERT "%s %d: device required i2c functionality is not supported\n", __func__, __LINE__);
return -ENODEV;
}
/* Allocate memory to hold the device data
* Using devm_kzalloc so do not have to worry about kfree */
data = devm_kzalloc(dev, sizeof(struct device_data), GFP_KERNEL);
if (dev == NULL)
{
printk(KERN_ALERT "%s %d: no memory\n", __func__, __LINE__);
return -ENOMEM;
}
/* Record the pointer to current client */
data->device_i2c_client = client;
/* Set the client's data field to point to device-specific data struct */
i2c_set_clientdata(client, data);
/* Add the device-specific data struct to our collection of device client devices */
device_data_tbl[id->driver_data] = data;
/* Do a read, test the access */
device_read();
return 0;
}
static int device_remove(struct i2c_client *client)
{
return 0;
}
int device_read(uint8_t device_device_id,
uint16_t const dev_reg_addr,
uint8_t *const read_val)
{
/* some read access */
}
static struct i2c_device_id device_idtable[] = {
{ "si5342", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, device_idtable);
static struct i2c_driver device_driver = {
.driver = {
.name = device_DRIVER_NAME,
.owner = THIS_MODULE
},
.id_table = device_idtable,
.probe = device_probe,
.remove = device_remove,
};
static int __init device_driver_init(void)
{
return i2c_add_driver(&device_driver);
}
module_init(device_driver_init);
static void __exit device_driver_exit(void)
{
return i2c_del_driver(&device_driver);
}
module_exit(device_driver_exit);
想知道是否需要在中添加以下元素
static struct file_operations oxdrv_fops =
{
.owner = THIS_MODULE,
.release = device_release,
.open = device_open,
.unlocked_ioctl = device_ioctl
};
/* Associated function definitions: device_open, device_ioctl, etc */
alloc_chrdev_region();
cdev_init();
我想我现在通过@Alexandre Belloni 的评论和阅读这组演示幻灯片更好地理解了设备驱动程序模型:http://free-electrons.com/doc/training/linux-kernel/linux-kernel-slides.pdf。相关幻灯片从第 221 页到第 236 页。
有 3 种类型的设备驱动程序:
- 字符
- 网络
- 阻止
但是,有特定的 "frameworks" 作为字符设备驱动程序的子类存在,它实现了相同类型设备驱动程序的公共部分。
例如,主板上用于硬件监控的温度传感器将在 hwmon 框架下注册 (https://www.kernel.org/doc/Documentation/hwmon/hwmon-kernel-api.txt)。您将实现 i2c probe
、read
、write
功能,而不是将它塑造成具有 file_operations struct
的字符设备,您只需要将其注册为 hwmon 设备: hwmon_device_register_with_groups()
。要暴露给用户空间,你需要使用 attributes
和你想要的暴露的 read/write 命令列表来构建你的 /sys/class/hwmon/hwmon*
目录(例如:从通道 1 读取温度,写入限制温度寄存器) .
构建内核时,select 您的设备 make menuconfig
以便与内核一起构建。有了这个,一旦你启动内核,设备就会出现在 /sys/class/hwmon/hwmon*
下,然后用户空间可以通过 sysfs 接口从设备 open
和 read
。
在这里看到一个很好的例子:http://lxr.free-electrons.com/source/drivers/hwmon/tmp421.c。或 hwmon 目录中的任何设备。
这就是我的困惑所在。正如@Alexandre Belloni 指出的那样,这些设备是在一个框架下注册的,因此不需要显式的字符设备驱动程序代码。对我来说情况并非如此,我认为我正在做的设备(时钟 PLL)没有合适的框架。因此,我将需要走一般路线并将其实现为字符设备。这也将允许我 load/unload 作为一个模块,而不是在内核启动期间自动加载它。
请随时纠正我犯的任何错误。我希望这对其他对编写 i2c 客户端感到困惑的人有所帮助。