/*
* Samsung TV Mixer driver
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
*
* Tomasz Stanislawski, <t.stanislaws@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation. either version 2 of the License,
* or (at your option) any later version
*/
#include "mixer.h"
#include <media/v4l2-ioctl.h>
#include <linux/videodev2.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/timer.h>
#include <media/videobuf2-dma-contig.h>
static int find_reg_callback(struct device *dev, void *p)
{
struct v4l2_subdev **sd = p;
*sd = dev_get_drvdata(dev);
/* non-zero value stops iteration */
return 1;
}
static struct v4l2_subdev *find_and_register_subdev(
struct mxr_device *mdev, char *module_name)
{
struct device_driver *drv;
struct v4l2_subdev *sd = NULL;
int ret;
/* TODO: add waiting until probe is finished */
drv = driver_find(module_name, &platform_bus_type);
if (!drv) {
mxr_warn(mdev, "module %s is missing\n", module_name);
return NULL;
}
/* driver refcnt is increased, it is safe to iterate over devices */
ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
/* ret == 0 means that find_reg_callback was never executed */
if (sd == NULL) {
mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
goto done;
}
/* v4l2_device_register_subdev detects if sd is NULL */
ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
if (ret) {
mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
sd = NULL;
}
done:
put_driver(drv);
return sd;
}
int __devinit mxr_acquire_video(struct mxr_device *mdev,
struct mxr_output_conf *output_conf, int output_count)
{
struct device *dev = mdev->dev;
struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
int i;
int ret = 0;
struct v4l2_subdev *sd;
strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
/* prepare context for V4L2 device */
ret = v4l2_device_register(dev, v4l2_dev);
if (ret) {
mxr_err(mdev, "could not register v4l2 device.\n");
goto fail;
}
mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
mxr_err(mdev, "could not acquire vb2 allocator\n");
goto fail_v4l2_dev;
}
/* registering outputs */
mdev->output_cnt = 0;
for (i = 0; i < output_count; ++i) {
struct mxr_output_conf *conf = &output_conf[i];
struct mxr_output *out;
sd = find_and_register_subdev(mdev, conf->module_name);
/* trying to register next output */
if (sd == NULL)
continue;
out = kzalloc(sizeof *out, GFP_KERNEL);
if (out == NULL) {
mxr_err(mdev, "no memory for '%s'\n",
conf->output_name);
ret = -ENOMEM;
/* registered subdevs are removed in fail_v4l2_dev */
goto fail_output;
}
strlcpy(out->name, conf->output_name, sizeof(out->name));
out->sd = sd;
out->cookie = conf->cookie;
mdev->output[mdev->output_cnt++] =