brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 5df67da Raw
263 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * c8sectpfe-common.c - C8SECTPFE STi DVB driver4 *5 * Copyright (c) STMicroelectronics 20156 *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}263