• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,&params) != 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