util.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * util functions for various ?zap implementations
  3. *
  4. * Copyright (C) 2001 Johannes Stezenbach (js@convergence.de)
  5. * for convergence integrated media
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <stdio.h>
  24. #include <errno.h>
  25. #include <stdint.h>
  26. #include <sys/ioctl.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <fcntl.h>
  30. #include <linux/dvb/frontend.h>
  31. #include <linux/dvb/dmx.h>
  32. int set_pesfilter(int dmxfd, int pid, int pes_type, int dvr)
  33. {
  34. struct dmx_pes_filter_params pesfilter;
  35. /* ignore this pid to allow radio services */
  36. if (pid < 0 || pid >= 0x1fff || (pid == 0 && pes_type != DMX_PES_OTHER))
  37. return 0;
  38. if (dvr) {
  39. int buffersize = 64 * 1024;
  40. if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
  41. perror("DMX_SET_BUFFER_SIZE failed");
  42. }
  43. pesfilter.pid = pid;
  44. pesfilter.input = DMX_IN_FRONTEND;
  45. pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
  46. pesfilter.pes_type = pes_type;
  47. pesfilter.flags = DMX_IMMEDIATE_START;
  48. if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
  49. fprintf(stderr, "DMX_SET_PES_FILTER failed "
  50. "(PID = 0x%04x): %d %m\n", pid, errno);
  51. return -1;
  52. }
  53. return 0;
  54. }
  55. int get_pmt_pid(char *dmxdev, int sid)
  56. {
  57. int patfd, count;
  58. int pmt_pid = 0;
  59. int patread = 0;
  60. int section_length;
  61. unsigned char buft[4096];
  62. unsigned char *buf = buft;
  63. struct dmx_sct_filter_params f;
  64. memset(&f, 0, sizeof(f));
  65. f.pid = 0;
  66. f.filter.filter[0] = 0x00;
  67. f.filter.mask[0] = 0xff;
  68. f.timeout = 0;
  69. f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
  70. if ((patfd = open(dmxdev, O_RDWR)) < 0) {
  71. perror("openening pat demux failed");
  72. return -1;
  73. }
  74. if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) {
  75. perror("ioctl DMX_SET_FILTER failed");
  76. close(patfd);
  77. return -1;
  78. }
  79. while (!patread) {
  80. if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
  81. count = read(patfd, buf, sizeof(buft));
  82. if (count < 0) {
  83. perror("read_sections: read error");
  84. close(patfd);
  85. return -1;
  86. }
  87. section_length = ((buf[1] & 0x0f) << 8) | buf[2];
  88. if (count != section_length + 3)
  89. continue;
  90. buf += 8;
  91. section_length -= 8;
  92. patread = 1; /* assumes one section contains the whole pat */
  93. while (section_length > 0) {
  94. int service_id = (buf[0] << 8) | buf[1];
  95. if (service_id == sid) {
  96. pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
  97. section_length = 0;
  98. }
  99. buf += 4;
  100. section_length -= 4;
  101. }
  102. }
  103. close(patfd);
  104. return pmt_pid;
  105. }
  106. char *type_str[] = {
  107. "QPSK",
  108. "QAM",
  109. "OFDM",
  110. "ATSC",
  111. };
  112. /* to be used with v3 drivers */
  113. int check_frontend_v3(int fd, enum fe_type type)
  114. {
  115. struct dvb_frontend_info info;
  116. int ret;
  117. ret = ioctl(fd, FE_GET_INFO, &info);
  118. if (ret < 0) {
  119. perror("ioctl FE_GET_INFO failed");
  120. close(fd);
  121. ret = -1;
  122. goto exit;
  123. }
  124. if (info.type != type) {
  125. fprintf(stderr, "Not a valid %s device!\n", type_str[type]);
  126. close(fd);
  127. ret = -EINVAL;
  128. goto exit;
  129. }
  130. exit:
  131. return ret;
  132. }
  133. char *del_str[] = {
  134. "UNDEFINED",
  135. "DVB-C (A)",
  136. "DVB-C (B)",
  137. "DVB-T",
  138. "DSS",
  139. "DVB-S",
  140. "DVB-S2",
  141. "DVB-H",
  142. "ISDB-T",
  143. "ISDB-S",
  144. "ISDB-C",
  145. "ATSC",
  146. "ATSC-M/H",
  147. "DTMB",
  148. "CMMB",
  149. "DAB",
  150. "DVB-T2",
  151. "TURBO",
  152. "QAM (C)",
  153. };
  154. static int map_delivery_mode(fe_type_t *type, enum fe_delivery_system delsys)
  155. {
  156. switch (delsys) {
  157. case SYS_DSS:
  158. case SYS_DVBS:
  159. case SYS_DVBS2:
  160. case SYS_TURBO:
  161. *type = FE_QPSK;
  162. break;
  163. case SYS_DVBT:
  164. case SYS_DVBT2:
  165. case SYS_DVBH:
  166. case SYS_ISDBT:
  167. *type = FE_OFDM;
  168. break;
  169. case SYS_DVBC_ANNEX_A:
  170. case SYS_DVBC_ANNEX_C:
  171. *type = FE_QAM;
  172. break;
  173. case SYS_ATSC:
  174. case SYS_DVBC_ANNEX_B:
  175. *type = FE_ATSC;
  176. break;
  177. default:
  178. fprintf(stderr, "Delivery system unsupported, please report to linux-media ML\n");
  179. return -1;
  180. }
  181. return 0;
  182. }
  183. int get_property(int fd, uint32_t pcmd, uint32_t *len, uint8_t *data)
  184. {
  185. struct dtv_property p, *b;
  186. struct dtv_properties cmd;
  187. int ret;
  188. p.cmd = pcmd;
  189. cmd.num = 1;
  190. cmd.props = &p;
  191. b = &p;
  192. ret = ioctl(fd, FE_GET_PROPERTY, &cmd);
  193. if (ret < 0) {
  194. fprintf(stderr, "FE_SET_PROPERTY returned %d\n", ret);
  195. return -1;
  196. }
  197. memcpy(len, &b->u.buffer.len, sizeof (uint32_t));
  198. memcpy(data, b->u.buffer.data, *len);
  199. return 0;
  200. }
  201. int set_property(int fd, uint32_t cmd, uint32_t data)
  202. {
  203. struct dtv_property p, *b;
  204. struct dtv_properties c;
  205. int ret;
  206. p.cmd = cmd;
  207. c.num = 1;
  208. c.props = &p;
  209. b = &p;
  210. b->u.data = data;
  211. ret = ioctl(fd, FE_SET_PROPERTY, &c);
  212. if (ret < 0) {
  213. fprintf(stderr, "FE_SET_PROPERTY returned %d\n", ret);
  214. return -1;
  215. }
  216. return 0;
  217. }
  218. int dvbfe_get_delsys(int fd, fe_delivery_system_t *delsys)
  219. {
  220. uint32_t len;
  221. /* Buggy API design */
  222. return get_property(fd, DTV_DELIVERY_SYSTEM, &len, (uint8_t *)delsys);
  223. }
  224. int dvbfe_set_delsys(int fd, enum fe_delivery_system delsys)
  225. {
  226. return set_property(fd, DTV_DELIVERY_SYSTEM, delsys);
  227. }
  228. int dvbfe_enum_delsys(int fd, uint32_t *len, uint8_t *data)
  229. {
  230. return get_property(fd, DTV_ENUM_DELSYS, len, data);
  231. }
  232. int dvbfe_get_version(int fd, int *major, int *minor)
  233. {
  234. struct dtv_property p, *b;
  235. struct dtv_properties cmd;
  236. int ret;
  237. p.cmd = DTV_API_VERSION;
  238. cmd.num = 1;
  239. cmd.props = &p;
  240. b = &p;
  241. ret = ioctl(fd, FE_GET_PROPERTY, &cmd);
  242. if (ret < 0) {
  243. fprintf(stderr, "FE_GET_PROPERTY failed, ret=%d\n", ret);
  244. return -1;
  245. }
  246. *major = (b->u.data >> 8) & 0xff;
  247. *minor = b->u.data & 0xff;
  248. return 0;
  249. }
  250. int check_frontend_multi(int fd, enum fe_type type, uint32_t *mstd)
  251. {
  252. int ret;
  253. enum fe_type delmode;
  254. unsigned int i, valid_delsys = 0;
  255. uint32_t len;
  256. uint8_t data[32];
  257. ret = dvbfe_enum_delsys(fd, &len, data);
  258. if (ret) {
  259. fprintf(stderr, "enum_delsys failed, ret=%d\n", ret);
  260. ret = -EIO;
  261. goto exit;
  262. }
  263. fprintf(stderr, "\t FE_CAN { ");
  264. for (i = 0; i < len; i++) {
  265. if (i < len - 1)
  266. fprintf(stderr, "%s + ", del_str[data[i]]);
  267. else
  268. fprintf(stderr, "%s", del_str[data[i]]);
  269. }
  270. fprintf(stderr, " }\n");
  271. /* check whether frontend can support our delivery */
  272. for (i = 0; i < len; i++) {
  273. map_delivery_mode(&delmode, data[i]);
  274. if (type == delmode) {
  275. valid_delsys = 1;
  276. ret = 0;
  277. break;
  278. }
  279. }
  280. if (!valid_delsys) {
  281. fprintf(stderr, "Not a valid %s device!\n", type_str[type]);
  282. ret = -EINVAL;
  283. goto exit;
  284. }
  285. *mstd = len; /* mstd has supported delsys count */
  286. exit:
  287. return ret;
  288. }
  289. int check_frontend(int fd, enum fe_type type, uint32_t *mstd)
  290. {
  291. int major, minor, ret;
  292. ret = dvbfe_get_version(fd, &major, &minor);
  293. if (ret)
  294. goto exit;
  295. fprintf(stderr, "Version: %d.%d ", major, minor);
  296. if ((major == 5) && (minor > 8)) {
  297. ret = check_frontend_multi(fd, type, mstd);
  298. if (ret)
  299. goto exit;
  300. } else {
  301. ret = check_frontend_v3(fd, type);
  302. if (ret)
  303. goto exit;
  304. }
  305. exit:
  306. return ret;
  307. }