1 /*
2 * Copyright (c) 2016 - Mauro Carvalho Chehab
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation version 2.1 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17 */
18
19 #include <libudev.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <locale.h>
23 #include <unistd.h>
24 #include <string.h>
25
26 #include "dvb-fe-priv.h"
27 #include "dvb-dev-priv.h"
28
29 #ifdef ENABLE_NLS
30 # include "gettext.h"
31 # include <libintl.h>
32 # define _(string) dgettext(LIBDVBV5_DOMAIN, string)
33 #else
34 # define _(string) string
35 #endif
36
37 const char * const dev_type_names[] = {
38 "frontend", "demux", "dvr", "net", "ca", "sec", "video", "audio"
39 };
40
41 const unsigned int
42 dev_type_names_size = sizeof(dev_type_names)/sizeof(*dev_type_names);
43
free_dvb_dev(struct dvb_dev_list * dvb_dev)44 void free_dvb_dev(struct dvb_dev_list *dvb_dev)
45 {
46 if (dvb_dev->path)
47 free(dvb_dev->path);
48 if (dvb_dev->syspath)
49 free(dvb_dev->syspath);
50 if (dvb_dev->sysname)
51 free(dvb_dev->sysname);
52 if (dvb_dev->bus_addr)
53 free(dvb_dev->bus_addr);
54 if (dvb_dev->bus_id)
55 free(dvb_dev->bus_id);
56 if (dvb_dev->manufacturer)
57 free(dvb_dev->manufacturer);
58 if (dvb_dev->product)
59 free(dvb_dev->product);
60 if (dvb_dev->serial)
61 free(dvb_dev->serial);
62 }
63
dvb_dev_alloc(void)64 struct dvb_device *dvb_dev_alloc(void)
65 {
66 struct dvb_device_priv *dvb;
67 struct dvb_v5_fe_parms_priv *parms;
68
69 dvb = calloc(1, sizeof(struct dvb_device_priv));
70 if (!dvb)
71 return NULL;
72
73 dvb->d.fe_parms = dvb_fe_dummy();
74 if (!dvb->d.fe_parms) {
75 dvb_dev_free(&dvb->d);
76 return NULL;
77 }
78 parms = (void *)dvb->d.fe_parms;
79 parms->dvb = dvb;
80
81 /* Initialize it to use the local DVB devices */
82 dvb_dev_local_init(dvb);
83
84 return &dvb->d;
85 }
86
dvb_dev_free_devices(struct dvb_device_priv * dvb)87 void dvb_dev_free_devices(struct dvb_device_priv *dvb)
88 {
89 int i;
90
91 for (i = 0; i < dvb->d.num_devices; i++)
92 free_dvb_dev(&dvb->d.devices[i]);
93 free(dvb->d.devices);
94
95 dvb->d.devices = NULL;
96 dvb->d.num_devices = 0;
97 }
98
dvb_dev_free(struct dvb_device * d)99 void dvb_dev_free(struct dvb_device *d)
100 {
101 struct dvb_device_priv *dvb = (void *)d;
102 struct dvb_open_descriptor *cur, *next;
103 struct dvb_dev_ops *ops = &dvb->ops;
104
105 /* Close all devices */
106 cur = dvb->open_list.next;
107 while (cur) {
108 next = cur->next;
109 dvb_dev_close(cur);
110 cur = next;
111 }
112
113 /* Call an implementation-specific free method, if defined */
114 if (ops->free)
115 ops->free(dvb);
116
117 dvb_fe_close(dvb->d.fe_parms);
118
119 dvb_dev_free_devices(dvb);
120
121 free(dvb);
122 }
123
dvb_dev_dump_device(char * msg,struct dvb_v5_fe_parms_priv * parms,struct dvb_dev_list * dev)124 void dvb_dev_dump_device(char *msg,
125 struct dvb_v5_fe_parms_priv *parms,
126 struct dvb_dev_list *dev)
127 {
128 if (parms->p.verbose < 2)
129 return;
130
131 dvb_log(msg, dev_type_names[dev->dvb_type], dev->sysname);
132
133 if (dev->path)
134 dvb_log(_(" path: %s"), dev->path);
135 if (dev->syspath)
136 dvb_log(_(" sysfs path: %s"), dev->syspath);
137 if (dev->bus_addr)
138 dvb_log(_(" bus addr: %s"), dev->bus_addr);
139 if (dev->bus_id)
140 dvb_log(_(" bus ID: %s"), dev->bus_id);
141 if (dev->manufacturer)
142 dvb_log(_(" manufacturer: %s"), dev->manufacturer);
143 if (dev->product)
144 dvb_log(_(" product: %s"), dev->product);
145 if (dev->serial)
146 dvb_log(_(" serial: %s"), dev->serial);
147 }
148
dvb_dev_seek_by_adapter(struct dvb_device * d,unsigned int adapter,unsigned int num,enum dvb_dev_type type)149 struct dvb_dev_list *dvb_dev_seek_by_adapter(struct dvb_device *d,
150 unsigned int adapter,
151 unsigned int num,
152 enum dvb_dev_type type)
153 {
154 struct dvb_device_priv *dvb = (void *)d;
155 struct dvb_dev_ops *ops = &dvb->ops;
156
157 if (!ops->seek_by_adapter)
158 return NULL;
159
160 return ops->seek_by_adapter(dvb, adapter, num, type);
161 }
162
dvb_dev_set_logpriv(struct dvb_device * dvb,unsigned verbose,dvb_logfunc_priv logfunc_priv,void * logpriv)163 void dvb_dev_set_logpriv(struct dvb_device *dvb, unsigned verbose,
164 dvb_logfunc_priv logfunc_priv, void *logpriv)
165 {
166 struct dvb_v5_fe_parms_priv *parms = (void *)dvb->fe_parms;
167
168 /* FIXME: how to get remote logs and set verbosity? */
169 parms->p.verbose = verbose;
170 parms->logpriv = logpriv;
171
172 if (logfunc_priv != NULL)
173 parms->logfunc_priv = logfunc_priv;
174 }
175
dvb_dev_set_log(struct dvb_device * dvb,unsigned verbose,dvb_logfunc logfunc)176 void dvb_dev_set_log(struct dvb_device *dvb, unsigned verbose,
177 dvb_logfunc logfunc)
178 {
179 struct dvb_v5_fe_parms_priv *parms = (void *)dvb->fe_parms;
180
181 /* FIXME: how to get remote logs and set verbosity? */
182 parms->p.verbose = verbose;
183
184 if (logfunc != NULL)
185 parms->p.logfunc = logfunc;
186 }
187
dvb_dev_find(struct dvb_device * d,dvb_dev_change_t handler,void * user_priv)188 int dvb_dev_find(struct dvb_device *d, dvb_dev_change_t handler, void *user_priv)
189 {
190 struct dvb_device_priv *dvb = (void *)d;
191 struct dvb_dev_ops *ops = &dvb->ops;
192
193 if (!ops->find)
194 return -1;
195
196 return ops->find(dvb, handler, user_priv);
197 }
198
dvb_dev_stop_monitor(struct dvb_device * d)199 void dvb_dev_stop_monitor(struct dvb_device *d)
200 {
201 struct dvb_device_priv *dvb = (void *)d;
202 struct dvb_dev_ops *ops = &dvb->ops;
203
204 if (ops->stop_monitor)
205 ops->stop_monitor(dvb);
206 }
207
dvb_get_dev_info(struct dvb_device * d,const char * sysname)208 struct dvb_dev_list *dvb_get_dev_info(struct dvb_device *d,
209 const char *sysname)
210 {
211 struct dvb_device_priv *dvb = (void *)d;
212 struct dvb_dev_ops *ops = &dvb->ops;
213
214 if (!ops->get_dev_info)
215 return NULL;
216
217 return ops->get_dev_info(dvb, sysname);
218 }
219
dvb_dev_open(struct dvb_device * d,const char * sysname,int flags)220 struct dvb_open_descriptor *dvb_dev_open(struct dvb_device *d,
221 const char *sysname, int flags)
222 {
223 struct dvb_device_priv *dvb = (void *)d;
224 struct dvb_dev_ops *ops = &dvb->ops;
225
226 if (!ops->open)
227 return NULL;
228
229 return ops->open(dvb, sysname, flags);
230 }
231
dvb_dev_get_fd(struct dvb_open_descriptor * open_dev)232 int dvb_dev_get_fd(struct dvb_open_descriptor *open_dev)
233 {
234 struct dvb_device_priv *dvb = open_dev->dvb;
235 struct dvb_dev_ops *ops = &dvb->ops;
236
237 if (!ops->get_fd)
238 return -1;
239
240 return ops->get_fd(open_dev);
241 }
242
dvb_dev_close(struct dvb_open_descriptor * open_dev)243 void dvb_dev_close(struct dvb_open_descriptor *open_dev)
244 {
245 struct dvb_device_priv *dvb = open_dev->dvb;
246 struct dvb_dev_ops *ops = &dvb->ops;
247
248 if (ops->close)
249 ops->close(open_dev);
250 }
251
dvb_dev_dmx_stop(struct dvb_open_descriptor * open_dev)252 void dvb_dev_dmx_stop(struct dvb_open_descriptor *open_dev)
253 {
254 struct dvb_device_priv *dvb = open_dev->dvb;
255 struct dvb_dev_ops *ops = &dvb->ops;
256
257 if (ops->dmx_stop)
258 ops->dmx_stop(open_dev);
259 }
260
dvb_dev_set_bufsize(struct dvb_open_descriptor * open_dev,int buffersize)261 int dvb_dev_set_bufsize(struct dvb_open_descriptor *open_dev,
262 int buffersize)
263 {
264 struct dvb_device_priv *dvb = open_dev->dvb;
265 struct dvb_dev_ops *ops = &dvb->ops;
266
267 if (!ops->set_bufsize)
268 return -1;
269
270 return ops->set_bufsize(open_dev, buffersize);
271 }
272
dvb_dev_read(struct dvb_open_descriptor * open_dev,void * buf,size_t count)273 ssize_t dvb_dev_read(struct dvb_open_descriptor *open_dev,
274 void *buf, size_t count)
275 {
276 struct dvb_device_priv *dvb = open_dev->dvb;
277 struct dvb_dev_ops *ops = &dvb->ops;
278
279 if (!ops->read)
280 return -1;
281
282 return ops->read(open_dev, buf, count);
283 }
284
dvb_dev_dmx_set_pesfilter(struct dvb_open_descriptor * open_dev,int pid,dmx_pes_type_t type,dmx_output_t output,int bufsize)285 int dvb_dev_dmx_set_pesfilter(struct dvb_open_descriptor *open_dev,
286 int pid, dmx_pes_type_t type,
287 dmx_output_t output, int bufsize)
288 {
289 struct dvb_device_priv *dvb = open_dev->dvb;
290 struct dvb_dev_ops *ops = &dvb->ops;
291
292 if (!ops->dmx_set_pesfilter)
293 return -1;
294
295 return ops->dmx_set_pesfilter(open_dev, pid, type, output, bufsize);
296 }
297
dvb_dev_dmx_set_section_filter(struct dvb_open_descriptor * open_dev,int pid,unsigned filtsize,unsigned char * filter,unsigned char * mask,unsigned char * mode,unsigned int flags)298 int dvb_dev_dmx_set_section_filter(struct dvb_open_descriptor *open_dev,
299 int pid, unsigned filtsize,
300 unsigned char *filter,
301 unsigned char *mask,
302 unsigned char *mode,
303 unsigned int flags)
304 {
305 struct dvb_device_priv *dvb = open_dev->dvb;
306 struct dvb_dev_ops *ops = &dvb->ops;
307
308 if (!ops->dmx_set_section_filter)
309 return -1;
310
311 return ops->dmx_set_section_filter(open_dev, pid, filtsize, filter,
312 mask, mode, flags);
313 }
314
dvb_dev_dmx_get_pmt_pid(struct dvb_open_descriptor * open_dev,int sid)315 int dvb_dev_dmx_get_pmt_pid(struct dvb_open_descriptor *open_dev, int sid)
316 {
317 struct dvb_device_priv *dvb = open_dev->dvb;
318 struct dvb_dev_ops *ops = &dvb->ops;
319
320 if (!ops->dmx_get_pmt_pid)
321 return -1;
322
323 return ops->dmx_get_pmt_pid(open_dev, sid);
324 }
325
dvb_dev_scan(struct dvb_open_descriptor * open_dev,struct dvb_entry * entry,check_frontend_t * check_frontend,void * args,unsigned other_nit,unsigned timeout_multiply)326 struct dvb_v5_descriptors *dvb_dev_scan(struct dvb_open_descriptor *open_dev,
327 struct dvb_entry *entry,
328 check_frontend_t *check_frontend,
329 void *args,
330 unsigned other_nit,
331 unsigned timeout_multiply)
332 {
333 struct dvb_device_priv *dvb = open_dev->dvb;
334 struct dvb_dev_ops *ops = &dvb->ops;
335
336 if (!ops->scan)
337 return NULL;
338
339 return ops->scan(open_dev, entry, check_frontend, args, other_nit,
340 timeout_multiply);
341 }
342
343 /* Frontend functions that can be overriden */
344
dvb_set_sys(struct dvb_v5_fe_parms * p,fe_delivery_system_t sys)345 int dvb_set_sys(struct dvb_v5_fe_parms *p, fe_delivery_system_t sys)
346 {
347 struct dvb_v5_fe_parms_priv *parms = (void *)p;
348 struct dvb_device_priv *dvb = parms->dvb;
349
350 if (!dvb || !dvb->ops.fe_set_sys)
351 return __dvb_set_sys(p, sys);
352
353 return dvb->ops.fe_set_sys(p, sys);
354 }
355
dvb_fe_get_parms(struct dvb_v5_fe_parms * p)356 int dvb_fe_get_parms(struct dvb_v5_fe_parms *p)
357 {
358 struct dvb_v5_fe_parms_priv *parms = (void *)p;
359 struct dvb_device_priv *dvb = parms->dvb;
360
361 if (!dvb || !dvb->ops.fe_get_parms)
362 return __dvb_fe_get_parms(p);
363
364 return dvb->ops.fe_get_parms(p);
365 }
366
dvb_fe_set_parms(struct dvb_v5_fe_parms * p)367 int dvb_fe_set_parms(struct dvb_v5_fe_parms *p)
368 {
369 struct dvb_v5_fe_parms_priv *parms = (void *)p;
370 struct dvb_device_priv *dvb = parms->dvb;
371
372 if (!dvb || !dvb->ops.fe_set_parms)
373 return __dvb_fe_set_parms(p);
374
375 return dvb->ops.fe_set_parms(p);
376 }
377
dvb_fe_get_stats(struct dvb_v5_fe_parms * p)378 int dvb_fe_get_stats(struct dvb_v5_fe_parms *p)
379 {
380 struct dvb_v5_fe_parms_priv *parms = (void *)p;
381 struct dvb_device_priv *dvb = parms->dvb;
382
383 if (!dvb || !dvb->ops.fe_get_stats)
384 return __dvb_fe_get_stats(p);
385
386 return dvb->ops.fe_get_stats(p);
387 }
388