soc camera 子系统之soc camera device初始化
2014-02-10 15:03
225 查看
从上一篇的博客soc camera 子系统简介(http://blog.csdn.net/smartvincent88/article/details/18987207)中的图中可以看出,soc camera device 是sensor的抽象,可以说,每个soc camera device 对应一个sensor或者其他的video设备。本节就结合soc_camera.c来具体分析soc camera device 的具体的初始化流程。
首先来看第一个函数:
static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
{
⑴
struct soc_camera_link *icl = pdev->dev.platform_data;
struct soc_camera_device *icd;
int ret;
if (!icl)
return -EINVAL;
⑵
icd = kzalloc(sizeof(*icd), GFP_KERNEL);
if (!icd)
return -ENOMEM;
icd->iface = icl->bus_id;
icd->pdev = &pdev->dev;
platform_set_drvdata(pdev, icd);
⑶
ret = soc_camera_device_register(icd);
if (ret < 0)
goto escdevreg;
⑷
soc_camera_device_init(&icd->dev, icl);
icd->user_width = DEFAULT_WIDTH;
icd->user_height = DEFAULT_HEIGHT;
dev_info(&pdev->dev, "register ok!\n");
return 0;
escdevreg:
kfree(icd);
return ret;
}
该probe函数是基于platform device 总线的,该probe函数的注册是在本地函数soc_camera_init中执行的。那么既然有了probe函数,那么肯定会有相应的paltform device啊,别急,我们先来看看,该函数主要做了哪些事情。
在解释该函数之前,先介绍一下两个主要的结构体,详见下面的注释。
struct soc_camera_link {
/* Camera bus id, used to match a camera and a bus */
int bus_id; //这个一般用于匹配soc camera host的序号
/* Per camera SOCAM_SENSOR_* bus flags */
unsigned long flags;
int i2c_adapter_id; //I2C 适配器号
struct i2c_board_info *board_info;
const char *module_name;
void *priv;
/* Optional regulators that have to be managed on power on/off events */
//可选的,用于电源的管理
struct regulator_bulk_data *regulators;
int num_regulators;
/*
* For non-I2C devices platform platform has to provide methods to
* add a device to the system and to remove
*/
//以下这几个成员函数,主要是针对那些非I2C的平台,用于管理sensor设备的添加或者删除,不过一般情况下用不到
int (*add_device)(struct soc_camera_link *, struct device *);
void (*del_device)(struct soc_camera_link *);
/* Optional callbacks to power on or off and reset the sensor */
int (*power)(struct device *, int);
int (*reset)(struct device *);
/*
* some platforms may support different data widths than the sensors
* native ones due to different data line routing. Let the board code
* overwrite the width flags.
*/
int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
unsigned long (*query_bus_param)(struct soc_camera_link *);
void (*free_bus)(struct soc_camera_link *);
};
下面介绍一下soc camera device 这个结构体,详见下面的注释
struct soc_camera_device {
struct list_head list;
struct device dev;
struct device *pdev; /* Platform device */
s32 user_width; //图像的宽度,以像素为单位
s32 user_height; //图像的高度,以像素为单位
u32 bytesperline; /* for padding, zero if unused */
u32 sizeimage;//一画图像的大小,也是存储图像缓冲区的大小
enum v4l2_colorspace colorspace;//色域,指描述色彩时所使用的坐标系
unsigned char iface; /* Host number */ //于camera link中的bus_id相对应
unsigned char devnum; /* Device number per host */
struct soc_camera_sense *sense; /* See comment in struct definition */
struct soc_camera_ops *ops;
struct video_device *vdev;
const struct soc_camera_format_xlate *current_fmt; //驱动中当前使用的视频格式
struct soc_camera_format_xlate *user_formats; //全部支持的视频格式
int num_user_formats;
enum v4l2_field field; /* Preserve field over close() */ //决定图像源数据交错的方式
void *host_priv; /* Per-device host private data */
/* soc_camera.c private count. Only accessed with .video_lock held */
int use_count;
struct mutex video_lock; /* Protects device data */
struct file *streamer; /* stream owner */
//下面这个共用体,非常重要,用于管理帧缓冲区
union {
struct videobuf_queue vb_vidq;
struct vb2_queue vb2_vidq;
};
};
在分析该probe函数之前,笔者先将对应于该probe函数的platform device的简单示例写错来,以便可以更好的分析该probe函数。示例如下:
static int example_power(struct device *dev,int power
{
}
static int example_reset(struct device *dev)
{
}
struct i2c_board_info example_info = {
I2C_BOARD_INFO("example_sensor",0x27),
};
struct soc_camera_link example_link = {
.bus_id = 0,/*match the soc camera host id */
.board_info = &example_info,
.i2c_adapter_id = 1,/*match the I2C Adapater ID.
*/
.power = example_power ,
.reset = example_reset,
};
struct platfom_device example_camera_device = {
.name = "camera device",
.id = 0,
.dev = {
.platform_data = &example_link,
},
};
以上的代码片度是一个简单的实例,那我们现在可以分析上面的probe函数了,首先,会通过传入的参数pdev获取platform_data,即struct soc_camera_link,然后(2)处的代码为struct soc_camera_device 申请内存,并且初始化,其中iface被初始化为bus_id,指定soc camera host的index。再来看(3)处的代码,调用函数soc_camera_device_register(struct soc_camera_device *dev)函数,来看看这个函数做了什么。
/* Image capture device */
static int soc_camera_device_register(struct soc_camera_device *icd)
{
struct soc_camera_device *ix;
int num = -1, i;
for (i = 0; i < 256 && num < 0; i++) {
num = i;
/* Check if this index is available on this interface */
list_for_each_entry(ix, &devices, list) {
if (ix->iface == icd->iface && ix->devnum == i) {
num = -1;
break;
}
}
}
if (num < 0)
/*
* ok, we have 256 cameras on this host...
* man, stay reasonable...
*/
return -ENOMEM;
icd->devnum = num;
icd->use_count = 0;
icd->host_priv = NULL;
mutex_init(&icd->video_lock);
list_add_tail(&icd->list, &devices);
return 0;
}
该函数核心是for循环,这个for循环目的很明确,确定Index为icd->iface的主机是否已经连接了256个image capture,如果没有,则找出空闲的devnum,即是空闲的设备号,否则,函数返回一个错误码。如果有空闲的devnum,则初始化icd,并且将icd加入到本地链表devices中。
好了,我们接着分析probe函数,(4)处的代码也做了一件很有意义的事情,就是调用了函数soc_camera_device_init,该函数的代码如下:
static void soc_camera_device_init(struct device *dev, void *pdata)
{
dev->platform_data = pdata;
dev->bus = &soc_camera_bus_type;
dev->release = dummy_release;
}
非常简单的实现,初始化soc camera device的成员结构体device,将设备的总线类型设置为soc_camera_bus_type,这个总线是soc_camera.c定义的一个简单的本地总线类型,仅供soc_camera.c内部使用。并且还将传入的参数icl赋值给dev的平台数据指针。接着(4)处的代码继续将icd得成员变量us
4000
er_width和user_height初始化为默认值。到此为止,该probe函数分析完了,接下来的部分就是结合soc camera host进行进一步初始化并且注册video
device的部分了。后面将继续分析。
首先来看第一个函数:
static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
{
⑴
struct soc_camera_link *icl = pdev->dev.platform_data;
struct soc_camera_device *icd;
int ret;
if (!icl)
return -EINVAL;
⑵
icd = kzalloc(sizeof(*icd), GFP_KERNEL);
if (!icd)
return -ENOMEM;
icd->iface = icl->bus_id;
icd->pdev = &pdev->dev;
platform_set_drvdata(pdev, icd);
⑶
ret = soc_camera_device_register(icd);
if (ret < 0)
goto escdevreg;
⑷
soc_camera_device_init(&icd->dev, icl);
icd->user_width = DEFAULT_WIDTH;
icd->user_height = DEFAULT_HEIGHT;
dev_info(&pdev->dev, "register ok!\n");
return 0;
escdevreg:
kfree(icd);
return ret;
}
该probe函数是基于platform device 总线的,该probe函数的注册是在本地函数soc_camera_init中执行的。那么既然有了probe函数,那么肯定会有相应的paltform device啊,别急,我们先来看看,该函数主要做了哪些事情。
在解释该函数之前,先介绍一下两个主要的结构体,详见下面的注释。
struct soc_camera_link {
/* Camera bus id, used to match a camera and a bus */
int bus_id; //这个一般用于匹配soc camera host的序号
/* Per camera SOCAM_SENSOR_* bus flags */
unsigned long flags;
int i2c_adapter_id; //I2C 适配器号
struct i2c_board_info *board_info;
const char *module_name;
void *priv;
/* Optional regulators that have to be managed on power on/off events */
//可选的,用于电源的管理
struct regulator_bulk_data *regulators;
int num_regulators;
/*
* For non-I2C devices platform platform has to provide methods to
* add a device to the system and to remove
*/
//以下这几个成员函数,主要是针对那些非I2C的平台,用于管理sensor设备的添加或者删除,不过一般情况下用不到
int (*add_device)(struct soc_camera_link *, struct device *);
void (*del_device)(struct soc_camera_link *);
/* Optional callbacks to power on or off and reset the sensor */
int (*power)(struct device *, int);
int (*reset)(struct device *);
/*
* some platforms may support different data widths than the sensors
* native ones due to different data line routing. Let the board code
* overwrite the width flags.
*/
int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
unsigned long (*query_bus_param)(struct soc_camera_link *);
void (*free_bus)(struct soc_camera_link *);
};
下面介绍一下soc camera device 这个结构体,详见下面的注释
struct soc_camera_device {
struct list_head list;
struct device dev;
struct device *pdev; /* Platform device */
s32 user_width; //图像的宽度,以像素为单位
s32 user_height; //图像的高度,以像素为单位
u32 bytesperline; /* for padding, zero if unused */
u32 sizeimage;//一画图像的大小,也是存储图像缓冲区的大小
enum v4l2_colorspace colorspace;//色域,指描述色彩时所使用的坐标系
unsigned char iface; /* Host number */ //于camera link中的bus_id相对应
unsigned char devnum; /* Device number per host */
struct soc_camera_sense *sense; /* See comment in struct definition */
struct soc_camera_ops *ops;
struct video_device *vdev;
const struct soc_camera_format_xlate *current_fmt; //驱动中当前使用的视频格式
struct soc_camera_format_xlate *user_formats; //全部支持的视频格式
int num_user_formats;
enum v4l2_field field; /* Preserve field over close() */ //决定图像源数据交错的方式
void *host_priv; /* Per-device host private data */
/* soc_camera.c private count. Only accessed with .video_lock held */
int use_count;
struct mutex video_lock; /* Protects device data */
struct file *streamer; /* stream owner */
//下面这个共用体,非常重要,用于管理帧缓冲区
union {
struct videobuf_queue vb_vidq;
struct vb2_queue vb2_vidq;
};
};
在分析该probe函数之前,笔者先将对应于该probe函数的platform device的简单示例写错来,以便可以更好的分析该probe函数。示例如下:
static int example_power(struct device *dev,int power
{
}
static int example_reset(struct device *dev)
{
}
struct i2c_board_info example_info = {
I2C_BOARD_INFO("example_sensor",0x27),
};
struct soc_camera_link example_link = {
.bus_id = 0,/*match the soc camera host id */
.board_info = &example_info,
.i2c_adapter_id = 1,/*match the I2C Adapater ID.
*/
.power = example_power ,
.reset = example_reset,
};
struct platfom_device example_camera_device = {
.name = "camera device",
.id = 0,
.dev = {
.platform_data = &example_link,
},
};
以上的代码片度是一个简单的实例,那我们现在可以分析上面的probe函数了,首先,会通过传入的参数pdev获取platform_data,即struct soc_camera_link,然后(2)处的代码为struct soc_camera_device 申请内存,并且初始化,其中iface被初始化为bus_id,指定soc camera host的index。再来看(3)处的代码,调用函数soc_camera_device_register(struct soc_camera_device *dev)函数,来看看这个函数做了什么。
/* Image capture device */
static int soc_camera_device_register(struct soc_camera_device *icd)
{
struct soc_camera_device *ix;
int num = -1, i;
for (i = 0; i < 256 && num < 0; i++) {
num = i;
/* Check if this index is available on this interface */
list_for_each_entry(ix, &devices, list) {
if (ix->iface == icd->iface && ix->devnum == i) {
num = -1;
break;
}
}
}
if (num < 0)
/*
* ok, we have 256 cameras on this host...
* man, stay reasonable...
*/
return -ENOMEM;
icd->devnum = num;
icd->use_count = 0;
icd->host_priv = NULL;
mutex_init(&icd->video_lock);
list_add_tail(&icd->list, &devices);
return 0;
}
该函数核心是for循环,这个for循环目的很明确,确定Index为icd->iface的主机是否已经连接了256个image capture,如果没有,则找出空闲的devnum,即是空闲的设备号,否则,函数返回一个错误码。如果有空闲的devnum,则初始化icd,并且将icd加入到本地链表devices中。
好了,我们接着分析probe函数,(4)处的代码也做了一件很有意义的事情,就是调用了函数soc_camera_device_init,该函数的代码如下:
static void soc_camera_device_init(struct device *dev, void *pdata)
{
dev->platform_data = pdata;
dev->bus = &soc_camera_bus_type;
dev->release = dummy_release;
}
非常简单的实现,初始化soc camera device的成员结构体device,将设备的总线类型设置为soc_camera_bus_type,这个总线是soc_camera.c定义的一个简单的本地总线类型,仅供soc_camera.c内部使用。并且还将传入的参数icl赋值给dev的平台数据指针。接着(4)处的代码继续将icd得成员变量us
4000
er_width和user_height初始化为默认值。到此为止,该probe函数分析完了,接下来的部分就是结合soc camera host进行进一步初始化并且注册video
device的部分了。后面将继续分析。
相关文章推荐
- soc camera子系统之初始化i2c client
- V4L2 soc-camera 子系统
- V4L2的soc-camera子系统
- soc camera子系统之注册video device设备
- i2c子系统之platfor_device初始化——smdk2440_machine_init()
- 协议[I2C]_I2C子系统之platfor_device初始化——smdk2440_machine_init()
- soc camera 子系统之soc camera host 与soc camera device 注册
- V4L2 soc-camera 子系统
- V4L2 soc-camera 子系统
- soc-camera 子系统
- 中断子系统1_中断子系统初始化
- v4L2 soc-camera 分析 - soc_camera.c
- timer 子系统的初始化过程
- Linux时间子系统之四:定时器的引擎:clock_event_device
- 步步为营,分析平台设备初始化platform_device_register()
- V4l2中soc_camera框架图
- McAfee更新失败,提示"初始化Common Updater子系统失败"的解决方法
- v4L2 soc-camera 分析 - soc_camera.c
- 《Linux内核修炼之道》精华分享与讨论(15)——子系统的初始化:内核选项解析
- soc camera 子系统简介