brintos

brintos / linux-shallow public Read only

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