diff options
Diffstat (limited to 'util/szap/util.c')
| -rw-r--r-- | util/szap/util.c | 381 |
1 files changed, 301 insertions, 80 deletions
diff --git a/util/szap/util.c b/util/szap/util.c index 301d666..60de8f8 100644 --- a/util/szap/util.c +++ b/util/szap/util.c @@ -23,6 +23,7 @@ #include <unistd.h> #include <stdio.h> #include <errno.h> +#include <stdint.h> #include <sys/ioctl.h> #include <sys/types.h> @@ -35,92 +36,312 @@ int set_pesfilter(int dmxfd, int pid, int pes_type, int dvr) { - struct dmx_pes_filter_params pesfilter; + struct dmx_pes_filter_params pesfilter; - /* ignore this pid to allow radio services */ - if (pid < 0 || - pid >= 0x1fff || - (pid == 0 && pes_type != DMX_PES_OTHER)) - return 0; + /* ignore this pid to allow radio services */ + if (pid < 0 || pid >= 0x1fff || (pid == 0 && pes_type != DMX_PES_OTHER)) + return 0; + + if (dvr) { + int buffersize = 64 * 1024; + if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1) + perror("DMX_SET_BUFFER_SIZE failed"); + } - if (dvr) { - int buffersize = 64 * 1024; - if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1) - perror("DMX_SET_BUFFER_SIZE failed"); - } - - pesfilter.pid = pid; - pesfilter.input = DMX_IN_FRONTEND; - pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; - pesfilter.pes_type = pes_type; - pesfilter.flags = DMX_IMMEDIATE_START; - - if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) { - fprintf(stderr, "DMX_SET_PES_FILTER failed " - "(PID = 0x%04x): %d %m\n", pid, errno); - return -1; - } - - return 0; + pesfilter.pid = pid; + pesfilter.input = DMX_IN_FRONTEND; + pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; + pesfilter.pes_type = pes_type; + pesfilter.flags = DMX_IMMEDIATE_START; + + if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) { + fprintf(stderr, "DMX_SET_PES_FILTER failed " + "(PID = 0x%04x): %d %m\n", pid, errno); + return -1; + } + return 0; } int get_pmt_pid(char *dmxdev, int sid) { - int patfd, count; - int pmt_pid = 0; - int patread = 0; - int section_length; - unsigned char buft[4096]; - unsigned char *buf = buft; - struct dmx_sct_filter_params f; - - memset(&f, 0, sizeof(f)); - f.pid = 0; - f.filter.filter[0] = 0x00; - f.filter.mask[0] = 0xff; - f.timeout = 0; - f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC; - - if ((patfd = open(dmxdev, O_RDWR)) < 0) { - perror("openening pat demux failed"); - return -1; - } - - if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) { - perror("ioctl DMX_SET_FILTER failed"); + int patfd, count; + int pmt_pid = 0; + int patread = 0; + int section_length; + unsigned char buft[4096]; + unsigned char *buf = buft; + struct dmx_sct_filter_params f; + + memset(&f, 0, sizeof(f)); + f.pid = 0; + f.filter.filter[0] = 0x00; + f.filter.mask[0] = 0xff; + f.timeout = 0; + f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC; + + if ((patfd = open(dmxdev, O_RDWR)) < 0) { + perror("openening pat demux failed"); + return -1; + } + + if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) { + perror("ioctl DMX_SET_FILTER failed"); + close(patfd); + return -1; + } + + while (!patread) { + if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW) + count = read(patfd, buf, sizeof(buft)); + + if (count < 0) { + perror("read_sections: read error"); + close(patfd); + return -1; + } + section_length = ((buf[1] & 0x0f) << 8) | buf[2]; + if (count != section_length + 3) + continue; + + buf += 8; + section_length -= 8; + + patread = 1; /* assumes one section contains the whole pat */ + while (section_length > 0) { + int service_id = (buf[0] << 8) | buf[1]; + + if (service_id == sid) { + pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3]; + section_length = 0; + } + buf += 4; + section_length -= 4; + } + } close(patfd); - return -1; - } - - while (!patread){ - if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW) - count = read(patfd, buf, sizeof(buft)); - if (count < 0) { - perror("read_sections: read error"); - close(patfd); - return -1; - } - - section_length = ((buf[1] & 0x0f) << 8) | buf[2]; - if (count != section_length + 3) - continue; - - buf += 8; - section_length -= 8; - - patread = 1; /* assumes one section contains the whole pat */ - while (section_length > 0) { - int service_id = (buf[0] << 8) | buf[1]; - if (service_id == sid) { - pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3]; - section_length = 0; - } - buf += 4; - section_length -= 4; - } - } - - close(patfd); - return pmt_pid; + return pmt_pid; +} + +char *type_str[] = { + "QPSK", + "QAM", + "OFDM", + "ATSC", +}; + +/* to be used with v3 drivers */ +int check_frontend_v3(int fd, enum fe_type type) +{ + struct dvb_frontend_info info; + int ret; + + ret = ioctl(fd, FE_GET_INFO, &info); + if (ret < 0) { + perror("ioctl FE_GET_INFO failed"); + close(fd); + ret = -1; + goto exit; + } + if (info.type != type) { + fprintf(stderr, "Not a valid %s device!\n", type_str[type]); + close(fd); + ret = -EINVAL; + goto exit; + } +exit: + return ret; +} + +char *del_str[] = { + "UNDEFINED", + "DVB-C (A)", + "DVB-C (B)", + "DVB-T", + "DSS", + "DVB-S", + "DVB-S2", + "DVB-H", + "ISDB-T", + "ISDB-S", + "ISDB-C", + "ATSC", + "ATSC-M/H", + "DTMB", + "CMMB", + "DAB", + "DVB-T2", + "TURBO", + "QAM (C)", +}; + +static int map_delivery_mode(fe_type_t *type, enum fe_delivery_system delsys) +{ + switch (delsys) { + case SYS_DSS: + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + *type = FE_QPSK; + break; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_DVBH: + case SYS_ISDBT: + *type = FE_OFDM; + break; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + *type = FE_QAM; + break; + case SYS_ATSC: + case SYS_DVBC_ANNEX_B: + *type = FE_ATSC; + break; + default: + fprintf(stderr, "Delivery system unsupported, please report to linux-media ML\n"); + return -1; + } + return 0; +} + +int get_property(int fd, uint32_t pcmd, uint32_t *len, uint8_t *data) +{ + struct dtv_property p, *b; + struct dtv_properties cmd; + int ret; + + p.cmd = pcmd; + cmd.num = 1; + cmd.props = &p; + b = &p; + + ret = ioctl(fd, FE_GET_PROPERTY, &cmd); + if (ret < 0) { + fprintf(stderr, "FE_SET_PROPERTY returned %d\n", ret); + return -1; + } + memcpy(len, &b->u.buffer.len, sizeof (uint32_t)); + memcpy(data, b->u.buffer.data, *len); + return 0; +} + +int set_property(int fd, uint32_t cmd, uint32_t data) +{ + struct dtv_property p, *b; + struct dtv_properties c; + int ret; + + p.cmd = cmd; + c.num = 1; + c.props = &p; + b = &p; + b->u.data = data; + ret = ioctl(fd, FE_SET_PROPERTY, &c); + if (ret < 0) { + fprintf(stderr, "FE_SET_PROPERTY returned %d\n", ret); + return -1; + } + return 0; +} + +int dvbfe_get_delsys(int fd, fe_delivery_system_t *delsys) +{ + uint32_t len; + /* Buggy API design */ + return get_property(fd, DTV_DELIVERY_SYSTEM, &len, (uint8_t *)delsys); +} + +int dvbfe_set_delsys(int fd, enum fe_delivery_system delsys) +{ + return set_property(fd, DTV_DELIVERY_SYSTEM, delsys); +} + +int dvbfe_enum_delsys(int fd, uint32_t *len, uint8_t *data) +{ + return get_property(fd, DTV_ENUM_DELSYS, len, data); +} + +int dvbfe_get_version(int fd, int *major, int *minor) +{ + struct dtv_property p, *b; + struct dtv_properties cmd; + int ret; + + p.cmd = DTV_API_VERSION; + cmd.num = 1; + cmd.props = &p; + b = &p; + + ret = ioctl(fd, FE_GET_PROPERTY, &cmd); + if (ret < 0) { + fprintf(stderr, "FE_GET_PROPERTY failed, ret=%d\n", ret); + return -1; + } + *major = (b->u.data >> 8) & 0xff; + *minor = b->u.data & 0xff; + return 0; +} + +int check_frontend_multi(int fd, enum fe_type type, uint32_t *mstd) +{ + int ret; + + enum fe_type delmode; + unsigned int i, valid_delsys = 0; + uint32_t len; + uint8_t data[32]; + + ret = dvbfe_enum_delsys(fd, &len, data); + if (ret) { + fprintf(stderr, "enum_delsys failed, ret=%d\n", ret); + ret = -EIO; + goto exit; + } + fprintf(stderr, "\t FE_CAN { "); + for (i = 0; i < len; i++) { + if (i < len - 1) + fprintf(stderr, "%s + ", del_str[data[i]]); + else + fprintf(stderr, "%s", del_str[data[i]]); + } + fprintf(stderr, " }\n"); + /* check whether frontend can support our delivery */ + for (i = 0; i < len; i++) { + map_delivery_mode(&delmode, data[i]); + if (type == delmode) { + valid_delsys = 1; + ret = 0; + break; + } + } + if (!valid_delsys) { + fprintf(stderr, "Not a valid %s device!\n", type_str[type]); + ret = -EINVAL; + goto exit; + } + *mstd = len; /* mstd has supported delsys count */ +exit: + return ret; +} + +int check_frontend(int fd, enum fe_type type, uint32_t *mstd) +{ + int major, minor, ret; + + ret = dvbfe_get_version(fd, &major, &minor); + if (ret) + goto exit; + fprintf(stderr, "Version: %d.%d ", major, minor); + if ((major == 5) && (minor > 8)) { + ret = check_frontend_multi(fd, type, mstd); + if (ret) + goto exit; + } else { + ret = check_frontend_v3(fd, type); + if (ret) + goto exit; + } +exit: + return ret; } |
