| #ifdef _FORTIFY_SOURCE |
| #undef _FORTIFY_SOURCE |
| #endif |
| /*************************************************************************** |
| * Copyright (c) 2014 Amlogic, Inc. All rights reserved. |
| * |
| * This source code is subject to the terms and conditions defined in the |
| * file 'LICENSE' which is part of this source code package. |
| * |
| * Description: |
| */ |
| /**\file |
| * \brief Linux DVB demux 驱动 |
| * |
| * \author Gong Ke <ke.gong@amlogic.com> |
| * \date 2010-07-21: create the document |
| ***************************************************************************/ |
| |
| #define printf_LEVEL 5 |
| |
| #include "am_mem.h" |
| //#include <am_misc.h> |
| #include <stdio.h> |
| #include "am_dmx_internal.h" |
| #include <limits.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/ioctl.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <poll.h> |
| #include <stdlib.h> |
| |
| /*add for config define for linux dvb *.h*/ |
| //#include <am_config.h> |
| #include "dmx.h" |
| |
| #define open(a...)\ |
| ({\ |
| int ret, times=3;\ |
| do {\ |
| ret = open(a);\ |
| if (ret == -1)\ |
| {\ |
| usleep(100*1000);\ |
| }\ |
| }while (ret==-1 && times--);\ |
| ret;\ |
| }) |
| |
| /**************************************************************************** |
| * Type definitions |
| ***************************************************************************/ |
| |
| typedef struct |
| { |
| char dev_name[32]; |
| int fd[DMX_FILTER_COUNT]; |
| } DVBDmx_t; |
| |
| /**************************************************************************** |
| * Static data definitions |
| ***************************************************************************/ |
| |
| static AM_ErrorCode_t dvb_open(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para); |
| static AM_ErrorCode_t dvb_close(AM_DMX_Device_t *dev); |
| static AM_ErrorCode_t dvb_alloc_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter); |
| static AM_ErrorCode_t dvb_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter); |
| static AM_ErrorCode_t dvb_set_sec_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params); |
| static AM_ErrorCode_t dvb_set_pes_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params); |
| static AM_ErrorCode_t dvb_enable_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable); |
| static AM_ErrorCode_t dvb_set_buf_size(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size); |
| static AM_ErrorCode_t dvb_poll(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout); |
| static AM_ErrorCode_t dvb_read(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size); |
| static AM_ErrorCode_t dvb_set_source(AM_DMX_Device_t *dev, AM_DMX_Source_t src); |
| static AM_ErrorCode_t dvb_get_stc(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter); |
| |
| const AM_DMX_Driver_t linux_dvb_dmx_drv = { |
| .open = dvb_open, |
| .close = dvb_close, |
| .alloc_filter = dvb_alloc_filter, |
| .free_filter = dvb_free_filter, |
| .set_sec_filter = dvb_set_sec_filter, |
| .set_pes_filter = dvb_set_pes_filter, |
| .enable_filter = dvb_enable_filter, |
| .set_buf_size = dvb_set_buf_size, |
| .poll = dvb_poll, |
| .read = dvb_read, |
| .set_source = dvb_set_source, |
| .get_stc = dvb_get_stc |
| }; |
| |
| /**************************************************************************** |
| * Static functions |
| ***************************************************************************/ |
| |
| #ifdef LINUX |
| #define DEMUX_DEVICE "/dev/dvb/adapter0/demux" |
| #else |
| #define DEMUX_DEVICE "/dev/dvb0.demux" |
| #endif |
| |
| static AM_ErrorCode_t dvb_open(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para) |
| { |
| DVBDmx_t *dmx; |
| int i; |
| |
| UNUSED(para); |
| |
| dmx = (DVBDmx_t*)malloc(sizeof(DVBDmx_t)); |
| if (!dmx) { |
| printf("not enough memory"); |
| return AM_DMX_ERR_NO_MEM; |
| } |
| |
| snprintf(dmx->dev_name, sizeof(dmx->dev_name), DEMUX_DEVICE"%d", dev->dev_no); |
| |
| for (i = 0; i < DMX_FILTER_COUNT; i++) |
| dmx->fd[i] = -1; |
| |
| dev->drv_data = dmx; |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_close(AM_DMX_Device_t *dev) |
| { |
| DVBDmx_t *dmx = (DVBDmx_t*)dev->drv_data; |
| |
| free(dmx); |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_alloc_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter) |
| { |
| DVBDmx_t *dmx = (DVBDmx_t*)dev->drv_data; |
| int fd; |
| |
| fd = open(dmx->dev_name, O_RDWR); |
| if (fd == -1) { |
| printf("cannot open \"%s\" (%s)", dmx->dev_name, strerror(errno)); |
| return AM_DMX_ERR_CANNOT_OPEN_DEV; |
| } |
| |
| dmx->fd[filter->id] = fd; |
| |
| filter->drv_data = (void*)(long)fd; |
| |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter) |
| { |
| DVBDmx_t *dmx = (DVBDmx_t*)dev->drv_data; |
| int fd = (long)filter->drv_data; |
| |
| close(fd); |
| dmx->fd[filter->id] = -1; |
| |
| return AM_SUCCESS; |
| } |
| AM_ErrorCode_t dvb_get_stc(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter) |
| { |
| int fd = (long)filter->drv_data; |
| int ret; |
| struct dmx_stc stc; |
| int i = 0; |
| |
| UNUSED(dev); |
| |
| for (i = 0; i < 3; i++) { |
| memset(&stc, 0, sizeof(struct dmx_stc)); |
| stc.num = i; |
| ret = ioctl(fd, DMX_GET_STC, &stc); |
| if (ret == 0) { |
| printf("get stc num %d: base:0x%0x, stc:0x%lx\n", stc.num, stc.base, stc.stc); |
| } else { |
| printf("get stc %d, fail\n", i); |
| } |
| } |
| return 0; |
| } |
| |
| static AM_ErrorCode_t dvb_set_sec_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params) |
| { |
| struct dmx_sct_filter_params p; |
| int fd = (long)filter->drv_data; |
| int ret; |
| |
| UNUSED(dev); |
| |
| //2. set input source |
| ret = ioctl(fd, DMX_SET_INPUT, INPUT_LOCAL); |
| if (ret != 0) { |
| printf("set pes filter failed ret = %d\n", ret); |
| } |
| |
| //3. set hw source |
| ret = ioctl(fd, DMX_SET_HW_SOURCE, DMA_0); |
| if (ret != 0) { |
| printf("set pes filter failed ret = %d\n", ret); |
| } |
| |
| p = *params; |
| ret = ioctl(fd, DMX_SET_FILTER, &p); |
| if (ret == -1) { |
| printf("set section filter failed (%s)", strerror(errno)); |
| return AM_DMX_ERR_SYS; |
| } |
| |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_set_pes_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params) |
| { |
| int fd = (long)filter->drv_data; |
| int ret; |
| |
| UNUSED(dev); |
| |
| fcntl(fd,F_SETFL,O_NONBLOCK); |
| |
| ret = ioctl(fd, DMX_SET_PES_FILTER, params); |
| if (ret == -1) { |
| printf("set section filter failed (%s)", strerror(errno)); |
| return AM_DMX_ERR_SYS; |
| } |
| printf("%s success\n", __FUNCTION__); |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_enable_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable) |
| { |
| int fd = (long)filter->drv_data; |
| int ret; |
| |
| UNUSED(dev); |
| |
| if (enable) |
| ret = ioctl(fd, DMX_START, 0); |
| else |
| ret = ioctl(fd, DMX_STOP, 0); |
| |
| if (ret == -1) { |
| printf("start filter failed (%s)", strerror(errno)); |
| return AM_DMX_ERR_SYS; |
| } |
| |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_set_buf_size(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size) |
| { |
| int fd = (long)filter->drv_data; |
| int ret; |
| |
| UNUSED(dev); |
| |
| ret = ioctl(fd, DMX_SET_BUFFER_SIZE, size); |
| if (ret == -1) { |
| printf("set buffer size failed (%s)", strerror(errno)); |
| return AM_DMX_ERR_SYS; |
| } |
| |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_poll(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout) |
| { |
| DVBDmx_t *dmx = (DVBDmx_t*)dev->drv_data; |
| struct pollfd fds[DMX_FILTER_COUNT]; |
| int fids[DMX_FILTER_COUNT]; |
| int i, cnt = 0, ret; |
| |
| for (i = 0; i < DMX_FILTER_COUNT; i++) { |
| if (dmx->fd[i] != -1) { |
| fds[cnt].events = POLLIN | POLLERR; |
| fds[cnt].fd = dmx->fd[i]; |
| fids[cnt] = i; |
| cnt++; |
| } |
| } |
| |
| if (!cnt) |
| return AM_DMX_ERR_TIMEOUT; |
| |
| ret = poll(fds, cnt, timeout); |
| if (ret <= 0) { |
| return AM_DMX_ERR_TIMEOUT; |
| } |
| |
| for (i = 0; i < cnt; i++) { |
| if (fds[i].revents & (POLLIN | POLLERR)) { |
| AM_DMX_FILTER_MASK_SET(mask, fids[i]); |
| } |
| } |
| |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_read(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size) |
| { |
| int fd = (long)filter->drv_data; |
| int len = *size; |
| int ret; |
| struct pollfd pfd; |
| |
| UNUSED(dev); |
| |
| if (fd == -1) |
| return AM_DMX_ERR_NOT_ALLOCATED; |
| |
| pfd.events = POLLIN|POLLERR; |
| pfd.fd = fd; |
| |
| ret = poll(&pfd, 1, 0); |
| if (ret <= 0) |
| return AM_DMX_ERR_NO_DATA; |
| |
| ret = read(fd, buf, len); |
| if (ret <= 0) { |
| if (errno == ETIMEDOUT) |
| return AM_DMX_ERR_TIMEOUT; |
| printf("read demux failed (%s) %d", strerror(errno), errno); |
| return AM_DMX_ERR_SYS; |
| } |
| |
| *size = ret; |
| return AM_SUCCESS; |
| } |
| |
| static AM_ErrorCode_t dvb_set_source(AM_DMX_Device_t *dev, AM_DMX_Source_t src) |
| { |
| char buf[32]; |
| char *cmd; |
| |
| snprintf(buf, sizeof(buf), "/sys/class/stb/demux%d_source", dev->dev_no); |
| |
| switch (src) { |
| case AM_DMX_SRC_TS0: |
| cmd = "ts0"; |
| break; |
| case AM_DMX_SRC_TS1: |
| cmd = "ts1"; |
| break; |
| #if defined(CHIP_8226M) || defined(CHIP_8626X) |
| case AM_DMX_SRC_TS2: |
| cmd = "ts2"; |
| break; |
| #endif |
| case AM_DMX_SRC_TS3: |
| cmd = "ts3"; |
| break; |
| case AM_DMX_SRC_HIU: |
| cmd = "hiu"; |
| break; |
| case AM_DMX_SRC_HIU1: |
| cmd = "hiu1"; |
| break; |
| default: |
| printf("do not support demux source %d", src); |
| return AM_DMX_ERR_NOT_SUPPORTED; |
| } |
| return 0; |
| // return AM_FileEcho(buf, cmd); |
| } |