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

videobuf2-dvb.c (8382B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *
      4 * some helper function for simple DVB cards which simply DMA the
      5 * complete transport stream and let the computer sort everything else
      6 * (i.e. we are using the software demux, ...).  Also uses the
      7 * video-buf to manage DMA buffers.
      8 *
      9 * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
     10 */
     11
     12#include <linux/module.h>
     13#include <linux/init.h>
     14#include <linux/device.h>
     15#include <linux/slab.h>
     16
     17#include <media/videobuf2-dvb.h>
     18
     19/* ------------------------------------------------------------------ */
     20
     21MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
     22MODULE_LICENSE("GPL");
     23
     24/* ------------------------------------------------------------------ */
     25
     26static int dvb_fnc(struct vb2_buffer *vb, void *priv)
     27{
     28	struct vb2_dvb *dvb = priv;
     29
     30	dvb_dmx_swfilter(&dvb->demux, vb2_plane_vaddr(vb, 0),
     31				      vb2_get_plane_payload(vb, 0));
     32	return 0;
     33}
     34
     35static int vb2_dvb_start_feed(struct dvb_demux_feed *feed)
     36{
     37	struct dvb_demux *demux = feed->demux;
     38	struct vb2_dvb *dvb = demux->priv;
     39	int rc = 0;
     40
     41	if (!demux->dmx.frontend)
     42		return -EINVAL;
     43
     44	mutex_lock(&dvb->lock);
     45	dvb->nfeeds++;
     46
     47	if (!dvb->dvbq.threadio) {
     48		rc = vb2_thread_start(&dvb->dvbq, dvb_fnc, dvb, dvb->name);
     49		if (rc)
     50			dvb->nfeeds--;
     51	}
     52	if (!rc)
     53		rc = dvb->nfeeds;
     54	mutex_unlock(&dvb->lock);
     55	return rc;
     56}
     57
     58static int vb2_dvb_stop_feed(struct dvb_demux_feed *feed)
     59{
     60	struct dvb_demux *demux = feed->demux;
     61	struct vb2_dvb *dvb = demux->priv;
     62	int err = 0;
     63
     64	mutex_lock(&dvb->lock);
     65	dvb->nfeeds--;
     66	if (0 == dvb->nfeeds)
     67		err = vb2_thread_stop(&dvb->dvbq);
     68	mutex_unlock(&dvb->lock);
     69	return err;
     70}
     71
     72static int vb2_dvb_register_adapter(struct vb2_dvb_frontends *fe,
     73			  struct module *module,
     74			  void *adapter_priv,
     75			  struct device *device,
     76			  struct media_device *mdev,
     77			  char *adapter_name,
     78			  short *adapter_nr,
     79			  int mfe_shared)
     80{
     81	int result;
     82
     83	mutex_init(&fe->lock);
     84
     85	/* register adapter */
     86	result = dvb_register_adapter(&fe->adapter, adapter_name, module,
     87		device, adapter_nr);
     88	if (result < 0) {
     89		pr_warn("%s: dvb_register_adapter failed (errno = %d)\n",
     90		       adapter_name, result);
     91	}
     92	fe->adapter.priv = adapter_priv;
     93	fe->adapter.mfe_shared = mfe_shared;
     94#ifdef CONFIG_MEDIA_CONTROLLER_DVB
     95	if (mdev)
     96		fe->adapter.mdev = mdev;
     97#endif
     98	return result;
     99}
    100
    101static int vb2_dvb_register_frontend(struct dvb_adapter *adapter,
    102	struct vb2_dvb *dvb)
    103{
    104	int result;
    105
    106	/* register frontend */
    107	result = dvb_register_frontend(adapter, dvb->frontend);
    108	if (result < 0) {
    109		pr_warn("%s: dvb_register_frontend failed (errno = %d)\n",
    110		       dvb->name, result);
    111		goto fail_frontend;
    112	}
    113
    114	/* register demux stuff */
    115	dvb->demux.dmx.capabilities =
    116		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
    117		DMX_MEMORY_BASED_FILTERING;
    118	dvb->demux.priv       = dvb;
    119	dvb->demux.filternum  = 256;
    120	dvb->demux.feednum    = 256;
    121	dvb->demux.start_feed = vb2_dvb_start_feed;
    122	dvb->demux.stop_feed  = vb2_dvb_stop_feed;
    123	result = dvb_dmx_init(&dvb->demux);
    124	if (result < 0) {
    125		pr_warn("%s: dvb_dmx_init failed (errno = %d)\n",
    126		       dvb->name, result);
    127		goto fail_dmx;
    128	}
    129
    130	dvb->dmxdev.filternum    = 256;
    131	dvb->dmxdev.demux        = &dvb->demux.dmx;
    132	dvb->dmxdev.capabilities = 0;
    133	result = dvb_dmxdev_init(&dvb->dmxdev, adapter);
    134
    135	if (result < 0) {
    136		pr_warn("%s: dvb_dmxdev_init failed (errno = %d)\n",
    137		       dvb->name, result);
    138		goto fail_dmxdev;
    139	}
    140
    141	dvb->fe_hw.source = DMX_FRONTEND_0;
    142	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
    143	if (result < 0) {
    144		pr_warn("%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
    145		       dvb->name, result);
    146		goto fail_fe_hw;
    147	}
    148
    149	dvb->fe_mem.source = DMX_MEMORY_FE;
    150	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
    151	if (result < 0) {
    152		pr_warn("%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
    153		       dvb->name, result);
    154		goto fail_fe_mem;
    155	}
    156
    157	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
    158	if (result < 0) {
    159		pr_warn("%s: connect_frontend failed (errno = %d)\n",
    160		       dvb->name, result);
    161		goto fail_fe_conn;
    162	}
    163
    164	/* register network adapter */
    165	result = dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
    166	if (result < 0) {
    167		pr_warn("%s: dvb_net_init failed (errno = %d)\n",
    168		       dvb->name, result);
    169		goto fail_fe_conn;
    170	}
    171	return 0;
    172
    173fail_fe_conn:
    174	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
    175fail_fe_mem:
    176	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
    177fail_fe_hw:
    178	dvb_dmxdev_release(&dvb->dmxdev);
    179fail_dmxdev:
    180	dvb_dmx_release(&dvb->demux);
    181fail_dmx:
    182	dvb_unregister_frontend(dvb->frontend);
    183fail_frontend:
    184	dvb_frontend_detach(dvb->frontend);
    185	dvb->frontend = NULL;
    186
    187	return result;
    188}
    189
    190/* ------------------------------------------------------------------ */
    191/* Register a single adapter and one or more frontends */
    192int vb2_dvb_register_bus(struct vb2_dvb_frontends *f,
    193			 struct module *module,
    194			 void *adapter_priv,
    195			 struct device *device,
    196			 struct media_device *mdev,
    197			 short *adapter_nr,
    198			 int mfe_shared)
    199{
    200	struct list_head *list, *q;
    201	struct vb2_dvb_frontend *fe;
    202	int res;
    203
    204	fe = vb2_dvb_get_frontend(f, 1);
    205	if (!fe) {
    206		pr_warn("Unable to register the adapter which has no frontends\n");
    207		return -EINVAL;
    208	}
    209
    210	/* Bring up the adapter */
    211	res = vb2_dvb_register_adapter(f, module, adapter_priv, device, mdev,
    212		fe->dvb.name, adapter_nr, mfe_shared);
    213	if (res < 0) {
    214		pr_warn("vb2_dvb_register_adapter failed (errno = %d)\n", res);
    215		return res;
    216	}
    217
    218	/* Attach all of the frontends to the adapter */
    219	mutex_lock(&f->lock);
    220	list_for_each_safe(list, q, &f->felist) {
    221		fe = list_entry(list, struct vb2_dvb_frontend, felist);
    222		res = vb2_dvb_register_frontend(&f->adapter, &fe->dvb);
    223		if (res < 0) {
    224			pr_warn("%s: vb2_dvb_register_frontend failed (errno = %d)\n",
    225				fe->dvb.name, res);
    226			goto err;
    227		}
    228		res = dvb_create_media_graph(&f->adapter, false);
    229		if (res < 0)
    230			goto err;
    231	}
    232
    233	mutex_unlock(&f->lock);
    234	return 0;
    235
    236err:
    237	mutex_unlock(&f->lock);
    238	vb2_dvb_unregister_bus(f);
    239	return res;
    240}
    241EXPORT_SYMBOL(vb2_dvb_register_bus);
    242
    243void vb2_dvb_unregister_bus(struct vb2_dvb_frontends *f)
    244{
    245	vb2_dvb_dealloc_frontends(f);
    246
    247	dvb_unregister_adapter(&f->adapter);
    248}
    249EXPORT_SYMBOL(vb2_dvb_unregister_bus);
    250
    251struct vb2_dvb_frontend *vb2_dvb_get_frontend(
    252	struct vb2_dvb_frontends *f, int id)
    253{
    254	struct list_head *list, *q;
    255	struct vb2_dvb_frontend *fe, *ret = NULL;
    256
    257	mutex_lock(&f->lock);
    258
    259	list_for_each_safe(list, q, &f->felist) {
    260		fe = list_entry(list, struct vb2_dvb_frontend, felist);
    261		if (fe->id == id) {
    262			ret = fe;
    263			break;
    264		}
    265	}
    266
    267	mutex_unlock(&f->lock);
    268
    269	return ret;
    270}
    271EXPORT_SYMBOL(vb2_dvb_get_frontend);
    272
    273int vb2_dvb_find_frontend(struct vb2_dvb_frontends *f,
    274	struct dvb_frontend *p)
    275{
    276	struct list_head *list, *q;
    277	struct vb2_dvb_frontend *fe = NULL;
    278	int ret = 0;
    279
    280	mutex_lock(&f->lock);
    281
    282	list_for_each_safe(list, q, &f->felist) {
    283		fe = list_entry(list, struct vb2_dvb_frontend, felist);
    284		if (fe->dvb.frontend == p) {
    285			ret = fe->id;
    286			break;
    287		}
    288	}
    289
    290	mutex_unlock(&f->lock);
    291
    292	return ret;
    293}
    294EXPORT_SYMBOL(vb2_dvb_find_frontend);
    295
    296struct vb2_dvb_frontend *vb2_dvb_alloc_frontend(
    297	struct vb2_dvb_frontends *f, int id)
    298{
    299	struct vb2_dvb_frontend *fe;
    300
    301	fe = kzalloc(sizeof(struct vb2_dvb_frontend), GFP_KERNEL);
    302	if (fe == NULL)
    303		return NULL;
    304
    305	fe->id = id;
    306	mutex_init(&fe->dvb.lock);
    307
    308	mutex_lock(&f->lock);
    309	list_add_tail(&fe->felist, &f->felist);
    310	mutex_unlock(&f->lock);
    311	return fe;
    312}
    313EXPORT_SYMBOL(vb2_dvb_alloc_frontend);
    314
    315void vb2_dvb_dealloc_frontends(struct vb2_dvb_frontends *f)
    316{
    317	struct list_head *list, *q;
    318	struct vb2_dvb_frontend *fe;
    319
    320	mutex_lock(&f->lock);
    321	list_for_each_safe(list, q, &f->felist) {
    322		fe = list_entry(list, struct vb2_dvb_frontend, felist);
    323		if (fe->dvb.net.dvbdev) {
    324			dvb_net_release(&fe->dvb.net);
    325			fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
    326				&fe->dvb.fe_mem);
    327			fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
    328				&fe->dvb.fe_hw);
    329			dvb_dmxdev_release(&fe->dvb.dmxdev);
    330			dvb_dmx_release(&fe->dvb.demux);
    331			dvb_unregister_frontend(fe->dvb.frontend);
    332		}
    333		if (fe->dvb.frontend)
    334			/* always allocated, may have been reset */
    335			dvb_frontend_detach(fe->dvb.frontend);
    336		list_del(list); /* remove list entry */
    337		kfree(fe);	/* free frontend allocation */
    338	}
    339	mutex_unlock(&f->lock);
    340}
    341EXPORT_SYMBOL(vb2_dvb_dealloc_frontends);