- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在尝试为嵌入式板开发驱动程序。驱动程序应该为 v4l2 打开一个接口(interface)并使用 i2c 与 2 个设备通信。司机将充当主人。
我似乎无法理解i2c_device_id
数组和i2c_add_driver
函数是如何工作的。我阅读了内核源代码中的文档,但它对我在多个从属客户端上没有帮助。
i2c_add_driver
两次吗? 我在这里粘贴我的代码。我尝试实例化了两个i2c_drivers
,分别调用了两次i2c_driver_add
并分别实现了i2c probe。第二次调用 i2c_add_driver
时,代码无法告诉我 foo1
已经注册。
我在我的 dts 文件中的 i2c1
下定义了两个 block ,例如:
&i2c1 {
...
foo0: foo0@00 {
compatible = "bar,foo0";
reg = <0x00>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu1_2>;
clocks = <&clks IMX6QDL_CLK_CKO>;
clock-names = "csi_mclk";
DOVDD-supply = <&vgen4_reg>; /* 1.8v */
AVDD-supply = <&vgen3_reg>; /* 2.8v, on rev C board is VGEN3,
on rev B board is VGEN5 */
DVDD-supply = <&vgen2_reg>; /* 1.5v*/
pwn-gpios = <&gpio1 16 1>; /* active low: SD1_DAT0 */
rst-gpios = <&gpio1 17 0>; /* active high: SD1_DAT1 */
csi_id = <0>;
mclk = <24000000>;
mclk_source = <0>;
};
foo1: foo1@02 {
compatible = "bar, foo1";
reg = <0x02>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu1_2>;
clocks = <&clks IMX6QDL_CLK_CKO>;
clock-names = "csi_mclk";
DOVDD-supply = <&vgen4_reg>; /* 1.8v */
AVDD-supply = <&vgen3_reg>; /* 2.8v, on rev C board is VGEN3,
on rev B board is VGEN5 */
DVDD-supply = <&vgen2_reg>; /* 1.5v*/
pwn-gpios = <&gpio1 16 1>; /* active low: SD1_DAT0 */
rst-gpios = <&gpio1 17 0>; /* active high: SD1_DAT1 */
csi_id = <0>;
mclk = <24000000>;
mclk_source = <0>;
};
...
两个 block 完全一样,除了它们的名字。
在驱动程序文件中,我实例化了以下结构:
static const struct i2c_device_id foo_id[] = {
{"foo0", 0},
{"foo1", 1},
{},
};
static struct i2c_driver foo0_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "foo0",
},
.probe = foo0_probe,
.remove = foo0_remove,
.id_table = foo_id,
};
static struct i2c_driver foo1_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "foo1",
},
.probe = foo1_probe,
.remove = foo1_remove,
.id_table = foo_id,
};
下面是我的init
和exit
函数:
MODULE_DEVICE_TABLE(i2c, foo_id);
static __init int foo_init(void)
{
u8 err;
err = i2c_add_driver(&foo0_i2c_driver);
if (err != 0)
pr_err("%s:driver registration failed i2c-slave0, error=%d\n",
__func__, err);
err = i2c_add_driver(&foo1_i2c_driver);
if (err != 0)
pr_err("%s:driver registration failed i2c-slave1, error=%d\n",
__func__, err);
return err;
}
static void __exit foo_clean(void)
{
if((&foo0_i2c_driver) != NULL && i2c0initialized)
{
i2c_del_driver(&foo0_i2c_driver);
i2c0initialized = 0;
}
if((&foo1_i2c_driver) != NULL && i2c1initialized)
{
i2c_del_driver(&foo1_i2c_driver);
i2c1initialized = 0;
}
}
module_init(foo_init);
module_exit(foo_clean);
下面是我的 probe
函数。我为两个奴隶准备了两份副本。
static int foo_probe(struct i2c_client *client,
const struct i2c_device_id *device_id)
{
struct pinctrl *pinctrls;
struct device *dev = &client->dev;
int ret = 0;
pinctrls = devm_pinctrl_get_select_default(dev);
if(IS_ERR(pinctrls))
{
dev_err(dev, "pinctrl setup failed\n");
return PTR_ERR(pinctrls);
}
memset(&foo_data, 0, sizeof(foo_data));
foo_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
if(IS_ERR(foo_data.sensor_clk))
{
dev_err(dev, "get mclk failed\n");
return PTR_ERR(foo_data.sensor_clk);
}
ret = of_property_read_u32(dev->of_node, "mclk", &(foo_data.mclk));
if(ret < 0)
{
dev_err(dev, "mclk frequency is invalid\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "mclk_source",
(u32 *)&(foo_data.mclk_source));
if(ret < 0)
{
dev_err(dev, "mclk source is invalid\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "csi_id", &(foo_data.csi));
if(ret < 0)
{
dev_err(dev, "csi_id invalid\n");
return ret;
}
clk_prepare_enable(foo_data.sensor_clk);
i2c_client0 = client;
/* custom data structures are set here */
foo_reset();
ret = foo_get_id();
if(ret < 0 /* || ret != foo_ID */)
{
clk_disable_unprepare(foo_data.sensor_clk);
pr_warning("foo is not found\n");
return -ENODEV;
}
clk_disable_unprepare(foo_data.sensor_clk);
foo_int_device.priv = &foo_data;
ret = v4l2_int_device_register(&foo_int_device);
pr_info("foo is found\n");
i2c0initialized = 1;
return ret;
}
最佳答案
这个答案晚了 5 个月,但希望它能帮助遇到同样问题(和我一样)但找不到合适答案的其他人。
简而言之解决方案就是用一个minor number来代表每个slave。您的驱动程序将在您存储的客户端列表中查找该次要编号以获得正确的 i2c_client。
长版您的 I2C 驱动程序最终可能是这种独特设备的字符设备驱动程序。否则,框架(例如 hwmon)可能已经实现,并且框架已经完成了处理多个从站的工作,因此您不必担心。参见 http://lxr.free-electrons.com/source/drivers/hwmon/例如。
现在假设它是一个字符设备驱动程序,在您的驱动程序 __init 中,您需要分配与从设备一样多的次设备号:
alloc_chrdev_region(&dev, *MINOR_START*, *NUM_DEVICES*, name)
/* for each minor or slave device, do cdev_init and cdev_add */
现在进入您的MODULE_DEVICE_TABLE
。为每个从站输入条目,记住字符串必须与设备树兼容条目相匹配。第二个字段是一个数字,我们将把它用作唯一标识符和次要数字(这就是诀窍):
struct i2c_device_id foo_idtable[] = {
{ "foo_1", 0 },
{ "foo_2", 1 },
{ },
};
MODULE_DEVICE_TABLE(i2c, foo_idtable);
好的,您的 .probe
函数将为每个匹配的设备树条目调用。当调用 .probe
函数时,Linux 会传入它为您实例化的 i2c_client 指针。这是技巧的另一部分,有一个全局表来存储这些单独的 i2c_client 指针。全局表的索引是次要编号。 minor number就是同样传入的id->driver_data
,也就是你之前在foo_idtable
中分配的编号。
static int foo_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
/* Store the i2c_client pointer in a global table using minor number as index
* make sure to allocate the global table dynamically */
that_table[id->driver_data] = client;
/* The id->driver_data is the minor number! */
}
希望你现在 catch 了。当你 insmod 你的 .ko 时,你想要制作多个节点,每个节点对应一个次要编号:
insmod foo.ko
make_dir /dev/foo
find_major foo
make_node /dev/foo/foo_0 c <major> 0
make_node /dev/foo/foo_1 c <major> 1
现在,当您的用户空间代码尝试使用您的驱动程序时,它将打开与正确的次要编号(从属设备)相对应的文件。在用户空间你会做这样的事情:
/* Accessing slave #0 */
int fd = open("/dev/foo/foo_0", O_RDWR);
/* Accessing slave #1 */
int fd_1 = open("/dev/foo/foo_1", O_RDWR);
您的 .open 实现将被调用。
static int foo_driver_open(struct inode *inode, struct file *filep)
{
int minor_num = MINOR(inode->i_rdev);
/* remember the global table we had before that was indexed using the minor number?
* Let's get the i2c_client stored there and get filep->private_data
* to point to that i2c_client. Then subsequent read/write/ioctl can just
* obtain the i2c_client from filep->private_data */
filep->private_data = that_table[minor_num];
}
例如,您的用户空间代码调用驱动程序的 ioctl:
ioctl(fd, FOO_IOCTL_DO_READ, &msg);
ioctl(fd_1, FOO_IOCTL_DO_WRITE, &msg);
在您的驱动程序的 ioctl 实现中:
long foo_driver_ioctl(struct file *filep, unsinged int cmd, unsigned long arg)
{
/* the filep->private_data has the i2c_client pointer! yay! */
struct i2c_client *client = filep->private_data;
/* now you can talk to your slave device with the i2c_client knowing
* it is the correct i2c_client */
}
就是这样:)。我希望这是有道理的。这是一个很长的解释,但我希望我是彻底的,但不要太困惑。最大的问题是我们有一个存储 i2c_cient 指针的全局表,但我想不出没有它的方法,因为 .probe
和 .open
有没有办法在彼此之间传递参数。如果有人有更好的解决方案,请告诉我。
关于c - 如何编写多个从属 i2c 客户端设备驱动程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39370398/
我正在 Jenkins 中配置从 Linux 节点。这里的多个标签的正确语法(分隔符和转义)是什么? 最佳答案 您应该使用 whitespaces 分隔标签。如果标签包含空格,您应该引用它(单引号和双
我已经设置了 master(192.168.1.10) 和 slave(192.168.1.11) postgresql。登录slave postgresql报错: postgres@sonia-Sy
我支持由小型企业托管的应用程序,基于 Web 的 ROR 应用程序在后端使用 pgsql 数据库。 Postgres 设置为复制到异地备用服务器,据我所知它工作正常,当我查询远程服务器时它显示它正在恢
这个方法是我写的(和其他帖子差不多) public void update(string fileName, string sheetName) { string connString = c
我已经为 MySQL 服务器设置了复制。我可以使用复制用户/密码从从机连接到主服务器。我已经运行了从属 SQL 线程,但是从属 I/O线程未运行,使用“显示从属状态”检查时从属 I/O 状态为空。可能
在使用Jenkins Docker插件时,可能由于错误而导致无法启动群集。我没有注意,目前有数千个脱机节点无法启动。 底线-是否可以批量删除Jenkin中的节点(从属),清理所有脱机节点甚至删除所有节
我正在尝试在一个旧项目中引入持续集成,我们遇到了非常具体的情况 - 可以将 CI 服务器只放在我们在 CentOS 上运行的测试服务器上。服务器有很多未使用的 RAM 和 CPU 功能。 但是,我们需
我最近更改了我的 jenkins 机器使用的其中一个从属设备的 DNS cname 记录。进行更改后,我更新了节点中的信息,使其指向新名称。从那时起,jenkins slave 无法启动并出现以下错误
我需要创建在 Amazon EC2 上的 Windows VM 下运行的 Jenkins 代理云。 我对此的看法是简单的场景: 我有几个预配置的 AMI,每个虚拟机都有与我的项目之一匹配的特定环境。我
使用 Jenkins EC2 插件,我无法让我的 Jenkins 主服务器通过 SSH 连接到我的 Jenkins 从服务器。从站启动并正确配置,但是: INFO: Connecting to 10.
奇怪的问题,我在工作区中有两个项目: 项目A 项目B 在 projectA 的 pom.xml 中我添加了: groupid projectB version 当我构建应用程序并部署到 tomca
在我的 Jenkinsfile 中出现错误后,从属代理 pod 似乎总是很快就会死亡并消失。有没有办法在我身处其中时执行它并使其保持事件状态?我使用 Helm 在 Kubernetes 上运行 Jen
我是一名优秀的程序员,十分优秀!