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

c8sectpfe-common.c (5926B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * c8sectpfe-common.c - C8SECTPFE STi DVB driver
      4 *
      5 * Copyright (c) STMicroelectronics 2015
      6 *
      7 *   Author: Peter Griffin <peter.griffin@linaro.org>
      8 *
      9 */
     10#include <linux/completion.h>
     11#include <linux/delay.h>
     12#include <linux/device.h>
     13#include <linux/dvb/dmx.h>
     14#include <linux/errno.h>
     15#include <linux/init.h>
     16#include <linux/interrupt.h>
     17#include <linux/io.h>
     18#include <linux/ioport.h>
     19#include <linux/module.h>
     20#include <linux/slab.h>
     21#include <linux/time.h>
     22#include <linux/wait.h>
     23
     24#include <media/dmxdev.h>
     25#include <media/dvbdev.h>
     26#include <media/dvb_demux.h>
     27#include <media/dvb_frontend.h>
     28#include <media/dvb_net.h>
     29
     30#include "c8sectpfe-common.h"
     31#include "c8sectpfe-core.h"
     32#include "c8sectpfe-dvb.h"
     33
     34static int register_dvb(struct stdemux *demux, struct dvb_adapter *adap,
     35				void *start_feed, void *stop_feed,
     36				struct c8sectpfei *fei)
     37{
     38	int result;
     39
     40	demux->dvb_demux.dmx.capabilities = DMX_TS_FILTERING |
     41					DMX_SECTION_FILTERING |
     42					DMX_MEMORY_BASED_FILTERING;
     43
     44	demux->dvb_demux.priv = demux;
     45	demux->dvb_demux.filternum = C8SECTPFE_MAXCHANNEL;
     46	demux->dvb_demux.feednum = C8SECTPFE_MAXCHANNEL;
     47
     48	demux->dvb_demux.start_feed = start_feed;
     49	demux->dvb_demux.stop_feed = stop_feed;
     50	demux->dvb_demux.write_to_decoder = NULL;
     51
     52	result = dvb_dmx_init(&demux->dvb_demux);
     53	if (result < 0) {
     54		dev_err(fei->dev, "dvb_dmx_init failed (errno = %d)\n",
     55			result);
     56		goto err_dmx;
     57	}
     58
     59	demux->dmxdev.filternum = demux->dvb_demux.filternum;
     60	demux->dmxdev.demux = &demux->dvb_demux.dmx;
     61	demux->dmxdev.capabilities = 0;
     62
     63	result = dvb_dmxdev_init(&demux->dmxdev, adap);
     64	if (result < 0) {
     65		dev_err(fei->dev, "dvb_dmxdev_init failed (errno = %d)\n",
     66			result);
     67
     68		goto err_dmxdev;
     69	}
     70
     71	demux->hw_frontend.source = DMX_FRONTEND_0 + demux->tsin_index;
     72
     73	result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
     74						&demux->hw_frontend);
     75	if (result < 0) {
     76		dev_err(fei->dev, "add_frontend failed (errno = %d)\n", result);
     77		goto err_fe_hw;
     78	}
     79
     80	demux->mem_frontend.source = DMX_MEMORY_FE;
     81	result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
     82						&demux->mem_frontend);
     83	if (result < 0) {
     84		dev_err(fei->dev, "add_frontend failed (%d)\n", result);
     85		goto err_fe_mem;
     86	}
     87
     88	result = demux->dvb_demux.dmx.connect_frontend(&demux->dvb_demux.dmx,
     89							&demux->hw_frontend);
     90	if (result < 0) {
     91		dev_err(fei->dev, "connect_frontend (%d)\n", result);
     92		goto err_fe_con;
     93	}
     94
     95	return 0;
     96
     97err_fe_con:
     98	demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
     99						     &demux->mem_frontend);
    100err_fe_mem:
    101	demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
    102						     &demux->hw_frontend);
    103err_fe_hw:
    104	dvb_dmxdev_release(&demux->dmxdev);
    105err_dmxdev:
    106	dvb_dmx_release(&demux->dvb_demux);
    107err_dmx:
    108	return result;
    109
    110}
    111
    112static void unregister_dvb(struct stdemux *demux)
    113{
    114
    115	demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
    116						     &demux->mem_frontend);
    117
    118	demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
    119						     &demux->hw_frontend);
    120
    121	dvb_dmxdev_release(&demux->dmxdev);
    122
    123	dvb_dmx_release(&demux->dvb_demux);
    124}
    125
    126static struct c8sectpfe *c8sectpfe_create(struct c8sectpfei *fei,
    127				void *start_feed,
    128				void *stop_feed)
    129{
    130	struct c8sectpfe *c8sectpfe;
    131	int result;
    132	int i, j;
    133
    134	short int ids[] = { -1 };
    135
    136	c8sectpfe = kzalloc(sizeof(struct c8sectpfe), GFP_KERNEL);
    137	if (!c8sectpfe)
    138		goto err1;
    139
    140	mutex_init(&c8sectpfe->lock);
    141
    142	c8sectpfe->device = fei->dev;
    143
    144	result = dvb_register_adapter(&c8sectpfe->adapter, "STi c8sectpfe",
    145					THIS_MODULE, fei->dev, ids);
    146	if (result < 0) {
    147		dev_err(fei->dev, "dvb_register_adapter failed (errno = %d)\n",
    148			result);
    149		goto err2;
    150	}
    151
    152	c8sectpfe->adapter.priv = fei;
    153
    154	for (i = 0; i < fei->tsin_count; i++) {
    155
    156		c8sectpfe->demux[i].tsin_index = i;
    157		c8sectpfe->demux[i].c8sectpfei = fei;
    158
    159		result = register_dvb(&c8sectpfe->demux[i], &c8sectpfe->adapter,
    160				start_feed, stop_feed, fei);
    161		if (result < 0) {
    162			dev_err(fei->dev,
    163				"register_dvb feed=%d failed (errno = %d)\n",
    164				result, i);
    165
    166			/* we take a all or nothing approach */
    167			for (j = 0; j < i; j++)
    168				unregister_dvb(&c8sectpfe->demux[j]);
    169			goto err3;
    170		}
    171	}
    172
    173	c8sectpfe->num_feeds = fei->tsin_count;
    174
    175	return c8sectpfe;
    176err3:
    177	dvb_unregister_adapter(&c8sectpfe->adapter);
    178err2:
    179	kfree(c8sectpfe);
    180err1:
    181	return NULL;
    182};
    183
    184static void c8sectpfe_delete(struct c8sectpfe *c8sectpfe)
    185{
    186	int i;
    187
    188	if (!c8sectpfe)
    189		return;
    190
    191	for (i = 0; i < c8sectpfe->num_feeds; i++)
    192		unregister_dvb(&c8sectpfe->demux[i]);
    193
    194	dvb_unregister_adapter(&c8sectpfe->adapter);
    195
    196	kfree(c8sectpfe);
    197};
    198
    199void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe,
    200					struct c8sectpfei *fei)
    201{
    202	int n;
    203	struct channel_info *tsin;
    204
    205	for (n = 0; n < fei->tsin_count; n++) {
    206
    207		tsin = fei->channel_data[n];
    208
    209		if (tsin) {
    210			if (tsin->frontend) {
    211				dvb_unregister_frontend(tsin->frontend);
    212				dvb_frontend_detach(tsin->frontend);
    213			}
    214
    215			i2c_put_adapter(tsin->i2c_adapter);
    216
    217			if (tsin->i2c_client) {
    218				module_put(tsin->i2c_client->dev.driver->owner);
    219				i2c_unregister_device(tsin->i2c_client);
    220			}
    221		}
    222	}
    223
    224	c8sectpfe_delete(c8sectpfe);
    225};
    226
    227int c8sectpfe_tuner_register_frontend(struct c8sectpfe **c8sectpfe,
    228				struct c8sectpfei *fei,
    229				void *start_feed,
    230				void *stop_feed)
    231{
    232	struct channel_info *tsin;
    233	struct dvb_frontend *frontend;
    234	int n, res;
    235
    236	*c8sectpfe = c8sectpfe_create(fei, start_feed, stop_feed);
    237	if (!*c8sectpfe)
    238		return -ENOMEM;
    239
    240	for (n = 0; n < fei->tsin_count; n++) {
    241		tsin = fei->channel_data[n];
    242
    243		res = c8sectpfe_frontend_attach(&frontend, *c8sectpfe, tsin, n);
    244		if (res)
    245			goto err;
    246
    247		res = dvb_register_frontend(&c8sectpfe[0]->adapter, frontend);
    248		if (res < 0) {
    249			dev_err(fei->dev, "dvb_register_frontend failed (%d)\n",
    250				res);
    251			goto err;
    252		}
    253
    254		tsin->frontend = frontend;
    255	}
    256
    257	return 0;
    258
    259err:
    260	c8sectpfe_tuner_unregister_frontend(*c8sectpfe, fei);
    261	return res;
    262}