root/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. register_dvb
  2. unregister_dvb
  3. c8sectpfe_create
  4. c8sectpfe_delete
  5. c8sectpfe_tuner_unregister_frontend
  6. c8sectpfe_tuner_register_frontend

   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 
  34 static 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 
  97 err_fe_con:
  98         demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
  99                                                      &demux->mem_frontend);
 100 err_fe_mem:
 101         demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
 102                                                      &demux->hw_frontend);
 103 err_fe_hw:
 104         dvb_dmxdev_release(&demux->dmxdev);
 105 err_dmxdev:
 106         dvb_dmx_release(&demux->dvb_demux);
 107 err_dmx:
 108         return result;
 109 
 110 }
 111 
 112 static 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 
 126 static 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;
 176 err3:
 177         dvb_unregister_adapter(&c8sectpfe->adapter);
 178 err2:
 179         kfree(c8sectpfe);
 180 err1:
 181         return NULL;
 182 };
 183 
 184 static 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 
 199 void 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 
 227 int 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 
 259 err:
 260         c8sectpfe_tuner_unregister_frontend(*c8sectpfe, fei);
 261         return res;
 262 }

/* [<][>][^][v][top][bottom][index][help] */