Embeded linux之soc camera

soc camera 子系统为分为soc camera device 和 soc camera host,并且定义了标准的接口或者回调函数.

流程:

  1.获取传来信息,填充soc_camera_link

  2.初始化soc_camera_device(iface、device、设备号、总线类型)、加入链表

  3.

一、/linux-3.0.35/drivers/media/video/soc_camera.c主要是用来管理接口或者回调函数.

module_init(soc_camera_init);

static int __init soc_camera_init(void)
{
  int ret = bus_register(&soc_camera_bus_type);//注册单没有关联
  ...
  ret = driver_register(&ic_drv);

  ...

  ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);

  ...
}

static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
{

  //通过传入的参数pdev获取platform_data,即struct soc_camera_link
  struct soc_camera_link *icl = pdev->dev.platform_data;

  struct soc_camera_device *icd;

  /*

   * 分配设备结构及初始化

   */

  icd = kzalloc(sizeof(*icd), GFP_KERNEL);

  icd->iface = icl->bus_id;  //iface被初始化为bus_id
  icd->pdev = &pdev->dev;
  platform_set_drvdata(pdev, icd);

  ret = soc_camera_device_register(icd);//soc_camera_device加到全局camera device链表@devices上,并且为它分配设备号,做一些必要的初始化

  soc_camera_device_init(&icd->dev, icl);//设置soc_came_device对应device的bus为soc_camera_bus_type,这样当我们注册设备时,就会调用soc_camera_probe

  icd->user_width  = DEFAULT_WIDTH;
  icd->user_height = DEFAULT_HEIGHT;
}

struct soc_camera_link {
  int bus_id;                //匹配soc camera host的序号
  unsigned long flags;
  int i2c_adapter_id;            //I2C 适配器号
  struct i2c_board_info *board_info;
  const char *module_name;
  void *priv;
  struct regulator_bulk_data *regulators;  //用于电源的管理
  int num_regulators;

  /*

  *针对那些非I2C的平台的函数,用于管理sensor设备的添加或者删除

  */
  int (*add_device)(struct soc_camera_link *, struct device *);
  void (*del_device)(struct soc_camera_link *);
  int (*power)(struct device *, int);
  int (*reset)(struct device *);
  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 *);
};

struct soc_camera_device {
  struct list_head list;
  struct device dev;
  struct device *pdev;  
  s32 user_width;           //图像的宽度,以像素为单位
  s32 user_height;          //图像的高度,以像素为单位
  u32 bytesperline;  
  u32 sizeimage;            //一画图像的大小,也是存储图像缓冲区的大小
  enum v4l2_colorspace colorspace;  //色域,指描述色彩时所使用的坐标系
  unsigned char iface;         //于camera link中的bus_id相对应
  unsigned char devnum;  
  struct soc_camera_sense *sense; 
  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;        //决定图像源数据交错的方式
  void *host_priv;  
  int use_count;
  struct mutex video_lock; 
  struct file *streamer;  

  /*

   * 管理帧缓冲区

   */
  union {
    struct videobuf_queue vb_vidq;
    struct vb2_queue vb2_vidq;
  };
};

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++) {  //判断挂接的设备是否256个设备号都占用
    num = i;
    list_for_each_entry(ix, &devices, list) {
    if (ix->iface == icd->iface && ix->devnum == i) {
      num = -1;
      break;
      }
    }
   }

  icd->devnum  = num;          //找到空闲的设备号
  icd->use_count  = 0;
  icd->host_priv  = NULL;
  mutex_init(&icd->video_lock);

  list_add_tail(&icd->list, &devices);    //将空闲的设备结构放入链表

}

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;
}

struct bus_type soc_camera_bus_type = {
 .name  = "soc-camera",
 .probe  = soc_camera_probe,
 .remove  = soc_camera_remove,
 .suspend = soc_camera_suspend,
 .resume  = soc_camera_resume,
};

static int soc_camera_probe(struct device *dev)
{

  ...
 ret = video_dev_create(icd);

  ...

} 

static int video_dev_create(struct soc_camera_device *icd)
{
 struct video_device *vdev = video_device_alloc();

 strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));

 vdev->parent  = &icd->dev;
 vdev->current_norm = V4L2_STD_UNKNOWN;
 vdev->fops  = &soc_camera_fops;
 vdev->ioctl_ops  = &soc_camera_ioctl_ops;
 vdev->release  = video_device_release;
 vdev->tvnorms  = V4L2_STD_UNKNOWN;

 icd->vdev = vdev;

 return 0;
}

static struct v4l2_file_operations soc_camera_fops = {
 .owner  = THIS_MODULE,
 .open  = soc_camera_open,
 .release = soc_camera_close,
 .unlocked_ioctl = video_ioctl2,
 .read  = soc_camera_read,
 .mmap  = soc_camera_mmap,
 .poll  = soc_camera_poll,
};

static int soc_camera_open(struct file *file)
{
 struct video_device *vdev = video_devdata(file);//获取video_driver信息

  ...

/linux-3.0.35/drivers/media/video/v4l2-ioctl.c

long video_ioctl2(struct file *file,
        unsigned int cmd, unsigned long arg)
{
  return video_usercopy(file, cmd, arg, __video_do_ioctl);
}

static long __video_do_ioctl(struct file *file,
  unsigned int cmd, void *arg)
{
  struct video_device *vfd = video_devdata(file);
  const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
  void *fh = file->private_data;

  ...

  case VIDIOC_S_CROP:
  {
    struct v4l2_crop *p = arg;

    ret = ops->vidioc_s_crop(file, fh, p);
    break;
  }

  ...

}

未完待续...

原文地址:https://www.cnblogs.com/pokerface/p/6518154.html