linux camera---1

41087 ワード

linuxカメラ駆動:
コアデータ構造:
/**
 * struct fimc_dev - abstraction for FIMC entity
 * @slock:	the spinlock protecting this data structure
 * @lock:	the mutex protecting this data structure
 * @pdev:	pointer to the FIMC platform device
 * @pdata:	pointer to the device platform data
 * @variant:	the IP variant information
 * @id:		FIMC device index (0..FIMC_MAX_DEVS)
 * @num_clocks: the number of clocks managed by this device instance
 * @clock:	clocks required for FIMC operation
 * @regs:	the mapped hardware registers
 * @regs_res:	the resource claimed for IO registers
 * @irq:	FIMC interrupt number
 * @irq_queue:	interrupt handler waitqueue
 * @m2m:	memory-to-memory V4L2 device information
 * @vid_cap:	camera capture device information
 * @state:	flags used to synchronize m2m and capture mode operation
 * @alloc_ctx:	videobuf2 memory allocator context
 */
struct fimc_dev {
	spinlock_t			slock;
	struct mutex			lock;
	struct platform_device		*pdev;
	struct s5p_platform_fimc	*pdata;
	struct samsung_fimc_variant	*variant;
	u16				id;
	u16				num_clocks;
	struct clk			*clock[MAX_FIMC_CLOCKS];
	void __iomem			*regs;
	struct resource			*regs_res;
	int				irq;
	wait_queue_head_t		irq_queue;
	struct fimc_m2m_device		m2m;
	struct fimc_vid_cap		vid_cap;
	unsigned long			state;
	struct vb2_alloc_ctx		*alloc_ctx;
};

/**
 * fimc_ctx - the device context data
 * @slock:		spinlock protecting this data structure
 * @s_frame:		source frame properties
 * @d_frame:		destination frame properties
 * @out_order_1p:	output 1-plane YCBCR order
 * @out_order_2p:	output 2-plane YCBCR order
 * @in_order_1p		input 1-plane YCBCR order
 * @in_order_2p:	input 2-plane YCBCR order
 * @in_path:		input mode (DMA or camera)
 * @out_path:		output mode (DMA or FIFO)
 * @scaler:		image scaler properties
 * @effect:		image effect
 * @rotation:		image clockwise rotation in degrees
 * @flip:		image flip mode
 * @flags:		additional flags for image conversion
 * @state:		flags to keep track of user configuration
 * @fimc_dev:		the FIMC device this context applies to
 * @m2m_ctx:		memory-to-memory device context
 */
struct fimc_ctx {
	spinlock_t		slock;
	struct fimc_frame	s_frame;
	struct fimc_frame	d_frame;
	u32			out_order_1p;
	u32			out_order_2p;
	u32			in_order_1p;
	u32			in_order_2p;
	enum fimc_datapath	in_path;
	enum fimc_datapath	out_path;
	struct fimc_scaler	scaler;
	struct fimc_effect	effect;
	int			rotation;
	u32			flip;
	u32			flags;
	u32			state;
	struct fimc_dev		*fimc_dev;
	struct v4l2_m2m_ctx	*m2m_ctx;
};
/* fimc controller abstration */
struct fimc_control {
	int				id;		/* controller id */
	char				name[16];
	atomic_t			in_use;
	void __iomem			*regs;		/* register i/o */
	struct clk			*clk;		/* interface clock */
	struct regulator	*regulator;		/* pd regulator */
	struct fimc_meminfo		mem;		/* for reserved mem */

	/* kernel helpers */
	struct mutex			lock;		/* controller lock */
	struct mutex			alloc_lock;
	struct mutex			v4l2_lock;
	wait_queue_head_t		wq;
	struct device			*dev;
	int				irq;

	/* v4l2 related */
	struct video_device		*vd;
	struct v4l2_device		v4l2_dev;

	/* fimc specific */
	struct fimc_limit		*limit;		/* H/W limitation */
	struct s3c_platform_camera	*cam;		/* activated camera */
	struct fimc_capinfo		*cap;		/* capture dev info */
	struct fimc_outinfo		*out;		/* output dev info */
	struct fimc_fbinfo		fb;		/* fimd info */
	struct fimc_scaler		sc;		/* scaler info */
	struct fimc_effect		fe;		/* fimc effect info */

	enum fimc_status		status;
	enum fimc_log			log;

	u32				ctx_busy[FIMC_MAX_CTXS];
};
/* global */
struct fimc_global {
	struct fimc_control		ctrl[FIMC_DEVICES];
	struct s3c_platform_camera	camera[FIMC_MAXCAMS];
	int				camera_isvalid[FIMC_MAXCAMS];
	int				active_camera;
	int				initialized;
};
デバイスオブジェクト構造:plotformプラットフォームprobeで使用し、デバイスドライバに転送する
struct platform_device {
	const char	* name;
	int		id;
	struct device	dev;
	u32		num_resources;
	struct resource	* resource;

	const struct platform_device_id	*id_entry;

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};
デバイス情報:
static struct i2c_board_info  ov9650_i2c_info = 
{
	I2C_BOARD_INFO("OV9650", 0x60>>1),
	.platform_data = &ov9650_plat,
};

