cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

video.c (4183B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2020 NVIDIA CORPORATION.  All rights reserved.
      4 */
      5
      6#include <linux/host1x.h>
      7#include <linux/module.h>
      8#include <linux/platform_device.h>
      9
     10#include <media/v4l2-event.h>
     11
     12#include "video.h"
     13
     14static void tegra_v4l2_dev_release(struct v4l2_device *v4l2_dev)
     15{
     16	struct tegra_video_device *vid;
     17
     18	vid = container_of(v4l2_dev, struct tegra_video_device, v4l2_dev);
     19
     20	/* cleanup channels here as all video device nodes are released */
     21	tegra_channels_cleanup(vid->vi);
     22
     23	v4l2_device_unregister(v4l2_dev);
     24	media_device_unregister(&vid->media_dev);
     25	media_device_cleanup(&vid->media_dev);
     26	kfree(vid);
     27}
     28
     29static void tegra_v4l2_dev_notify(struct v4l2_subdev *sd,
     30				  unsigned int notification, void *arg)
     31{
     32	struct tegra_vi_channel *chan;
     33	const struct v4l2_event *ev = arg;
     34
     35	if (notification != V4L2_DEVICE_NOTIFY_EVENT)
     36		return;
     37
     38	chan = v4l2_get_subdev_hostdata(sd);
     39	v4l2_event_queue(&chan->video, arg);
     40	if (ev->type == V4L2_EVENT_SOURCE_CHANGE && vb2_is_streaming(&chan->queue))
     41		vb2_queue_error(&chan->queue);
     42}
     43
     44static int host1x_video_probe(struct host1x_device *dev)
     45{
     46	struct tegra_video_device *vid;
     47	int ret;
     48
     49	vid = kzalloc(sizeof(*vid), GFP_KERNEL);
     50	if (!vid)
     51		return -ENOMEM;
     52
     53	dev_set_drvdata(&dev->dev, vid);
     54
     55	vid->media_dev.dev = &dev->dev;
     56	strscpy(vid->media_dev.model, "NVIDIA Tegra Video Input Device",
     57		sizeof(vid->media_dev.model));
     58
     59	media_device_init(&vid->media_dev);
     60	ret = media_device_register(&vid->media_dev);
     61	if (ret < 0) {
     62		dev_err(&dev->dev,
     63			"failed to register media device: %d\n", ret);
     64		goto cleanup;
     65	}
     66
     67	vid->v4l2_dev.mdev = &vid->media_dev;
     68	vid->v4l2_dev.release = tegra_v4l2_dev_release;
     69	vid->v4l2_dev.notify = tegra_v4l2_dev_notify;
     70	ret = v4l2_device_register(&dev->dev, &vid->v4l2_dev);
     71	if (ret < 0) {
     72		dev_err(&dev->dev,
     73			"V4L2 device registration failed: %d\n", ret);
     74		goto unregister_media;
     75	}
     76
     77	ret = host1x_device_init(dev);
     78	if (ret < 0)
     79		goto unregister_v4l2;
     80
     81	if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) {
     82		/*
     83		 * Both vi and csi channels are available now.
     84		 * Register v4l2 nodes and create media links for TPG.
     85		 */
     86		ret = tegra_v4l2_nodes_setup_tpg(vid);
     87		if (ret < 0) {
     88			dev_err(&dev->dev,
     89				"failed to setup tpg graph: %d\n", ret);
     90			goto device_exit;
     91		}
     92	}
     93
     94	return 0;
     95
     96device_exit:
     97	host1x_device_exit(dev);
     98	/* vi exit ops does not clean channels, so clean them here */
     99	tegra_channels_cleanup(vid->vi);
    100unregister_v4l2:
    101	v4l2_device_unregister(&vid->v4l2_dev);
    102unregister_media:
    103	media_device_unregister(&vid->media_dev);
    104cleanup:
    105	media_device_cleanup(&vid->media_dev);
    106	kfree(vid);
    107	return ret;
    108}
    109
    110static int host1x_video_remove(struct host1x_device *dev)
    111{
    112	struct tegra_video_device *vid = dev_get_drvdata(&dev->dev);
    113
    114	if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
    115		tegra_v4l2_nodes_cleanup_tpg(vid);
    116
    117	host1x_device_exit(dev);
    118
    119	/* This calls v4l2_dev release callback on last reference */
    120	v4l2_device_put(&vid->v4l2_dev);
    121
    122	return 0;
    123}
    124
    125static const struct of_device_id host1x_video_subdevs[] = {
    126#if defined(CONFIG_ARCH_TEGRA_210_SOC)
    127	{ .compatible = "nvidia,tegra210-csi", },
    128	{ .compatible = "nvidia,tegra210-vi", },
    129#endif
    130	{ }
    131};
    132
    133static struct host1x_driver host1x_video_driver = {
    134	.driver = {
    135		.name = "tegra-video",
    136	},
    137	.probe = host1x_video_probe,
    138	.remove = host1x_video_remove,
    139	.subdevs = host1x_video_subdevs,
    140};
    141
    142static struct platform_driver * const drivers[] = {
    143	&tegra_csi_driver,
    144	&tegra_vi_driver,
    145};
    146
    147static int __init host1x_video_init(void)
    148{
    149	int err;
    150
    151	err = host1x_driver_register(&host1x_video_driver);
    152	if (err < 0)
    153		return err;
    154
    155	err = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
    156	if (err < 0)
    157		goto unregister_host1x;
    158
    159	return 0;
    160
    161unregister_host1x:
    162	host1x_driver_unregister(&host1x_video_driver);
    163	return err;
    164}
    165module_init(host1x_video_init);
    166
    167static void __exit host1x_video_exit(void)
    168{
    169	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
    170	host1x_driver_unregister(&host1x_video_driver);
    171}
    172module_exit(host1x_video_exit);
    173
    174MODULE_AUTHOR("Sowjanya Komatineni <skomatineni@nvidia.com>");
    175MODULE_DESCRIPTION("NVIDIA Tegra Host1x Video driver");
    176MODULE_LICENSE("GPL v2");