123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /*
- * c8sectpfe-common.c - C8SECTPFE STi DVB driver
- *
- * Copyright (c) STMicroelectronics 2015
- *
- * Author: Peter Griffin <peter.griffin@linaro.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
- #include <linux/completion.h>
- #include <linux/delay.h>
- #include <linux/device.h>
- #include <linux/dvb/dmx.h>
- #include <linux/errno.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/ioport.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/time.h>
- #include <linux/wait.h>
- #include "dmxdev.h"
- #include "dvbdev.h"
- #include "dvb_demux.h"
- #include "dvb_frontend.h"
- #include "dvb_net.h"
- #include "c8sectpfe-common.h"
- #include "c8sectpfe-core.h"
- #include "c8sectpfe-dvb.h"
- static int register_dvb(struct stdemux *demux, struct dvb_adapter *adap,
- void *start_feed, void *stop_feed,
- struct c8sectpfei *fei)
- {
- int result;
- demux->dvb_demux.dmx.capabilities = DMX_TS_FILTERING |
- DMX_SECTION_FILTERING |
- DMX_MEMORY_BASED_FILTERING;
- demux->dvb_demux.priv = demux;
- demux->dvb_demux.filternum = C8SECTPFE_MAXCHANNEL;
- demux->dvb_demux.feednum = C8SECTPFE_MAXCHANNEL;
- demux->dvb_demux.start_feed = start_feed;
- demux->dvb_demux.stop_feed = stop_feed;
- demux->dvb_demux.write_to_decoder = NULL;
- result = dvb_dmx_init(&demux->dvb_demux);
- if (result < 0) {
- dev_err(fei->dev, "dvb_dmx_init failed (errno = %d)\n",
- result);
- goto err_dmx;
- }
- demux->dmxdev.filternum = demux->dvb_demux.filternum;
- demux->dmxdev.demux = &demux->dvb_demux.dmx;
- demux->dmxdev.capabilities = 0;
- result = dvb_dmxdev_init(&demux->dmxdev, adap);
- if (result < 0) {
- dev_err(fei->dev, "dvb_dmxdev_init failed (errno = %d)\n",
- result);
- goto err_dmxdev;
- }
- demux->hw_frontend.source = DMX_FRONTEND_0 + demux->tsin_index;
- result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
- &demux->hw_frontend);
- if (result < 0) {
- dev_err(fei->dev, "add_frontend failed (errno = %d)\n", result);
- goto err_fe_hw;
- }
- demux->mem_frontend.source = DMX_MEMORY_FE;
- result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
- &demux->mem_frontend);
- if (result < 0) {
- dev_err(fei->dev, "add_frontend failed (%d)\n", result);
- goto err_fe_mem;
- }
- result = demux->dvb_demux.dmx.connect_frontend(&demux->dvb_demux.dmx,
- &demux->hw_frontend);
- if (result < 0) {
- dev_err(fei->dev, "connect_frontend (%d)\n", result);
- goto err_fe_con;
- }
- return 0;
- err_fe_con:
- demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
- &demux->mem_frontend);
- err_fe_mem:
- demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
- &demux->hw_frontend);
- err_fe_hw:
- dvb_dmxdev_release(&demux->dmxdev);
- err_dmxdev:
- dvb_dmx_release(&demux->dvb_demux);
- err_dmx:
- return result;
- }
- static void unregister_dvb(struct stdemux *demux)
- {
- demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
- &demux->mem_frontend);
- demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
- &demux->hw_frontend);
- dvb_dmxdev_release(&demux->dmxdev);
- dvb_dmx_release(&demux->dvb_demux);
- }
- static struct c8sectpfe *c8sectpfe_create(struct c8sectpfei *fei,
- void *start_feed,
- void *stop_feed)
- {
- struct c8sectpfe *c8sectpfe;
- int result;
- int i, j;
- short int ids[] = { -1 };
- c8sectpfe = kzalloc(sizeof(struct c8sectpfe), GFP_KERNEL);
- if (!c8sectpfe)
- goto err1;
- mutex_init(&c8sectpfe->lock);
- c8sectpfe->device = fei->dev;
- result = dvb_register_adapter(&c8sectpfe->adapter, "STi c8sectpfe",
- THIS_MODULE, fei->dev, ids);
- if (result < 0) {
- dev_err(fei->dev, "dvb_register_adapter failed (errno = %d)\n",
- result);
- goto err2;
- }
- c8sectpfe->adapter.priv = fei;
- for (i = 0; i < fei->tsin_count; i++) {
- c8sectpfe->demux[i].tsin_index = i;
- c8sectpfe->demux[i].c8sectpfei = fei;
- result = register_dvb(&c8sectpfe->demux[i], &c8sectpfe->adapter,
- start_feed, stop_feed, fei);
- if (result < 0) {
- dev_err(fei->dev,
- "register_dvb feed=%d failed (errno = %d)\n",
- result, i);
- /* we take a all or nothing approach */
- for (j = 0; j < i; j++)
- unregister_dvb(&c8sectpfe->demux[j]);
- goto err3;
- }
- }
- c8sectpfe->num_feeds = fei->tsin_count;
- return c8sectpfe;
- err3:
- dvb_unregister_adapter(&c8sectpfe->adapter);
- err2:
- kfree(c8sectpfe);
- err1:
- return NULL;
- };
- static void c8sectpfe_delete(struct c8sectpfe *c8sectpfe)
- {
- int i;
- if (!c8sectpfe)
- return;
- for (i = 0; i < c8sectpfe->num_feeds; i++)
- unregister_dvb(&c8sectpfe->demux[i]);
- dvb_unregister_adapter(&c8sectpfe->adapter);
- kfree(c8sectpfe);
- };
- void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe,
- struct c8sectpfei *fei)
- {
- int n;
- struct channel_info *tsin;
- for (n = 0; n < fei->tsin_count; n++) {
- tsin = fei->channel_data[n];
- if (tsin && tsin->frontend) {
- dvb_unregister_frontend(tsin->frontend);
- dvb_frontend_detach(tsin->frontend);
- }
- if (tsin && tsin->i2c_adapter)
- i2c_put_adapter(tsin->i2c_adapter);
- if (tsin && tsin->i2c_client) {
- if (tsin->i2c_client->dev.driver->owner)
- module_put(tsin->i2c_client->dev.driver->owner);
- i2c_unregister_device(tsin->i2c_client);
- }
- }
- c8sectpfe_delete(c8sectpfe);
- };
- int c8sectpfe_tuner_register_frontend(struct c8sectpfe **c8sectpfe,
- struct c8sectpfei *fei,
- void *start_feed,
- void *stop_feed)
- {
- struct channel_info *tsin;
- struct dvb_frontend *frontend;
- int n, res;
- *c8sectpfe = c8sectpfe_create(fei, start_feed, stop_feed);
- if (!*c8sectpfe)
- return -ENOMEM;
- for (n = 0; n < fei->tsin_count; n++) {
- tsin = fei->channel_data[n];
- res = c8sectpfe_frontend_attach(&frontend, *c8sectpfe, tsin, n);
- if (res)
- goto err;
- res = dvb_register_frontend(&c8sectpfe[0]->adapter, frontend);
- if (res < 0) {
- dev_err(fei->dev, "dvb_register_frontend failed (%d)\n",
- res);
- goto err;
- }
- tsin->frontend = frontend;
- }
- return 0;
- err:
- c8sectpfe_tuner_unregister_frontend(*c8sectpfe, fei);
- return res;
- }
|