static struct s3c_platform_camera ov9650 = {
	.id			= CAMERA_PAR_A,
	.type		= CAM_TYPE_ITU,
	.fmt		= ITU_601_YCBCR422_8BIT,
	.order422	= CAM_ORDER422_8BIT_CBYCRY,
	.i2c_busnum	= IIC_NUM_CAM_USED,
	.info		= &ov9650_i2c_info,
	.pixelformat	= V4L2_PIX_FMT_VYUY,
	.srclk_name	= "mout_mpll",
	.clk_name	= "sclk_cam0",
	.clk_rate	= 24000000,
//	.line_length	= 640,
	.line_length	= 1920,
	.width		= 640,
	.height	= 480,
	.window	= {
		.left	= 0,
		.top	= 0,
		.width	= 640,
		.height= 480,
	},

	/* Polarity */
	.inv_pclk	= 0,
	.inv_vsync	= 0,
	.inv_href	= 0,
	.inv_hsync	= 0,

	.initialized	= 0,

//	.cam_power	= smdkv210_OV9650_power,
	.cam_power	= tqcam_OV9650_power,

};
static struct s3c_platform_fimc fimc_plat_lsi = {
	.srclk_name	= "mout_mpll",
	.clk_name	= "sclk_fimc",
	.lclk_name	= "fimc",
	.clk_rate	= 166750000,
#if defined(CONFIG_VIDEO_S5K4EA)
	.default_cam	= CAMERA_CSI_C,
#else
#ifdef CAM_ITU_CH_A
	.default_cam	= CAMERA_PAR_A,
#else
	.default_cam	= CAMERA_PAR_B,
#endif
#endif
	.camera		= {

			&ov9650,
	},
	.hw_ver		= 0x43,
};
static struct s5p_media_device tq210_media_devs[] = {
	[0] = {
		.id			= S5P_MDEV_MFC,
		.name		= "mfc",
		.bank		= 0,
		.memsize	= S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0,
		.paddr		= 0,
	},
	[1] = {
		.id			= S5P_MDEV_MFC,
		.name		= "mfc",
		.bank		= 1,
		.memsize	= S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1,
		.paddr		= 0,
	},
	[2] = {
		.id			= S5P_MDEV_FIMC0,
		.name		= "fimc0",
		.bank		= 1,
		.memsize	= S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0,
		.paddr		= 0,
	},
.............................

media_devsはtq 210_を指すメディアdevs配列
void __init s3c_fimc0_set_platdata(struct s3c_platform_fimc *pd)
{
	struct s3c_platform_fimc *npd;

	if (!pd)
		pd = &default_fimc0_data;

	npd = kmemdup(pd, sizeof(struct s3c_platform_fimc), GFP_KERNEL);
	if (!npd)
		printk(KERN_ERR "%s: no memory for platform data
", __func__); else { if (!npd->cfg_gpio) npd->cfg_gpio = s3c_fimc0_cfg_gpio; if (!npd->clk_on) npd->clk_on = s3c_fimc_clk_on; if (!npd->clk_off) npd->clk_off = s3c_fimc_clk_off; npd->hw_ver = 0x45; /* starting physical address of memory region */ npd->pmem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMC0, 1); /* size of memory region */ npd->pmem_size = s5p_get_media_memsize_bank(S5P_MDEV_FIMC0, 1); s3c_device_fimc0.dev.platform_data = npd; }
struct platform_device s3c_device_fimc0 = {
	.name		= "s3c-fimc",
	.id		= 0,
	.num_resources	= ARRAY_SIZE(s3c_fimc0_resource),
	.resource	= s3c_fimc0_resource,
};
デバイスドライバ登録:入り口;
static struct platform_driver fimc_driver = {
	.probe		= fimc_probe,
	.remove		= fimc_remove,
	.suspend	= fimc_suspend,
	.resume		= fimc_resume,
	.driver		= {
		.name	= FIMC_NAME,
		.owner	= THIS_MODULE,
	},
};
static int fimc_register(void)
{
	platform_driver_register(&fimc_driver);

	return 0;
}

static void fimc_unregister(void)
{
	platform_driver_unregister(&fimc_driver);
}

late_initcall(fimc_register);
fimc_に登録していますドライブ後;bus device driverによってplayformプラットフォームでマッチングします.呼び出し
fimc_driver->fimc_probe関数;バインディングデバイスオブジェクトを登録する.
static int __devinit fimc_probe(struct platform_device *pdev)
{
	struct s3c_platform_fimc *pdata;
	struct fimc_control *ctrl;
	struct clk *srclk;
	int ret;
	if (!fimc_dev) {   struct *fimc_global
		fimc_dev = kzalloc(sizeof(*fimc_dev), GFP_KERNEL);
		if (!fimc_dev) {
			dev_err(&pdev->dev, "%s: not enough memory
", __func__); return -ENOMEM; } } ctrl = fimc_register_controller(pdev); if (!ctrl) { printk(KERN_ERR "%s: cannot register fimc
", __func__); goto err_alloc; } pdata = to_fimc_plat(&pdev->dev); if (pdata->cfg_gpio) pdata->cfg_gpio(pdev); /* fimc source clock */ srclk = clk_get(&pdev->dev, pdata->srclk_name); /* fimc clock */ ctrl->clk = clk_get(&pdev->dev, pdata->clk_name); /* set parent for mclk */ clk_set_parent(ctrl->clk, srclk); /* set rate for mclk */ clk_set_rate(ctrl->clk, pdata->clk_rate); /* V4L2 device-subdev registration */ ret = v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev); if (ret) { fimc_err("%s: v4l2 device register failed
", __func__); goto err_fimc; } /* things to initialize once */ if (!fimc_dev->initialized) { ret = fimc_init_global(pdev); if (ret) goto err_v4l2; } /* video device register */ ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id); if (ret) { fimc_err("%s: cannot register video driver
", __func__); goto err_v4l2; } video_set_drvdata(ctrl->vd, ctrl); ret = device_create_file(&(pdev->dev), &dev_attr_log_level); .............. return -EINVAL;
デバイス情報の転送:
plotformによるとdeviceのid
ctrl->vd=&fimc_video.device[id]
方向:
struct video_device fimc_video_device[FIMC_DEVICES] = {
	[0] = {
		.fops = &fimc_fops,
		.ioctl_ops = &fimc_v4l2_ops,
		.release = fimc_vdev_release,
	},
static
struct fimc_control *fimc_register_controller(struct platform_device *pdev)
{
	struct s3c_platform_fimc *pdata;
	struct fimc_control *ctrl;
	struct resource *res;
	int id, mdev_id;

	id = pdev->id;
	mdev_id = S5P_MDEV_FIMC0 + id;
	pdata = to_fimc_plat(&pdev->dev);

	ctrl = get_fimc_ctrl(id);
	ctrl->id = id;
	ctrl->dev = &pdev->dev;
	ctrl->vd = &fimc_video_device[id];
	ctrl->vd->minor = id;

	/* alloc from bank1 as default */
	ctrl->mem.base = pdata->pmem_start;
	ctrl->mem.size = pdata->pmem_size;
	ctrl->mem.curr = ctrl->mem.base;

	ctrl->status = FIMC_STREAMOFF;
	switch (pdata->hw_ver) {
	case 0x40:
		ctrl->limit = &fimc40_limits[id];
		break;
	..........................
	}

	ctrl->log = FIMC_LOG_DEFAULT;

	sprintf(ctrl->name, "%s%d", FIMC_NAME, id);
	strcpy(ctrl->vd->name, ctrl->name);

	atomic_set(&ctrl->in_use, 0);
	mutex_init(&ctrl->lock);
	mutex_init(&ctrl->alloc_lock);
	mutex_init(&ctrl->v4l2_lock);
	init_waitqueue_head(&ctrl->wq);

	/* get resource for io memory */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		fimc_err("%s: failed to get io memory region
", __func__); return NULL; } /* request mem region request_mem_region , , , 。*/ res = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (!res) { fimc_err("%s: failed to request io memory region
", __func__); return NULL; } /* ioremap for register block I/O */ ctrl->regs = ioremap(res->start, res->end - res->start + 1); if (!ctrl->regs) { fimc_err("%s: failed to remap io region
", __func__); return NULL; } /* irq */ ctrl->irq = platform_get_irq(pdev, 0); if (request_irq(ctrl->irq, fimc_irq, IRQF_DISABLED, ctrl->name, ctrl)) fimc_err("%s: request_irq failed
", __func__); fimc_hwset_reset(ctrl); return ctrl;
v 4 l 2_deviceとdeviceが関連しています.
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
{
	if (v4l2_dev == NULL)
		return -EINVAL;

	INIT_LIST_HEAD(&v4l2_dev->subdevs);
	spin_lock_init(&v4l2_dev->lock);
	mutex_init(&v4l2_dev->ioctl_lock);
	v4l2_prio_init(&v4l2_dev->prio);
	kref_init(&v4l2_dev->ref);
	v4l2_dev->dev = dev;
	if (dev == NULL) {
		/* If dev == NULL, then name must be filled in by the caller */
		WARN_ON(!v4l2_dev->name[0]);
		return 0;
	}

	/* Set name to driver name + device name if it is empty. */
	if (!v4l2_dev->name[0])
		snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
			dev->driver->name, dev_name(dev));
	if (!dev_get_drvdata(dev))
		dev_set_drvdata(dev, v4l2_dev);
	return 0;
plotformを取得しますdeviceに関する情報
static int fimc_init_global(struct platform_device *pdev)
{
	struct s3c_platform_fimc *pdata;
	struct s3c_platform_camera *cam;
	int i;

	pdata = to_fimc_plat(&pdev->dev);

	/* Registering external camera modules. re-arrange order to be sure */
	for (i = 0; i < FIMC_MAXCAMS; i++) {
		cam = pdata->camera[i];
		if (!cam)
			break;

		cam->srclk = clk_get(&pdev->dev, cam->srclk_name);
		if (IS_ERR(cam->srclk)) {
			dev_err(&pdev->dev, "%s: failed to get mclk source
", __func__); return -EINVAL; } /* mclk */ cam->clk = clk_get(&pdev->dev, cam->clk_name); if (IS_ERR(cam->clk)) { dev_err(&pdev->dev, "%s: failed to get mclk source
", __func__); clk_put(cam->srclk); return -EINVAL; } clk_put(cam->clk); clk_put(cam->srclk); /* Assign camera device to fimc */ memcpy(&fimc_dev->camera[i], cam, sizeof(*cam)); fimc_dev->camera_isvalid[i] = 1; fimc_dev->camera[i].initialized = 0; } fimc_dev->active_camera = -1; fimc_dev->initialized = 1; return 0;
対:video_レジスターdevice
主にcdevのfopsを設定します.
v dev->cdev->ops=&v 4 l 2_fops;
登録します
cdev_add(vdev->>cdev,MKDEV(VIDEOuMAJOR,vdev->minor);
デバイス番号を設定
vdev->dev.devt=MKDEV(VIDEOuMAJOR、vdev->minor)
登録したdeviceはバスの中に行きます.
ret=device_register(&vdev->dev);
vdev->dev.release=v 4 l 2_device_release;
登録entry:
ret=media_device_レジスターentity(vdev->v 4 l 2 mdev、.
ioの操作には、
videoudevice[vdev->minor==vdev;
/**
 *	__video_register_device - register video4linux devices
 *	@vdev: video device structure we want to register
 *	@type: type of device to register
 *	@nr:   which device node number (0 == /dev/video0, 1 == /dev/video1, ...
 *             -1 == first free)
 *	@warn_if_nr_in_use: warn if the desired device node number
 *	       was already in use and another number was chosen instead.
 *	@owner: module that owns the video device node
 *
 *	The registration code assigns minor numbers and device node numbers
 *	based on the requested type and registers the new device node with
 *	the kernel.
 *
 *	This function assumes that struct video_device was zeroed when it
 *	was allocated and does not contain any stale date.
 *
 *	An error is returned if no free minor or device node number could be
 *	found, or if the registration of the device node failed.
 *
 *	Zero is returned on success.
 *
 *	Valid types are
 *
 *	%VFL_TYPE_GRABBER - A frame grabber
 *
 *	%VFL_TYPE_VBI - Vertical blank data (undecoded)
 *
 *	%VFL_TYPE_RADIO - A radio card
 *
 *	%VFL_TYPE_SUBDEV - A subdevice
 */
int __video_register_device(struct video_device *vdev, int type, int nr,
		int warn_if_nr_in_use, struct module *owner)
{
	int i = 0;
	int ret;
	int minor_offset = 0;
	int minor_cnt = VIDEO_NUM_DEVICES;
	const char *name_base;

	/* A minor value of -1 marks this video device as never
	   having been registered */
	vdev->minor = -1;

	/* the release callback MUST be present */
	WARN_ON(!vdev->release);
	if (!vdev->release)
		return -EINVAL;

	/* v4l2_fh support */
	spin_lock_init(&vdev->fh_lock);
	INIT_LIST_HEAD(&vdev->fh_list);

	/* Part 1: check device type */
	switch (type) {
	case VFL_TYPE_GRABBER:
		name_base = "video";
		break;
	case VFL_TYPE_VBI:
		name_base = "vbi";
		break;
	case VFL_TYPE_RADIO:
		name_base = "radio";
		break;
	case VFL_TYPE_SUBDEV:
		name_base = "v4l-subdev";
		break;
	default:
		printk(KERN_ERR "%s called with unknown type: %d
", __func__, type); return -EINVAL; } vdev->vfl_type = type; vdev->cdev = NULL; if (vdev->v4l2_dev) { if (vdev->v4l2_dev->dev) vdev->parent = vdev->v4l2_dev->dev; if (vdev->ctrl_handler == NULL) vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; /* If the prio state pointer is NULL, then use the v4l2_device prio state. */ if (vdev->prio == NULL) vdev->prio = &vdev->v4l2_dev->prio; } /* Part 2: find a free minor, device node number and device index. */ #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES /* Keep the ranges for the first four types for historical * reasons. * Newer devices (not yet in place) should use the range * of 128-191 and just pick the first free minor there * (new style). */ switch (type) { case VFL_TYPE_GRABBER: minor_offset = 0; minor_cnt = 64; break; case VFL_TYPE_RADIO: minor_offset = 64; minor_cnt = 64; break; case VFL_TYPE_VBI: minor_offset = 224; minor_cnt = 32; break; default: minor_offset = 128; minor_cnt = 64; break; } #endif /* Pick a device node number */ mutex_lock(&videodev_lock); nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt); if (nr == minor_cnt) nr = devnode_find(vdev, 0, minor_cnt); if (nr == minor_cnt) { printk(KERN_ERR "could not get a free device node number
"); mutex_unlock(&videodev_lock); return -ENFILE; } #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES /* 1-on-1 mapping of device node number to minor number */ i = nr; #else /* The device node number and minor numbers are independent, so we just find the first free minor number. */ for (i = 0; i < VIDEO_NUM_DEVICES; i++) if (video_device[i] == NULL) break; if (i == VIDEO_NUM_DEVICES) { mutex_unlock(&videodev_lock); printk(KERN_ERR "could not get a free minor
"); return -ENFILE; } #endif vdev->minor = i + minor_offset; vdev->num = nr; devnode_set(vdev); /* Should not happen since we thought this minor was free */ WARN_ON(video_device[vdev->minor] != NULL); vdev->index = get_index(vdev); mutex_unlock(&videodev_lock); /* Part 3: Initialize the character device */ vdev->cdev = cdev_alloc(); if (vdev->cdev == NULL) { ret = -ENOMEM; goto cleanup; } vdev->cdev->ops = &v4l2_fops; vdev->cdev->owner = owner; ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); if (ret < 0) { printk(KERN_ERR "%s: cdev_add failed
", __func__); kfree(vdev->cdev); vdev->cdev = NULL; goto cleanup; } /* Part 4: register the device with sysfs */ vdev->dev.class = &video_class; vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); if (vdev->parent) vdev->dev.parent = vdev->parent; dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); ret = device_register(&vdev->dev); if (ret < 0) { printk(KERN_ERR "%s: device_register failed
", __func__); goto cleanup; } /* Register the release callback that will be called when the last reference to the device goes away. */ vdev->dev.release = v4l2_device_release; if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) printk(KERN_WARNING "%s: requested %s%d, got %s
", __func__, name_base, nr, video_device_node_name(vdev)); /* Increase v4l2_device refcount */ if (vdev->v4l2_dev) v4l2_device_get(vdev->v4l2_dev); #if defined(CONFIG_MEDIA_CONTROLLER) /* Part 5: Register the entity. */ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; vdev->entity.v4l.major = VIDEO_MAJOR; vdev->entity.v4l.minor = vdev->minor; ret = media_device_register_entity(vdev->v4l2_dev->mdev, &vdev->entity); if (ret < 0) printk(KERN_WARNING "%s: media_device_register_entity failed
", __func__); } #endif /* Part 6: Activate this minor. The char device can now be used. */ set_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_lock(&videodev_lock); video_device[vdev->minor] = vdev; mutex_unlock(&videodev_lock); return 0; cleanup: mutex_lock(&videodev_lock); if (vdev->cdev) cdev_del(vdev->cdev); devnode_clear(vdev); mutex_unlock(&videodev_lock); /* Mark this video device as never having been registered. */ vdev->minor = -1; return ret; } EXPORT_SYMBOL(__video_register_device); /** * video_unregister_device - unregister a video4linux device * @vdev: the device to unregister * * This unregisters the passed device. Future open calls will * be met with errors. */ void video_unregister_device(struct video_device *vdev) { /* Check if vdev was ever registered at all */ if (!vdev || !video_is_registered(vdev)) return; mutex_lock(&videodev_lock); /* This must be in a critical section to prevent a race with v4l2_open. * Once this bit has been cleared video_get may never be called again. */ clear_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_unlock(&videodev_lock); device_unregister(&vdev->dev); } EXPORT_SYMBOL(video_unregister_device); /* * Initialise video for linux */ static int __init videodev_init(void) { dev_t dev = MKDEV(VIDEO_MAJOR, 0); int ret; printk(KERN_INFO "Linux video capture interface: v2.00
"); ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME); if (ret < 0) { printk(KERN_WARNING "videodev: unable to get major %d
", VIDEO_MAJOR); return ret; } ret = class_register(&video_class); if (ret < 0) { unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); printk(KERN_WARNING "video_dev: class_register failed
"); return -EIO; } return 0; } static void __exit videodev_exit(void) { dev_t dev = MKDEV(VIDEO_MAJOR, 0); class_unregister(&video_class); unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); } module_init(videodev_init) module_exit(videodev_exit) MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <[email protected]>"); MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR); /* * Local variables: * c-basic-offset: 8 * End: */
は、ドラヴィーデータを設定します.
Videousetudvdata(ctrl->vd,ctrl);
    if(ctrl->vd->dev->p->driver udta==null)     つまり、ctrl->vd->dev->p->driverudta=ctrlです.
v 4 l 2 Uusubdevの登録、すなわちiicデバイスの登録、およびv 4 l 2デバイスとのバインディングはいかがですか?
static const struct i2c_device_id ov3640_id[] = {
	{ OV3640_DRIVER_NAME, 0 },
	{ },
};
MODULE_DEVICE_TABLE(i2c, ov3640_id);

static struct v4l2_i2c_driver_data v4l2_i2c_data = {
	.name = OV3640_DRIVER_NAME,
	.probe = ov3640_probe,
	.remove = __devexit_p(ov3640_remove),
	.id_table = ov3640_id,
};
/* Bus-based I2C implementation for kernels >= 2.6.26 */

static int __init v4l2_i2c_drv_init(void)
{
	v4l2_i2c_driver.driver.name = v4l2_i2c_data.name;
	v4l2_i2c_driver.command = v4l2_i2c_data.command;
	v4l2_i2c_driver.probe = v4l2_i2c_data.probe;
	v4l2_i2c_driver.remove = v4l2_i2c_data.remove;
	v4l2_i2c_driver.suspend = v4l2_i2c_data.suspend;
	v4l2_i2c_driver.resume = v4l2_i2c_data.resume;
	v4l2_i2c_driver.id_table = v4l2_i2c_data.id_table;
	return i2c_add_driver(&v4l2_i2c_driver);
}


static void __exit v4l2_i2c_drv_cleanup(void)
{
	i2c_del_driver(&v4l2_i2c_driver);
}

module_init(v4l2_i2c_drv_init);
module_exit(v4l2_i2c_drv_cleanup);
iicの登録分析iic設備についてiic設備駆動を分析します.
static const struct v4l2_subdev_core_ops ov3640_core_ops = {
	.init = ov3640_init,	/* initializing API */
	.s_config = ov3640_s_config,	/* Fetch platform data */
	.queryctrl = ov3640_queryctrl,
	.querymenu = ov3640_querymenu,
	.g_ctrl = ov3640_g_ctrl,
	.s_ctrl = ov3640_s_ctrl,
};

static const struct v4l2_subdev_video_ops ov3640_video_ops = {
	.g_fmt = ov3640_g_fmt,
	.s_fmt = ov3640_s_fmt,
	.enum_framesizes = ov3640_enum_framesizes,
	.enum_frameintervals = ov3640_enum_frameintervals,
	.enum_fmt = ov3640_enum_fmt,
	.try_fmt = ov3640_try_fmt,
	.g_parm = ov3640_g_parm,
	.s_parm = ov3640_s_parm,
};

static const struct v4l2_subdev_ops ov3640_ops = {
	.core = &ov3640_core_ops,
	.video = &ov3640_video_ops,
};

static int ov3640_remove(struct i2c_client *client);
/*
 * ov3640_probe
 * Fetching platform data is being done with s_config subdev call.
 * In probe routine, we just register subdev device
 */
static int ov3640_probe(struct i2c_client *client,
			 const struct i2c_device_id *id)
{
	struct ov3640_state *state;
	struct v4l2_subdev *sd;
	int err = 0;

	state = kzalloc(sizeof(struct ov3640_state), GFP_KERNEL);
	if (state == NULL)
		return -ENOMEM;

	sd = &state->sd;
	strcpy(sd->name, OV3640_DRIVER_NAME);

	/* Registering subdev */
	v4l2_i2c_subdev_init(sd, client, &ov3640_ops);

	err =  checkIfOV3640(sd);
	dev_info(&client->dev, "ov3640 has been probed,err(%d)
",err); if(err < 0) ov3640_remove(client); return err; }
clientとsdを設定します.
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
		const struct v4l2_subdev_ops *ops)
{
	v4l2_subdev_init(sd, ops);
	sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
	/* the owner is the same as the i2c_client's driver owner */
	sd->owner = client->driver->driver.owner;
	/* i2c_client and v4l2_subdev point to one another */
	v4l2_set_subdevdata(sd, client);
	i2c_set_clientdata(client, sd);
	/* initialize name */
	snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
		client->driver->driver.name, i2c_adapter_id(client->adapter),
		client->addr);
}
v 4 l 2 Uusubdevとi 2 cuclientは互いに関連して、そのov 3640を設定します.
にあります v 4 l 2 udviceにinputをセットする camera id
 ここで問題を分析する
int fimc_s_input(struct file *file, void *fh, unsigned int i)
{
	struct fimc_global *fimc = get_fimc_dev();
	struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
	int ret = 0;

	fimc_dbg("%s: index %d
", __func__, i); if (i < 0 || i >= FIMC_MAXCAMS) { fimc_err("%s: invalid input index
", __func__); return -EINVAL; } if (!fimc->camera_isvalid[i]) return -EINVAL; if (fimc->camera[i].sd && ctrl->id != 2) { fimc_err("%s: Camera already in use.
", __func__); return -EBUSY; } mutex_lock(&ctrl->v4l2_lock); /* If ctrl->cam is not NULL, there is one subdev already registered. * We need to unregister that subdev first. */ if (i != fimc->active_camera) { fimc_release_subdev(ctrl); ctrl->cam = &fimc->camera[i]; ret = fimc_configure_subdev(ctrl); if (ret < 0) { mutex_unlock(&ctrl->v4l2_lock); fimc_err("%s: Could not register camera sensor " "with V4L2.
", __func__); return -ENODEV; } fimc->active_camera = i; } if (ctrl->id == 2) { if (i == fimc->active_camera) { ctrl->cam = &fimc->camera[i]; } else { mutex_unlock(&ctrl->v4l2_lock); return -EINVAL; } } mutex_unlock(&ctrl->v4l2_lock); return 0;
その中にfimcction figureubdev()を配置します.
int fimc_configure_subdev(struct fimc_control *ctrl)
{
	struct i2c_adapter *i2c_adap;
	struct i2c_board_info *i2c_info;
	struct v4l2_subdev *sd;
	unsigned short addr;
	int err;
	char *name;

	err = 0;
	/* set parent for mclk */
	if (clk_get_parent(ctrl->cam->clk->parent))
		clk_set_parent(ctrl->cam->clk->parent, ctrl->cam->srclk);

	/* set rate for mclk */
	if (clk_get_rate(ctrl->cam->clk))
		clk_set_rate(ctrl->cam->clk, ctrl->cam->clk_rate);

	i2c_adap = i2c_get_adapter(ctrl->cam->i2c_busnum);
	if (!i2c_adap)
		fimc_err("subdev i2c_adapter missing-skip registration
"); i2c_info = ctrl->cam->info; if (!i2c_info) { fimc_err("%s: subdev i2c board info missing
", __func__); return -ENODEV; } name = i2c_info->type; if (!name) { fimc_err("subdev i2c driver name missing-skip registration
"); return -ENODEV; } addr = i2c_info->addr; if (!addr) { fimc_err("subdev i2c address missing-skip registration
"); return -ENODEV; } /* * NOTE: first time subdev being registered, * s_config is called and try to initialize subdev device * but in this point, we are not giving MCLK and power to subdev * so nothing happens but pass platform data through */ sd = v4l2_i2c_new_subdev_board(&ctrl->v4l2_dev, i2c_adap, i2c_info, &addr); if (!sd) { fimc_err("%s: v4l2 subdev board registering failed
", __func__); err = -1; } /* Assign subdev to proper camera device pointer */ ctrl->cam->sd = sd; return err; // return 0; }
アドホッターを見つける
struct i2c_adapter *i2c_get_adapter(int nr)
{
	struct i2c_adapter *adapter;

	mutex_lock(&core_lock);
	adapter = idr_find(&i2c_adapter_idr, nr);
	if (adapter && !try_module_get(adapter->owner))
		adapter = NULL;

	mutex_unlock(&core_lock);
	return adapter;
}
i 2 cuinfo=ctrl->cam->info;addr=i 2 cuinfo->addr;cameraのiic情報;
/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
		struct i2c_adapter *adapter, struct i2c_board_info *info,
		const unsigned short *probe_addrs)
{
	struct v4l2_subdev *sd = NULL;
	struct i2c_client *client;

	BUG_ON(!v4l2_dev);

	request_module(I2C_MODULE_PREFIX "%s", info->type);

	/* Create the i2c client */
	if (info->addr == 0 && probe_addrs)
		client = i2c_new_probed_device(adapter, info, probe_addrs,
					       NULL);
	else
		client = i2c_new_device(adapter, info); 

	/* Note: by loading the module first we are certain that c->driver
	   will be set if the driver was found. If the module was not loaded
	   first, then the i2c core tries to delay-load the module for us,
	   and then c->driver is still NULL until the module is finally
	   loaded. This delay-load mechanism doesn't work if other drivers
	   want to use the i2c device, so explicitly loading the module
	   is the best alternative. */
	if (client == NULL || client->driver == NULL)
		goto error;

	/* Lock the module so we can safely get the v4l2_subdev pointer */
	if (!try_module_get(client->driver->driver.owner))
		goto error;
	sd = i2c_get_clientdata(client);

	/* Register with the v4l2_device which increases the module's
	   use count as well. */
	if (v4l2_device_register_subdev(v4l2_dev, sd))
		sd = NULL;
	/* Decrease the module use count to match the first try_module_get. */
	module_put(client->driver->driver.owner);

error:
	/* If we have a client but no subdev, then something went wrong and
	   we must unregister the client. */
	if (client && sd == NULL)
		i2c_unregister_device(client);
	return sd;
}
E
struct i 2 ccauclient* client=i 2 cmunevice;
分析:問題を分析することです.
int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
				struct v4l2_subdev *sd)
{
#if defined(CONFIG_MEDIA_CONTROLLER)
	struct media_entity *entity = &sd->entity;   
#endif
	int err;

	/* Check for valid input */
	if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
		return -EINVAL;

	/* Warn if we apparently re-register a subdev */
	WARN_ON(sd->v4l2_dev != NULL);

	if (!try_module_get(sd->owner))
		return -ENODEV;

	sd->v4l2_dev = v4l2_dev;
	if (sd->internal_ops && sd->internal_ops->registered) {
		err = sd->internal_ops->registered(sd);
		if (err) {
			module_put(sd->owner);
			return err;
		}
	}

	/* This just returns 0 if either of the two args is NULL */
	err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
	if (err) {
		if (sd->internal_ops && sd->internal_ops->unregistered)
			sd->internal_ops->unregistered(sd);
		module_put(sd->owner);
		return err;
	}

#if defined(CONFIG_MEDIA_CONTROLLER)
	/* Register the entity. */
	if (v4l2_dev->mdev) {
		err = media_device_register_entity(v4l2_dev->mdev, entity);
		if (err < 0) {
			if (sd->internal_ops && sd->internal_ops->unregistered)
				sd->internal_ops->unregistered(sd);
			module_put(sd->owner);
			return err;
		}
	}
#endif

	spin_lock(&v4l2_dev->lock);
	list_add_tail(&sd->list, &v4l2_dev->subdevs);
	spin_unlock(&v4l2_dev->lock);

	return 0;
struct mediat*entity=&sd->entity; 入り口のところ
sd->v 4 l 2 udev=v 4 l 2 udev;
mediaudvicement(v 4 l 2 udev->mdev,entity)
         -----.>チェーンを入れる
listudutail(&sd->list、&v 4 l 2 udv->subdevs);
ctrl->cam->sd=sd;
static ininline int fimcummapucap(ststrut file*filp、strut vmuuuaaaaaaaaaatu){stuct fimcuuuuuuuuuuuuda*prvuuuuuuda=( stuct fimuuuuuuuuuuudvuuuuuuuuuuuuuuuudaa*******)))) filp-prlp-prlp-prlp-prlp-prtttttttttttttttttttttttttttfifififififittttttttttttt start;u 32 pfn、idx=vma->vmuuugoff;vma->vmuupuage uplot=pgprot cached(vma->vmuplage upt)vma->vma->vmufffrags𞓜=VMuRESERVVVVD;/*page frame number of the address for a source frame*to be storored at.*/pfn=__physt uuuuuufn(ctrl-cap-cap-cap-cap-->cap->bufs[ddddddddtttttttttttttttttfs]]]]]]]Bfs[fs[fs[fs]]]]]Bfs[ddddddddddddddddfs[fx]]]]uSHARED){fimc err}{%s:writable mapping must be sharred}(vma,vma->vmustart,pfn,size,vma->vmupuage uplrot){fimccurr("%s:mmap fail],_func_];return-EIAVAL;return0;
対する:v 4 l 2 udviceとv 4 l 2 uusud関連;
これは別の種類です v 4 l 2 files fimcucature ufops
最初のv 4 l 2で、ufile.  fimc opsは違っていますが、原理は同じです.
static const struct v 4 l 2 filecturation s fimcCashutures={.owner=THIS MODULE..open=fimccatureewn,release=fimccauturewlose,poll=ficcature,poll=ficcation.apple.apple.apple.apple.apple.apple=
static int fimc_capture_open(struct file *file)
{
	struct fimc_dev *fimc = video_drvdata(file);
	int ret = 0;

	dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);

	/* Return if the corresponding video mem2mem node is already opened. */
	if (fimc_m2m_active(fimc))
		return -EBUSY;

	if (++fimc->vid_cap.refcnt == 1) {
		ret = fimc_isp_subdev_init(fimc, 0);
		if (ret) {
			fimc->vid_cap.refcnt--;
			return -EIO;
		}
	}

	file->private_data = fimc->vid_cap.ctx;

	return 0;
static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index)
{
	struct s5p_fimc_isp_info *isp_info;
	struct s5p_platform_fimc *pdata = fimc->pdata;
	int ret;

	if (index >= pdata->num_clients)
		return -EINVAL;

	isp_info = &pdata->isp_info[index];

	if (isp_info->clk_frequency)
		clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency);

	ret = clk_enable(fimc->clock[CLK_CAM]);
	if (ret)
		return ret;

	ret = fimc_subdev_attach(fimc, index);
	if (ret)
		return ret;

	ret = fimc_hw_set_camera_polarity(fimc, isp_info);
	if (ret)
		return ret;

	ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1);
	if (!ret)
		return ret;

	/* enabling power failed so unregister subdev */
	fimc_subdev_unregister(fimc);

	v4l2_err(&fimc->vid_cap.v4l2_dev, "ISP initialization failed: %d
", ret); return ret; }
/**
 * fimc_subdev_attach - attach v4l2_subdev to camera host interface
 *
 * @fimc: FIMC device information
 * @index: index to the array of available subdevices,
 *	   -1 for full array search or non negative value
 *	   to select specific subdevice
 */
static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
{
	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
	struct s5p_platform_fimc *pdata = fimc->pdata;
	struct s5p_fimc_isp_info *isp_info;
	struct v4l2_subdev *sd;
	int i;

	for (i = 0; i < pdata->num_clients; ++i) {
		isp_info = &pdata->isp_info[i];

		if (index >= 0 && i != index)
			continue;

		sd = fimc_subdev_register(fimc, isp_info);
		if (!IS_ERR_OR_NULL(sd)) {
			vid_cap->sd = sd;
			vid_cap->input_index = i;

			return 0;
		}
	}

	vid_cap->input_index = -1;
	vid_cap->sd = NULL;
	v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed
", fimc->id); return -ENODEV;
static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
					    struct s5p_fimc_isp_info *isp_info)
{
	struct i2c_adapter *i2c_adap;
	struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
	struct v4l2_subdev *sd = NULL;

	i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num);
	if (!i2c_adap)
		return ERR_PTR(-ENOMEM);

	sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
				       isp_info->board_info, NULL);
	if (!sd) {
		v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev
"); return NULL; } v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly
", isp_info->board_info->type); return sd; }
/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
		struct i2c_adapter *adapter, struct i2c_board_info *info,
		const unsigned short *probe_addrs)
{
	struct v4l2_subdev *sd = NULL;
	struct i2c_client *client;

	BUG_ON(!v4l2_dev);

	request_module(I2C_MODULE_PREFIX "%s", info->type);

	/* Create the i2c client */
	if (info->addr == 0 && probe_addrs)
		client = i2c_new_probed_device(adapter, info, probe_addrs,
					       NULL);
	else
		client = i2c_new_device(adapter, info);

	/* Note: by loading the module first we are certain that c->driver
	   will be set if the driver was found. If the module was not loaded
	   first, then the i2c core tries to delay-load the module for us,
	   and then c->driver is still NULL until the module is finally
	   loaded. This delay-load mechanism doesn't work if other drivers
	   want to use the i2c device, so explicitly loading the module
	   is the best alternative. */
	if (client == NULL || client->driver == NULL)
		goto error;

	/* Lock the module so we can safely get the v4l2_subdev pointer */
	if (!try_module_get(client->driver->driver.owner))
		goto error;
	sd = i2c_get_clientdata(client);

	/* Register with the v4l2_device which increases the module's
	   use count as well. */
	if (v4l2_device_register_subdev(v4l2_dev, sd))
		sd = NULL;
	/* Decrease the module use count to match the first try_module_get. */
	module_put(client->driver->driver.owner);

error:
	/* If we have a client but no subdev, then something went wrong and
	   we must unregister the client. */
	if (client && sd == NULL)
		i2c_unregister_device(client);
	return sd;
EXPORT_SYMBOL_GPL(v4l2_device_unregister);

int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
				struct v4l2_subdev *sd)
{
#if defined(CONFIG_MEDIA_CONTROLLER)
	struct media_entity *entity = &sd->entity;
#endif
	int err;

	/* Check for valid input */
	if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
		return -EINVAL;

	/* Warn if we apparently re-register a subdev */
	WARN_ON(sd->v4l2_dev != NULL);

	if (!try_module_get(sd->owner))
		return -ENODEV;

	sd->v4l2_dev = v4l2_dev;
	if (sd->internal_ops && sd->internal_ops->registered) {
		err = sd->internal_ops->registered(sd);
		if (err) {
			module_put(sd->owner);
			return err;
		}
	}

	/* This just returns 0 if either of the two args is NULL */
	err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
	if (err) {
		if (sd->internal_ops && sd->internal_ops->unregistered)
			sd->internal_ops->unregistered(sd);
		module_put(sd->owner);
		return err;
	}

#if defined(CONFIG_MEDIA_CONTROLLER)
	/* Register the entity. */
	if (v4l2_dev->mdev) {
		err = media_device_register_entity(v4l2_dev->mdev, entity);
		if (err < 0) {
			if (sd->internal_ops && sd->internal_ops->unregistered)
				sd->internal_ops->unregistered(sd);
			module_put(sd->owner);
			return err;
		}
	}
#endif

	spin_lock(&v4l2_dev->lock);
	list_add_tail(&sd->list, &v4l2_dev->subdevs);
	spin_unlock(&v4l2_dev->lock);

	return 0;