1 /*
2 * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * Description:
19 */
20 #include <linux/version.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/mutex.h>
24 #include <linux/wait.h>
25 #include <linux/string.h>
26 #include <linux/interrupt.h>
27 #include <linux/fs.h>
28 #include <linux/cdev.h>
29 #include <linux/device.h>
30 #include <linux/spinlock.h>
31 #include <linux/fcntl.h>
32 #include <linux/slab.h>
33 #include <linux/uaccess.h>
34 #include <linux/poll.h>
35 #include <linux/delay.h>
36 #include <linux/platform_device.h>
37 #include <linux/gpio.h>
38 #include <linux/string.h>
39 #include <linux/vmalloc.h>
40 #include <linux/poll.h>
41 #include <linux/crc32.h>
42 #include <asm/uaccess.h>
43 #include <asm/div64.h>
44
45 //#include "aml_dvb.h"
46 #include "aml_dmx.h"
47 #include "aml_dmx_ext.h"
48 //#include "hwdemux.h"
49
50 #define pr_error(fmt, args...) printk("DVB: " fmt, ## args)
51 #define pr_inf(fmt, args...) printk(KERN_DEBUG fmt, ## args)
52
53 #define MAX_SEC_FEED_NUM 20
54 #define MAX_TS_FEED_NUM 20
55 #define MAX_FILTER_PER_SEC_FEED 8
56
57
58 #define DMX_STATE_FREE 0
59 #define DMX_STATE_ALLOCATED 1
60 #define DMX_STATE_SET 2
61 #define DMX_STATE_READY 3
62 #define DMX_STATE_GO 4
63
64 #define SWDMX_MAX_PID 0x1fff
65
66 #define DMX_TYPE_TS 0
67 #define DMX_TYPE_SEC 1
68 #define DMX_TYPE_PES 2
69
70 static int _dmx_write(struct aml_dmx *pdmx, const u8 *buf, size_t count);
71
72
_invert_mode(struct dmx_section_filter * filter)73 static inline void _invert_mode(struct dmx_section_filter *filter)
74 {
75 int i;
76
77 for (i = 0; i < DMX_FILTER_SIZE; i++)
78 filter->filter_mode[i] ^= 0xff;
79 }
80
_dmx_open(struct dmx_demux * demux)81 static int _dmx_open(struct dmx_demux *demux)
82 {
83 struct aml_dmx *pdmx = (struct aml_dmx *)demux->priv;
84
85 if (pdmx->users >= MAX_SW_DEMUX_USERS)
86 return -EUSERS;
87
88 pdmx->users++;
89 return 0;
90 }
91
_dmx_close(struct dmx_demux * demux)92 static int _dmx_close(struct dmx_demux *demux)
93 {
94 struct aml_dmx *pdmx = (struct aml_dmx *)demux->priv;
95
96 if (pdmx->users == 0)
97 return -ENODEV;
98
99 pdmx->users--;
100
101 if (pdmx->users == 0) {
102 if (pdmx->used_hwdmx)
103 hwdmx_inject_destroy(pdmx->hwdmx);
104 }
105 //FIXME: release any unneeded resources if users==0
106 return 0;
107 }
108
_dmx_write_from_user(struct dmx_demux * demux,const char __user * buf,size_t count)109 static int _dmx_write_from_user(struct dmx_demux *demux, const char __user *buf, size_t count)
110 {
111 struct aml_dmx *pdmx = (struct aml_dmx *)demux->priv;
112 void *p;
113 int ret = 0;
114
115 if (pdmx->used_hwdmx) {
116 ret = hwdmx_inject(pdmx->hwdmx, buf, count);
117 return ret;
118 }
119 // pr_inf("_dmx_write_from_user\n");
120 p = memdup_user(buf, count);
121 if (IS_ERR(p)) {
122 pr_error("get fail mem pointer\n");
123 return PTR_ERR(p);
124 }
125 ret = _dmx_write(pdmx, p, count);
126
127 kfree(p);
128
129 if (signal_pending(current))
130 return -EINTR;
131 return ret;
132 }
133
_dmx_section_feed_alloc(struct aml_dmx * demux)134 static struct sw_demux_sec_feed *_dmx_section_feed_alloc(struct aml_dmx *demux)
135 {
136 int i;
137
138 for (i = 0; i < demux->sec_feed_num; i++)
139 if (demux->section_feed[i].state == DMX_STATE_FREE)
140 break;
141
142 if (i == demux->sec_feed_num)
143 return NULL;
144
145 demux->section_feed[i].state = DMX_STATE_ALLOCATED;
146
147 return &demux->section_feed[i];
148 }
149
_dmx_ts_feed_alloc(struct aml_dmx * demux)150 static struct sw_demux_ts_feed *_dmx_ts_feed_alloc(struct aml_dmx *demux)
151 {
152 int i;
153
154 for (i = 0; i < demux->ts_feed_num; i++)
155 if (demux->ts_feed[i].state == DMX_STATE_FREE)
156 break;
157
158 if (i == demux->ts_feed_num)
159 return NULL;
160
161 demux->ts_feed[i].state = DMX_STATE_ALLOCATED;
162
163 return &demux->ts_feed[i];
164 }
165
_dmx_dmx_sec_filter_alloc(struct sw_demux_sec_feed * sec_feed)166 static struct sw_demux_sec_filter *_dmx_dmx_sec_filter_alloc(struct sw_demux_sec_feed *sec_feed)
167 {
168 int i;
169
170 for (i = 0; i < MAX_FILTER_PER_SEC_FEED; i++)
171 if (sec_feed->filter[i].state == DMX_STATE_FREE)
172 break;
173
174 if (i == MAX_FILTER_PER_SEC_FEED)
175 return NULL;
176
177 sec_feed->filter[i].state = DMX_STATE_ALLOCATED;
178
179 return &sec_feed->filter[i];
180 }
181 #if 0
182 static void prdump(const char* m, const void* data, uint32_t len) {
183 if (m)
184 pr_error("%s:\n", m);
185 if (data) {
186 size_t i = 0;
187 const unsigned char *c __attribute__((unused)) = data;
188 while (len >= 16) {
189 pr_error("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
190 c[i], c[i+1], c[i+2], c[i+3], c[i+4], c[i+5], c[i+6], c[i+7],
191 c[i+8], c[i+9], c[i+10], c[i+11], c[i+12], c[i+13], c[i+14], c[i+15]);
192 len -= 16;
193 i += 16;
194 }
195 while (len >= 8) {
196 pr_error("%02x %02x %02x %02x %02x %02x %02x %02x\n",
197 c[i], c[i+1], c[i+2], c[i+3], c[i+4], c[i+5], c[i+6], c[i+7]);
198 len -= 8;
199 i += 8;
200 }
201 while (len >= 4) {
202 printk("%02x %02x %02x %02x\n",
203 c[i], c[i+1], c[i+2], c[i+3]);
204 len -= 4;
205 i += 4;
206 }
207 while (len >= 1) {
208 pr_error("%02x ", c[i]);
209 len -= 1;
210 i += 1;
211 }
212 }
213 }
214 #endif
_ts_pkt_cb(SWDMX_TsPacket * pkt,SWDMX_Ptr data)215 static void _ts_pkt_cb (SWDMX_TsPacket *pkt, SWDMX_Ptr data)
216 {
217 // prdump("ts_data", pkt->packet, 32);
218
219 struct dmx_ts_feed * source_feed = (struct dmx_ts_feed *)data;
220 struct sw_demux_ts_feed *ts_feed = (struct sw_demux_ts_feed *)data;
221
222 if (ts_feed->state != DMX_STATE_GO) {
223 return ;
224 }
225 if (ts_feed->ts_cb) {
226 ts_feed->ts_cb(pkt->packet,pkt->packet_len,NULL,0,source_feed);
227 }
228 }
_sec_cb(SWDMX_UInt8 * sec,SWDMX_Int len,SWDMX_Ptr data)229 static void _sec_cb (SWDMX_UInt8 *sec, SWDMX_Int len, SWDMX_Ptr data)
230 {
231 struct dmx_section_filter *source_filter = (struct dmx_section_filter *)data;
232 struct sw_demux_sec_feed *sec_feed = (struct sw_demux_sec_feed *)source_filter->parent;
233
234 // prdump("sec_data", sec, 32);
235
236 if (sec_feed->state != DMX_STATE_GO) {
237 return ;
238 }
239
240 if (sec_feed->sec_cb) {
241 sec_feed->sec_cb(sec,len,NULL, 0,source_filter);
242 }
243 }
244
_dmx_ts_feed_set(struct dmx_ts_feed * ts_feed,u16 pid,int ts_type,enum dmx_ts_pes pes_type,size_t circular_buffer_size,ktime_t timeout)245 static int _dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
246 enum dmx_ts_pes pes_type,
247 size_t circular_buffer_size, ktime_t timeout)
248 {
249 struct sw_demux_ts_feed *feed = (struct sw_demux_ts_feed *)ts_feed;
250 struct aml_dmx *demux = (struct aml_dmx *)ts_feed->parent->priv;
251
252 pr_inf("_dmx_ts_feed_set pid:0x%0x\n",pid);
253
254 if (pid >= SWDMX_MAX_PID)
255 return -EINVAL;
256
257 if (mutex_lock_interruptible(demux->pmutex))
258 return -ERESTARTSYS;
259
260 if (ts_type & TS_DECODER) {
261 if (pes_type >= DMX_PES_OTHER) {
262 mutex_unlock(demux->pmutex);
263 return -EINVAL;
264 }
265 }
266
267 feed->pid = pid;
268 feed->ts_type = ts_type;
269 // feed->type = DMX_TYPE_PES; //ts_type;
270 feed->pes_type = pes_type;
271 feed->state = DMX_STATE_READY;
272
273 #if 0
274 feed->buffer_size = circular_buffer_size;
275
276 if (feed->buffer_size) {
277 feed->buffer = vmalloc(feed->buffer_size);
278 if (!feed->buffer) {
279 mutex_unlock(&demux->mutex);
280 return -ENOMEM;
281 }
282 }
283 #endif
284
285 /*enable hw pid filter*/
286 if (demux->used_hwdmx)
287 hwdmx_set_pid(feed->tschan,feed->type, feed->pes_type, feed->pid);
288
289 mutex_unlock(demux->pmutex);
290
291 return 0;
292 }
293
_dmx_ts_feed_start_filtering(struct dmx_ts_feed * ts_feed)294 static int _dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
295 {
296 struct sw_demux_ts_feed *feed = (struct sw_demux_ts_feed *)ts_feed;
297 struct aml_dmx *demux = (struct aml_dmx *)ts_feed->parent->priv;
298 SWDMX_TsFilterParams tsfp;
299
300 pr_inf("_dmx_ts_feed_start_filtering\n");
301 if (mutex_lock_interruptible(demux->pmutex)) {
302
303 pr_error("%s line:%d\n",__func__,__LINE__);
304 return -ERESTARTSYS;
305 }
306
307 if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
308 mutex_unlock(demux->pmutex);
309 return -EINVAL;
310 }
311
312 tsfp.pid = feed->pid;
313 swdmx_ts_filter_set_params(feed->tsf, &tsfp);
314 swdmx_ts_filter_add_ts_packet_cb(feed->tsf, _ts_pkt_cb, ts_feed);
315
316 if (swdmx_ts_filter_enable(feed->tsf) != SWDMX_OK) {
317 mutex_unlock(demux->pmutex);
318 return -EINVAL;
319 }
320
321 if (feed->type == TS_PACKET) {
322 dmx_ext_add_pvr_pid(demux->id, feed->pid);
323 }
324 spin_lock_irq(demux->pslock);
325 ts_feed->is_filtering = 1;
326 feed->state = DMX_STATE_GO;
327 spin_unlock_irq(demux->pslock);
328 mutex_unlock(demux->pmutex);
329
330 return 0;
331 }
332
_dmx_ts_feed_stop_filtering(struct dmx_ts_feed * ts_feed)333 static int _dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
334 {
335 struct sw_demux_ts_feed *feed = (struct sw_demux_ts_feed *)ts_feed;
336 struct aml_dmx *demux = (struct aml_dmx *)ts_feed->parent->priv;
337
338 pr_inf("_dmx_ts_feed_stop_filtering \n");
339 mutex_lock(demux->pmutex);
340
341 if (feed->state < DMX_STATE_GO) {
342 mutex_unlock(demux->pmutex);
343 return -EINVAL;
344 }
345
346 if (swdmx_ts_filter_disable(feed->tsf) != SWDMX_OK) {
347 mutex_unlock(demux->pmutex);
348 return -EINVAL;
349 }
350 if (feed->type == TS_PACKET) {
351 dmx_ext_remove_pvr_pid(demux->id, feed->pid);
352 }
353
354 spin_lock_irq(demux->pslock);
355 ts_feed->is_filtering = 0;
356 feed->state = DMX_STATE_ALLOCATED;
357 spin_unlock_irq(demux->pslock);
358 mutex_unlock(demux->pmutex);
359
360 return 0;
361 }
_dmx_section_feed_allocate_filter(struct dmx_section_feed * feed,struct dmx_section_filter ** filter)362 static int _dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
363 struct dmx_section_filter **filter)
364 {
365 struct aml_dmx *demux = (struct aml_dmx *)feed->parent->priv;
366 struct sw_demux_sec_filter *sec_filter;
367
368 pr_inf("_dmx_section_feed_allocate_filter \n");
369
370 if (mutex_lock_interruptible(demux->pmutex))
371 return -ERESTARTSYS;
372
373 sec_filter = _dmx_dmx_sec_filter_alloc((struct sw_demux_sec_feed *)feed);
374 if (!sec_filter) {
375 mutex_unlock(demux->pmutex);
376 return -EBUSY;
377 }
378 sec_filter->secf = swdmx_demux_alloc_sec_filter(demux->swdmx);
379 if (!sec_filter->secf) {
380 sec_filter->state = DMX_STATE_FREE;
381 mutex_unlock(demux->pmutex);
382 return -EBUSY;
383 }
384 spin_lock_irq(demux->pslock);
385 *filter = &sec_filter->section_filter;
386 (*filter)->parent = feed;
387 // (*filter)->priv = sec_filter;
388 spin_unlock_irq(demux->pslock);
389 mutex_unlock(demux->pmutex);
390 return 0;
391 }
392
_dmx_section_feed_set(struct dmx_section_feed * feed,u16 pid,size_t circular_buffer_size,int check_crc)393 static int _dmx_section_feed_set(struct dmx_section_feed *feed,
394 u16 pid, size_t circular_buffer_size,
395 int check_crc)
396 {
397 struct sw_demux_sec_feed *sec_feed = (struct sw_demux_sec_feed *)feed;
398 struct aml_dmx *demux = (struct aml_dmx *)feed->parent->priv;
399
400 pr_inf("_dmx_section_feed_set \n");
401
402 if (pid >= SWDMX_MAX_PID)
403 return -EINVAL;
404
405 if (mutex_lock_interruptible(demux->pmutex))
406 return -ERESTARTSYS;
407
408 sec_feed->pid = pid;
409 sec_feed->check_crc = check_crc;
410 sec_feed->type = DMX_TYPE_SEC;
411 sec_feed->state = DMX_STATE_READY;
412
413 /*enable hw pid filter*/
414 if (demux->used_hwdmx)
415 hwdmx_set_pid(sec_feed->secchan,sec_feed->type, 0, sec_feed->pid);
416
417 mutex_unlock(demux->pmutex);
418
419 return 0;
420 }
_dmx_section_feed_start_filtering(struct dmx_section_feed * feed)421 static int _dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
422 {
423 struct sw_demux_sec_feed *sec_feed = (struct sw_demux_sec_feed *)feed;
424 struct aml_dmx *demux = (struct aml_dmx *)feed->parent->priv;
425 SWDMX_SecFilterParams params;
426 int i = 0;
427 int start_flag = 0;
428
429 pr_inf("_dmx_section_feed_start_filtering\n");
430 if (mutex_lock_interruptible(demux->pmutex))
431 return -ERESTARTSYS;
432
433 if (feed->is_filtering) {
434 mutex_unlock(demux->pmutex);
435 return -EBUSY;
436 }
437 for (i=0; i<MAX_FILTER_PER_SEC_FEED; i++) {
438 if (sec_feed->filter[i].state == DMX_STATE_ALLOCATED) {
439 params.pid = sec_feed->pid;
440 params.crc32 = sec_feed->check_crc;
441
442 memcpy(&sec_feed->filter[i].section_filter.filter_value[1],&sec_feed->filter[i].section_filter.filter_value[3],SWDMX_SEC_FILTER_LEN-1);
443 memcpy(&sec_feed->filter[i].section_filter.filter_mask[1],&sec_feed->filter[i].section_filter.filter_mask[3],SWDMX_SEC_FILTER_LEN-1);
444 memcpy(&sec_feed->filter[i].section_filter.filter_mode[1],&sec_feed->filter[i].section_filter.filter_mode[3],SWDMX_SEC_FILTER_LEN-1);
445 _invert_mode(&sec_feed->filter[i].section_filter);
446
447 memcpy(params.value,sec_feed->filter[i].section_filter.filter_value,SWDMX_SEC_FILTER_LEN);
448 memcpy(params.mask,sec_feed->filter[i].section_filter.filter_mask,SWDMX_SEC_FILTER_LEN);
449 memcpy(params.mode,sec_feed->filter[i].section_filter.filter_mode,SWDMX_SEC_FILTER_LEN);
450
451 if (swdmx_sec_filter_set_params(sec_feed->filter[i].secf,¶ms) != SWDMX_OK) {
452 continue;
453 }
454
455 swdmx_sec_filter_add_section_cb(sec_feed->filter[i].secf, _sec_cb, &sec_feed->filter[i].section_filter);
456
457 if (swdmx_sec_filter_enable(sec_feed->filter[i].secf) != SWDMX_OK) {
458 continue;
459 }
460 sec_feed->filter[i].state = DMX_STATE_GO;
461 start_flag = 1;
462 }
463 else if (sec_feed->filter[i].state == DMX_STATE_READY) {
464 if (swdmx_sec_filter_enable(sec_feed->filter[i].secf) != SWDMX_OK) {
465 continue;
466 }
467 sec_feed->filter[i].state = DMX_STATE_GO;
468 start_flag = 1;
469 }
470 }
471 if (start_flag != 1) {
472 pr_error("%s fail \n",__FUNCTION__);
473 return -1;
474 }
475 sec_feed->state = DMX_STATE_GO;
476
477 spin_lock_irq(demux->pslock);
478 feed->is_filtering = 1;
479 spin_unlock_irq(demux->pslock);
480 mutex_unlock(demux->pmutex);
481
482 return 0;
483 }
484
_dmx_section_feed_stop_filtering(struct dmx_section_feed * feed)485 static int _dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
486 {
487 struct sw_demux_sec_feed *sec_feed = (struct sw_demux_sec_feed *)feed;
488 struct aml_dmx *demux = (struct aml_dmx *)feed->parent->priv;
489 int i = 0;
490 int start_flag = 0;
491
492 pr_inf("_dmx_section_feed_stop_filtering \n");
493
494 if (mutex_lock_interruptible(demux->pmutex))
495 return -ERESTARTSYS;
496
497 if (feed->is_filtering == 0) {
498 mutex_unlock(demux->pmutex);
499 return -EINVAL;
500 }
501 for (i=0; i<MAX_FILTER_PER_SEC_FEED; i++) {
502 if (sec_feed->filter[i].state == DMX_STATE_GO) {
503 if (swdmx_sec_filter_disable(sec_feed->filter[i].secf) != SWDMX_OK) {
504 continue;
505 }
506 sec_feed->filter[i].state = DMX_STATE_READY;
507 start_flag = 1;
508 }
509 }
510 if (start_flag != 1) {
511 pr_error("%s no found start filter \n",__FUNCTION__);
512 mutex_unlock(demux->pmutex);
513 return 0;
514 }
515
516 spin_lock_irq(demux->pslock);
517 feed->is_filtering = 0;
518 spin_unlock_irq(demux->pslock);
519 mutex_unlock(demux->pmutex);
520
521 return 0;
522 }
523
_dmx_section_feed_release_filter(struct dmx_section_feed * feed,struct dmx_section_filter * filter)524 static int _dmx_section_feed_release_filter(struct dmx_section_feed *feed,
525 struct dmx_section_filter *filter)
526 {
527 struct sw_demux_sec_feed *sec_feed = (struct sw_demux_sec_feed *)feed;
528 struct aml_dmx *demux = (struct aml_dmx *)feed->parent->priv;
529 int i = 0;
530
531 pr_inf("_dmx_section_feed_release_filter\n");
532
533 if (mutex_lock_interruptible(demux->pmutex))
534 return -ERESTARTSYS;
535
536 if (sec_feed->type != DMX_TYPE_SEC) {
537 mutex_unlock(demux->pmutex);
538 return -EINVAL;
539 }
540 for (i=0; i<MAX_FILTER_PER_SEC_FEED; i++) {
541 if (sec_feed->filter[i].state != DMX_STATE_FREE && (&sec_feed->filter[i].section_filter) == filter) {
542 swdmx_sec_filter_free(sec_feed->filter[i].secf);
543 sec_feed->filter[i].secf = NULL;
544 memset(filter,0,sizeof(struct dmx_section_filter));
545 sec_feed->filter[i].state = DMX_STATE_FREE;
546 break;
547 }
548 }
549
550 mutex_unlock(demux->pmutex);
551
552 return 0;
553 }
554
_dmx_allocate_ts_feed(struct dmx_demux * dmx,struct dmx_ts_feed ** ts_feed,dmx_ts_cb callback)555 static int _dmx_allocate_ts_feed(struct dmx_demux *dmx,
556 struct dmx_ts_feed **ts_feed,
557 dmx_ts_cb callback)
558 {
559 struct aml_dmx *demux = (struct aml_dmx *)dmx->priv;
560 struct sw_demux_ts_feed *feed;
561
562 pr_inf("_dmx_allocate_ts_feed line:%d\n",__LINE__);
563 if (mutex_lock_interruptible(demux->pmutex))
564 return -ERESTARTSYS;
565
566 if (!(feed = _dmx_ts_feed_alloc(demux))) {
567 mutex_unlock(demux->pmutex);
568 pr_error("_dmx_allocate_ts_feed line:%d\n",__LINE__);
569 return -EBUSY;
570 }
571
572 feed->type = DMX_TYPE_TS;
573 feed->ts_cb = callback;
574
575 (*ts_feed) = &feed->ts_feed;
576 (*ts_feed)->parent = dmx;
577 // (*ts_feed)->priv = feed;
578 (*ts_feed)->is_filtering = 0;
579 (*ts_feed)->start_filtering = _dmx_ts_feed_start_filtering;
580 (*ts_feed)->stop_filtering = _dmx_ts_feed_stop_filtering;
581 (*ts_feed)->set = _dmx_ts_feed_set;
582
583 feed->tsf = swdmx_demux_alloc_ts_filter(demux->swdmx);
584 if (!feed->tsf)
585 {
586 pr_error("_dmx_allocate_ts_feed line:%d\n",__LINE__);
587 feed->state = DMX_STATE_FREE;
588 mutex_unlock(demux->pmutex);
589 return ERESTARTSYS;
590 }
591 if (demux->used_hwdmx) {
592 feed->tschan = hwdmx_alloc_chan(demux->hwdmx);
593 if (!feed->tschan) {
594 pr_error("hwdmx_alloc_chan fail line:%d\n",__LINE__);
595 swdmx_ts_filter_free(feed->tsf);
596 feed->state = DMX_STATE_FREE;
597 mutex_unlock(demux->pmutex);
598 return ERESTARTSYS;
599 }
600 }
601 mutex_unlock(demux->pmutex);
602
603 return 0;
604 }
605
_dmx_release_ts_feed(struct dmx_demux * dmx,struct dmx_ts_feed * ts_feed)606 static int _dmx_release_ts_feed(struct dmx_demux *dmx,
607 struct dmx_ts_feed *ts_feed)
608 {
609 struct aml_dmx *demux = (struct aml_dmx *)dmx->priv;
610 struct sw_demux_ts_feed *feed;
611
612 pr_inf(" _dmx_release_ts_feed\n");
613 if (!ts_feed) {
614 return 0;
615 }
616 if (mutex_lock_interruptible(demux->pmutex))
617 return -ERESTARTSYS;
618
619 feed = (struct sw_demux_ts_feed *)ts_feed;
620
621 if (demux->used_hwdmx)
622 hwdmx_free_chan(feed->tschan);
623 swdmx_ts_filter_free(feed->tsf);
624 feed->state = DMX_STATE_FREE;
625
626 mutex_unlock(demux->pmutex);
627 return 0;
628 }
629
_dmx_allocate_section_feed(struct dmx_demux * dmx,struct dmx_section_feed ** feed,dmx_section_cb callback)630 static int _dmx_allocate_section_feed(struct dmx_demux *dmx,
631 struct dmx_section_feed **feed,
632 dmx_section_cb callback)
633 {
634 struct aml_dmx *demux = (struct aml_dmx *)dmx->priv;
635 struct sw_demux_sec_feed *sec_feed;
636 int i;
637
638 pr_inf("_dmx_allocate_section_feed \n");
639 if (mutex_lock_interruptible(demux->pmutex))
640 return -ERESTARTSYS;
641
642 if (!(sec_feed = _dmx_section_feed_alloc(demux))) {
643 mutex_unlock(demux->pmutex);
644 return -EBUSY;
645 }
646
647 sec_feed->sec_filter_num = MAX_FILTER_PER_SEC_FEED;
648 sec_feed->filter = vmalloc(sizeof(struct sw_demux_sec_filter) * sec_feed->sec_filter_num);
649 if (!sec_feed->filter) {
650 mutex_unlock(demux->pmutex);
651 return -EBUSY;
652 }
653 for (i=0; i<sec_feed->sec_filter_num; i++) {
654 sec_feed->filter[i].state = DMX_STATE_FREE;
655 }
656 sec_feed->sec_cb = callback;
657 sec_feed->type = DMX_TYPE_SEC;
658
659 (*feed) = &sec_feed->sec_feed;
660 (*feed)->parent = dmx;
661 // (*feed)->priv = sec_feed;
662 (*feed)->is_filtering = 0;
663
664 (*feed)->set = _dmx_section_feed_set;
665 (*feed)->allocate_filter = _dmx_section_feed_allocate_filter;
666 (*feed)->start_filtering = _dmx_section_feed_start_filtering;
667 (*feed)->stop_filtering = _dmx_section_feed_stop_filtering;
668 (*feed)->release_filter = _dmx_section_feed_release_filter;
669
670 if (demux->used_hwdmx) {
671 sec_feed->secchan = hwdmx_alloc_chan(demux->hwdmx);
672 if (!sec_feed->secchan) {
673 pr_error("%s error\n",__FUNCTION__);
674 }
675 }
676 mutex_unlock(demux->pmutex);
677 return 0;
678 }
679
_dmx_release_section_feed(struct dmx_demux * dmx,struct dmx_section_feed * feed)680 static int _dmx_release_section_feed(struct dmx_demux *dmx,
681 struct dmx_section_feed *feed)
682 {
683 struct aml_dmx *demux = (struct aml_dmx *)dmx->priv;
684 struct sw_demux_sec_feed *sec_feed;
685
686 pr_inf(" _dmx_release_section_feed\n");
687 if (mutex_lock_interruptible(demux->pmutex))
688 return -ERESTARTSYS;
689
690 sec_feed = (struct sw_demux_sec_feed *)feed;
691 sec_feed->state = DMX_STATE_FREE;
692
693 if (demux->used_hwdmx) {
694 if (sec_feed->secchan) {
695 hwdmx_free_chan(sec_feed->secchan);
696 sec_feed->secchan = NULL;
697 }
698 }
699 mutex_unlock(demux->pmutex);
700 return 0;
701 }
_dmx_add_frontend(struct dmx_demux * dmx,struct dmx_frontend * frontend)702 static int _dmx_add_frontend(struct dmx_demux *dmx,
703 struct dmx_frontend *frontend)
704 {
705 struct aml_dmx *demux = (struct aml_dmx *)dmx->priv;
706 struct list_head *head = &demux->frontend_list;
707
708 list_add(&(frontend->connectivity_list), head);
709
710 return 0;
711 }
712
_dmx_remove_frontend(struct dmx_demux * dmx,struct dmx_frontend * frontend)713 static int _dmx_remove_frontend(struct dmx_demux *dmx,
714 struct dmx_frontend *frontend)
715 {
716 struct aml_dmx *demux = (struct aml_dmx *)dmx->priv;
717 struct list_head *pos, *n, *head = &demux->frontend_list;
718
719 list_for_each_safe(pos, n, head) {
720 if (DMX_FE_ENTRY(pos) == frontend) {
721 list_del(pos);
722 return 0;
723 }
724 }
725
726 return -ENODEV;
727 }
728
_dmx_get_frontends(struct dmx_demux * dmx)729 static struct list_head *_dmx_get_frontends(struct dmx_demux *dmx)
730 {
731 struct aml_dmx *demux = (struct aml_dmx *)dmx->priv;
732
733 if (list_empty(&demux->frontend_list))
734 return NULL;
735
736 return &demux->frontend_list;
737 }
738
_dmx_connect_frontend(struct dmx_demux * dmx,struct dmx_frontend * frontend)739 static int _dmx_connect_frontend(struct dmx_demux *dmx,
740 struct dmx_frontend *frontend)
741 {
742 struct aml_dmx *demux = (struct aml_dmx *)dmx->priv;
743
744 if (dmx->frontend)
745 return -EINVAL;
746
747 mutex_lock(demux->pmutex);
748
749 dmx->frontend = frontend;
750 mutex_unlock(demux->pmutex);
751 return 0;
752 }
753
_dmx_disconnect_frontend(struct dmx_demux * dmx)754 static int _dmx_disconnect_frontend(struct dmx_demux *dmx)
755 {
756 struct aml_dmx *demux = (struct aml_dmx *)dmx;
757
758 mutex_lock(demux->pmutex);
759
760 dmx->frontend = NULL;
761 mutex_unlock(demux->pmutex);
762 return 0;
763 }
764
_dmx_get_pes_pids(struct dmx_demux * dmx,u16 * pids)765 static int _dmx_get_pes_pids(struct dmx_demux *dmx, u16 * pids)
766 {
767 struct aml_dmx *demux = (struct aml_dmx *)dmx;
768
769 memcpy(pids, demux->pids, 5 * sizeof(u16));
770 return 0;
771 }
_dmx_write(struct aml_dmx * pdmx,const u8 * buf,size_t count)772 static int _dmx_write(struct aml_dmx *pdmx, const u8 *buf, size_t count)
773 {
774 int n = 0;
775
776 if (pdmx->tsp == NULL)
777 {
778 pr_error("_dmx_write invalid tsp\n");
779 return -1;
780 }
781
782 if (mutex_lock_interruptible(pdmx->pmutex))
783 return -ERESTARTSYS;
784
785 n = swdmx_ts_parser_run(pdmx->tsp, (SWDMX_UInt8 *)buf, count);
786 if (n != 0) {
787 // printk("call swdmx_ts_parser_run,len 0x%zx,Remaining len: 0x%0x\n",count,n);
788 }
789 mutex_unlock(pdmx->pmutex);
790
791 return n;
792 }
793
dmx_init(struct aml_dmx * pdmx,struct dvb_adapter * dvb_adapter)794 int dmx_init(struct aml_dmx *pdmx, struct dvb_adapter *dvb_adapter)
795 {
796 int ret;
797 int i = 0;
798
799 pdmx->dmx.capabilities =
800 (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
801 DMX_MEMORY_BASED_FILTERING);
802 pdmx->dmx.priv = pdmx;
803
804 pdmx->ts_feed_num = MAX_TS_FEED_NUM;
805 pdmx->ts_feed = vmalloc(sizeof(struct sw_demux_ts_feed)*(pdmx->ts_feed_num));
806 if (!pdmx->ts_feed) {
807 return -ENOMEM;
808 }
809 for (i=0; i<pdmx->ts_feed_num; i++) {
810 pdmx->ts_feed[i].state = DMX_STATE_FREE;
811 }
812
813 pdmx->sec_feed_num = MAX_SEC_FEED_NUM;
814 pdmx->section_feed = vmalloc(sizeof(struct sw_demux_sec_feed)*(pdmx->sec_feed_num));
815 if (!pdmx->section_feed) {
816 vfree(pdmx->ts_feed);
817 pdmx->ts_feed = NULL;
818 return -ENOMEM;
819 }
820
821 for (i=0; i<pdmx->sec_feed_num; i++) {
822 pdmx->section_feed[i].state = DMX_STATE_FREE;
823 }
824 INIT_LIST_HEAD(&pdmx->frontend_list);
825
826 for (i = 0; i < DMX_PES_OTHER; i++) {
827 pdmx->pids[i] = 0xffff;
828 }
829
830 pdmx->used_hwdmx = 1;
831
832 pdmx->dmx.open = _dmx_open;
833 pdmx->dmx.close = _dmx_close;
834 pdmx->dmx.write = _dmx_write_from_user;
835 pdmx->dmx.allocate_ts_feed = _dmx_allocate_ts_feed;
836 pdmx->dmx.release_ts_feed = _dmx_release_ts_feed;
837 pdmx->dmx.allocate_section_feed = _dmx_allocate_section_feed;
838 pdmx->dmx.release_section_feed = _dmx_release_section_feed;
839
840 pdmx->dmx.add_frontend = _dmx_add_frontend;
841 pdmx->dmx.remove_frontend = _dmx_remove_frontend;
842 pdmx->dmx.get_frontends = _dmx_get_frontends;
843 pdmx->dmx.connect_frontend = _dmx_connect_frontend;
844 pdmx->dmx.disconnect_frontend = _dmx_disconnect_frontend;
845 pdmx->dmx.get_pes_pids = _dmx_get_pes_pids;
846
847 pdmx->dev.filternum = (MAX_TS_FEED_NUM+MAX_SEC_FEED_NUM);
848 pdmx->dev.demux = &pdmx->dmx;
849 pdmx->dev.capabilities = 0;
850 ret = dvb_dmxdev_init(&pdmx->dev, dvb_adapter);
851 if (ret < 0) {
852 pr_error("dvb_dmxdev_init failed: error %d\n", ret);
853 vfree(pdmx->ts_feed);
854 return -1;
855 }
856 pdmx->dev.dvr_dvbdev->writers = MAX_SW_DEMUX_USERS;
857
858 pdmx->mem_fe.source = DMX_MEMORY_FE;
859 ret = pdmx->dmx.add_frontend(&pdmx->dmx,&pdmx->mem_fe);
860 if (ret <0) {
861 pr_error("dvb_dmxdev_init add frontend: error %d\n", ret);
862 vfree(pdmx->ts_feed);
863 return -1;
864 }
865 pdmx->dmx.connect_frontend(&pdmx->dmx,&pdmx->mem_fe);
866 if (ret <0) {
867 pr_error("dvb_dmxdev_init connect frontend: error %d\n", ret);
868 vfree(pdmx->ts_feed);
869 return -1;
870 }
871 pdmx->buf_warning_level = 60;
872 pdmx->init = 1;
873 // dvb_net_init(dvb_adapter, &dmx->dvb_net, &pdmx->dmx);
874
875 return 0;
876
877 }
dmx_destroy(struct aml_dmx * pdmx)878 int dmx_destroy(struct aml_dmx *pdmx) {
879
880 if (pdmx->init) {
881 vfree(pdmx->ts_feed);
882 // mutex_destroy(pdmx->mutex);
883
884 swdmx_demux_free(pdmx->swdmx);
885 dvb_dmxdev_release(&pdmx->dev);
886 pdmx->init = 0;
887 }
888 return 0;
889 }
dmx_set_work_mode(struct aml_dmx * pdmx,int work_mode)890 int dmx_set_work_mode(struct aml_dmx *pdmx,int work_mode){
891
892 if (pdmx->init == 0) {
893 return -1;
894 }
895 pdmx->used_hwdmx = work_mode;
896 return 0;
897 }
dmx_get_work_mode(struct aml_dmx * pdmx,int * work_mode)898 int dmx_get_work_mode(struct aml_dmx *pdmx,int *work_mode){
899
900 if (pdmx->init == 0) {
901 return -1;
902 }
903 *work_mode = pdmx->used_hwdmx;
904 return 0;
905 }
906
dmx_get_buf_warning_status(struct aml_dmx * pdmx,int * status)907 int dmx_get_buf_warning_status(struct aml_dmx *pdmx, int *status){
908 int i = 0;
909 ssize_t free_mem = 0;
910 ssize_t total_mem = 0;
911
912 struct dmxdev *pdev = &pdmx->dev;
913
914 if (pdmx->init == 0) {
915 return -1;
916 }
917
918 for (i = 0; i < pdev->filternum; i++) {
919 if ((pdev->filter[i].state < DMXDEV_STATE_SET) ||
920 (pdev->filter[i].type != DMXDEV_TYPE_PES))
921 continue;
922
923 free_mem = dvb_ringbuffer_free(&pdev->filter[i].buffer);
924 total_mem = pdev->filter[i].buffer.size;
925
926 if ((total_mem-free_mem)*100/total_mem >= pdmx->buf_warning_level) {
927 *status = 1;
928 return 0;
929 }
930 }
931 *status = 0;
932 return 0;
933 }
934
dmx_set_buf_warning_level(struct aml_dmx * pdmx,int level)935 int dmx_set_buf_warning_level(struct aml_dmx *pdmx, int level) {
936 pdmx->buf_warning_level = level;
937 return 0;
938 }
dmx_write_sw_from_user(struct aml_dmx * pdmx,const char __user * buf,size_t count)939 int dmx_write_sw_from_user(struct aml_dmx *pdmx, const char __user *buf, size_t count)
940 {
941 void *p;
942 int ret = 0;
943
944 p = memdup_user(buf, count);
945 if (IS_ERR(p)) {
946 pr_error("get fail mem pointer\n");
947 return PTR_ERR(p);
948 }
949 ret = _dmx_write(pdmx, p, count);
950
951 kfree(p);
952
953 if (signal_pending(current))
954 return -EINTR;
955 return ret;
956 }
957
958