linux/drivers/staging/media/atomisp/pci/atomisp_file.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Support for Medifield PNW Camera Imaging ISP subsystem.
   4 *
   5 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
   6 *
   7 * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License version
  11 * 2 as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 *
  19 */
  20
  21#include <media/v4l2-event.h>
  22#include <media/v4l2-mediabus.h>
  23
  24#include <media/videobuf-vmalloc.h>
  25#include <linux/delay.h>
  26
  27#include "ia_css.h"
  28
  29#include "atomisp_cmd.h"
  30#include "atomisp_common.h"
  31#include "atomisp_file.h"
  32#include "atomisp_internal.h"
  33#include "atomisp_ioctl.h"
  34
  35static void file_work(struct work_struct *work)
  36{
  37        struct atomisp_file_device *file_dev =
  38            container_of(work, struct atomisp_file_device, work);
  39        struct atomisp_device *isp = file_dev->isp;
  40        /* only support file injection on subdev0 */
  41        struct atomisp_sub_device *asd = &isp->asd[0];
  42        struct atomisp_video_pipe *out_pipe = &asd->video_in;
  43        unsigned short *buf = videobuf_to_vmalloc(out_pipe->outq.bufs[0]);
  44        struct v4l2_mbus_framefmt isp_sink_fmt;
  45
  46        if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
  47                return;
  48
  49        dev_dbg(isp->dev, ">%s: ready to start streaming\n", __func__);
  50        isp_sink_fmt = *atomisp_subdev_get_ffmt(&asd->subdev, NULL,
  51                                                V4L2_SUBDEV_FORMAT_ACTIVE,
  52                                                ATOMISP_SUBDEV_PAD_SINK);
  53
  54        while (!ia_css_isp_has_started())
  55                usleep_range(1000, 1500);
  56
  57        ia_css_stream_send_input_frame(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
  58                                       buf, isp_sink_fmt.width,
  59                                       isp_sink_fmt.height);
  60        dev_dbg(isp->dev, "<%s: streaming done\n", __func__);
  61}
  62
  63static int file_input_s_stream(struct v4l2_subdev *sd, int enable)
  64{
  65        struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd);
  66        struct atomisp_device *isp = file_dev->isp;
  67        /* only support file injection on subdev0 */
  68        struct atomisp_sub_device *asd = &isp->asd[0];
  69
  70        dev_dbg(isp->dev, "%s: enable %d\n", __func__, enable);
  71        if (enable) {
  72                if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
  73                        return 0;
  74
  75                queue_work(file_dev->work_queue, &file_dev->work);
  76                return 0;
  77        }
  78        cancel_work_sync(&file_dev->work);
  79        return 0;
  80}
  81
  82static int file_input_get_fmt(struct v4l2_subdev *sd,
  83                              struct v4l2_subdev_state *sd_state,
  84                              struct v4l2_subdev_format *format)
  85{
  86        struct v4l2_mbus_framefmt *fmt = &format->format;
  87        struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd);
  88        struct atomisp_device *isp = file_dev->isp;
  89        /* only support file injection on subdev0 */
  90        struct atomisp_sub_device *asd = &isp->asd[0];
  91        struct v4l2_mbus_framefmt *isp_sink_fmt;
  92
  93        if (format->pad)
  94                return -EINVAL;
  95        isp_sink_fmt = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
  96                                               V4L2_SUBDEV_FORMAT_ACTIVE,
  97                                               ATOMISP_SUBDEV_PAD_SINK);
  98
  99        fmt->width = isp_sink_fmt->width;
 100        fmt->height = isp_sink_fmt->height;
 101        fmt->code = isp_sink_fmt->code;
 102
 103        return 0;
 104}
 105
 106static int file_input_set_fmt(struct v4l2_subdev *sd,
 107                              struct v4l2_subdev_state *sd_state,
 108                              struct v4l2_subdev_format *format)
 109{
 110        struct v4l2_mbus_framefmt *fmt = &format->format;
 111
 112        if (format->pad)
 113                return -EINVAL;
 114        file_input_get_fmt(sd, sd_state, format);
 115        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
 116                sd_state->pads->try_fmt = *fmt;
 117        return 0;
 118}
 119
 120static int file_input_log_status(struct v4l2_subdev *sd)
 121{
 122        /*to fake*/
 123        return 0;
 124}
 125
 126static int file_input_s_power(struct v4l2_subdev *sd, int on)
 127{
 128        /* to fake */
 129        return 0;
 130}
 131
 132static int file_input_enum_mbus_code(struct v4l2_subdev *sd,
 133                                     struct v4l2_subdev_state *sd_state,
 134                                     struct v4l2_subdev_mbus_code_enum *code)
 135{
 136        /*to fake*/
 137        return 0;
 138}
 139
 140static int file_input_enum_frame_size(struct v4l2_subdev *sd,
 141                                      struct v4l2_subdev_state *sd_state,
 142                                      struct v4l2_subdev_frame_size_enum *fse)
 143{
 144        /*to fake*/
 145        return 0;
 146}
 147
 148static int file_input_enum_frame_ival(struct v4l2_subdev *sd,
 149                                      struct v4l2_subdev_state *sd_state,
 150                                      struct v4l2_subdev_frame_interval_enum
 151                                      *fie)
 152{
 153        /*to fake*/
 154        return 0;
 155}
 156
 157static const struct v4l2_subdev_video_ops file_input_video_ops = {
 158        .s_stream = file_input_s_stream,
 159};
 160
 161static const struct v4l2_subdev_core_ops file_input_core_ops = {
 162        .log_status = file_input_log_status,
 163        .s_power = file_input_s_power,
 164};
 165
 166static const struct v4l2_subdev_pad_ops file_input_pad_ops = {
 167        .enum_mbus_code = file_input_enum_mbus_code,
 168        .enum_frame_size = file_input_enum_frame_size,
 169        .enum_frame_interval = file_input_enum_frame_ival,
 170        .get_fmt = file_input_get_fmt,
 171        .set_fmt = file_input_set_fmt,
 172};
 173
 174static const struct v4l2_subdev_ops file_input_ops = {
 175        .core = &file_input_core_ops,
 176        .video = &file_input_video_ops,
 177        .pad = &file_input_pad_ops,
 178};
 179
 180void
 181atomisp_file_input_unregister_entities(struct atomisp_file_device *file_dev)
 182{
 183        media_entity_cleanup(&file_dev->sd.entity);
 184        v4l2_device_unregister_subdev(&file_dev->sd);
 185}
 186
 187int atomisp_file_input_register_entities(struct atomisp_file_device *file_dev,
 188        struct v4l2_device *vdev)
 189{
 190        /* Register the subdev and video nodes. */
 191        return  v4l2_device_register_subdev(vdev, &file_dev->sd);
 192}
 193
 194void atomisp_file_input_cleanup(struct atomisp_device *isp)
 195{
 196        struct atomisp_file_device *file_dev = &isp->file_dev;
 197
 198        if (file_dev->work_queue) {
 199                destroy_workqueue(file_dev->work_queue);
 200                file_dev->work_queue = NULL;
 201        }
 202}
 203
 204int atomisp_file_input_init(struct atomisp_device *isp)
 205{
 206        struct atomisp_file_device *file_dev = &isp->file_dev;
 207        struct v4l2_subdev *sd = &file_dev->sd;
 208        struct media_pad *pads = file_dev->pads;
 209        struct media_entity *me = &sd->entity;
 210
 211        file_dev->isp = isp;
 212        file_dev->work_queue = alloc_workqueue(isp->v4l2_dev.name, 0, 1);
 213        if (!file_dev->work_queue) {
 214                dev_err(isp->dev, "Failed to initialize file inject workq\n");
 215                return -ENOMEM;
 216        }
 217
 218        INIT_WORK(&file_dev->work, file_work);
 219
 220        v4l2_subdev_init(sd, &file_input_ops);
 221        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 222        strscpy(sd->name, "file_input_subdev", sizeof(sd->name));
 223        v4l2_set_subdevdata(sd, file_dev);
 224
 225        pads[0].flags = MEDIA_PAD_FL_SINK;
 226        me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
 227
 228        return media_entity_pads_init(me, 1, pads);
 229}
 230