lsdvb.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * lsdvb - list PCI DVB devices
  3. *
  4. * Copyright (C) 2010 Manu Abraham <abraham.manu@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #define _GNU_SOURCE
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <stdint.h>
  24. #include <string.h>
  25. #include <sys/ioctl.h>
  26. #include <fcntl.h>
  27. #include <unistd.h>
  28. #include <sys/stat.h>
  29. #include <sys/param.h>
  30. #include <sys/types.h>
  31. #include <dirent.h>
  32. #include <linux/dvb/frontend.h>
  33. #define DVB_DIR "/dev/dvb"
  34. #define DVB_DEV_DIR "/dev/dvb"
  35. #define DVB_SYSFS_DIR "/sys/class/dvb"
  36. /**
  37. * DVB sysfs entries are found thus:
  38. * /sys/class/dvb/dvb0.frontend0/device/dvb/dvb0.frontend0/uevent for DVB_ADAPTER_NUM, DVB_DEVICE_NUM
  39. *
  40. * /sys/class/dvb/dvb0.frontend0/device/device for PCI_DEVICE_ID
  41. * /sys/class/dvb/dvb0.frontend0/device/vendor for PCI_VENDOR_ID
  42. * /sys/class/dvb/dvb0.frontend0/device/irq for PCI_IRQ
  43. */
  44. #define MAXLEN 64
  45. int get_frontend_entry(DIR *dvb_dir, char *frontend_dev)
  46. {
  47. struct dirent *adap_dir;
  48. char tmp[MAXLEN];
  49. adap_dir = readdir(dvb_dir);
  50. if (adap_dir != NULL) {
  51. /**
  52. * Directory structure follows:
  53. * .
  54. * ..
  55. * ~dvb0.demux0
  56. * ~dvb0.dvr0
  57. * ~dvb0.frontend0
  58. * ~dvb0.net0
  59. * ~dvb1.demux0
  60. * ~dvb1.dvr0
  61. * ~dvb1.frontend0
  62. * ~dvb1.net0
  63. */
  64. /* print information */
  65. sprintf(tmp, "%s/%s", DVB_SYSFS_DIR, adap_dir->d_name);
  66. /* search for a dir entry with string "frontend" */
  67. if (strstr(tmp, "frontend")) {
  68. /* found a dvbX.frontendY */
  69. strcpy(frontend_dev, tmp);
  70. return 0;
  71. } else {
  72. return -2;
  73. }
  74. } else {
  75. return -1;
  76. }
  77. }
  78. /* read device number and adapter number from the uevent file */
  79. int read_frontend_uevent(char *uevent, int *device, int *adapter)
  80. {
  81. char uf_name[MAXLEN];
  82. FILE *ufile;
  83. char line[128];
  84. char *token = NULL;
  85. /* get uevent file */
  86. sprintf(uf_name, "%s/%s", uevent, "uevent");
  87. ufile = fopen(uf_name, "r");
  88. if (ufile == NULL) {
  89. fprintf(stderr, "File: %s open failed\n", uf_name);
  90. return -1;
  91. }
  92. while (1) {
  93. if (fgets(line, sizeof (line), ufile) == NULL)
  94. return -1;
  95. if (strstr(line, "DVB_ADAPTER_NUM")) {
  96. token = strtok(line, "=");
  97. token = strtok(NULL, "=");
  98. *adapter = atoi(token);
  99. }
  100. if (strstr(line, "DVB_DEVICE_NUM")) {
  101. token = strtok(line, "=");
  102. token = strtok(NULL, "=");
  103. *device = atoi(token);
  104. }
  105. }
  106. fclose(ufile);
  107. return 0;
  108. }
  109. int read_device_uevent(char *uevent,
  110. char *drv,
  111. int *pci_ven,
  112. int *pci_dev,
  113. int *pci_subven,
  114. int *pci_subdev,
  115. int *domain,
  116. int *bus,
  117. int *device,
  118. int *fn)
  119. {
  120. char uf_name[MAXLEN];
  121. FILE *ufile;
  122. char line[128];
  123. char *token = NULL;
  124. char *tmp;
  125. unsigned int i;
  126. /* get uevent file */
  127. sprintf(uf_name, "%s/%s", uevent, "device/uevent");
  128. ufile = fopen(uf_name, "r");
  129. if (ufile == NULL) {
  130. fprintf(stderr, "File: %s open failed\n", uf_name);
  131. return -1;
  132. }
  133. while (1) {
  134. if (fgets(line, sizeof (line), ufile) == NULL)
  135. return -1;
  136. if (strstr(line, "DRIVER")) {
  137. token = strtok(line, "=");
  138. token = strtok(NULL, "=");
  139. for (i = 0; i < strlen(token); i++) {
  140. if (token[i] == '\n' || token[i] == '\r')
  141. token[i] = '\0';
  142. }
  143. strcpy(drv, token);
  144. }
  145. if (strstr(line, "PCI_ID")) {
  146. token = strtok(line, "=");
  147. token = strtok(NULL, "=");
  148. *pci_ven = atoi(strtok(token, ":"));
  149. *pci_dev = atoi(strtok(NULL, ":"));
  150. }
  151. if (strstr(line, "PCI_SUBSYS_ID")) {
  152. token = strtok(line, "=");
  153. token = strtok(NULL, "=");
  154. *pci_subven = atoi(strtok(token, ":"));
  155. *pci_subdev = atoi(strtok(NULL, ":"));
  156. }
  157. if (strstr(line, "PCI_SLOT_NAME")) {
  158. token = strtok(line, "=");
  159. token = strtok(NULL, "=");
  160. *domain = atoi(strtok(token, ":"));
  161. *bus = atoi(strtok(NULL, ":"));
  162. tmp = strtok(NULL, ":");
  163. *device = atoi(strtok(tmp, "."));
  164. *fn = atoi(strtok(NULL, "."));
  165. }
  166. }
  167. fclose(ufile);
  168. return 0;
  169. }
  170. /* retrieve frontend info */
  171. int get_frontend_info(int adapter, char *frontend)
  172. {
  173. DIR *dev_dir;
  174. struct dirent *adap_dir;
  175. char tmp[MAXLEN];
  176. sprintf(tmp, "%s/adapter%d", DVB_DIR, adapter);
  177. dev_dir = opendir(tmp);
  178. if (!dev_dir) {
  179. fprintf(stderr, "ERROR: Opening %s directory\n", tmp);
  180. return - 1;
  181. }
  182. while ((adap_dir = readdir(dev_dir)) != NULL) {
  183. /**
  184. * Directory structure follows:
  185. * .
  186. * ..
  187. * frontend0
  188. * frontend1
  189. * demux0
  190. * dvr0
  191. * net0
  192. */
  193. if (!strcmp(adap_dir->d_name, "."))
  194. continue;
  195. if (!strcmp(adap_dir->d_name, ".."))
  196. continue;
  197. /* search for a dir entry with string "frontend" */
  198. if (strstr(adap_dir->d_name, "frontend")) {
  199. /* found a dvbX.frontendY */
  200. strcpy(frontend, adap_dir->d_name);
  201. }
  202. }
  203. closedir(dev_dir);
  204. return 0;
  205. }
  206. int main(void)
  207. {
  208. DIR *sys_dir;
  209. char frontend_dev[MAXLEN];
  210. int entry, device, adapter;
  211. char drv[MAXLEN];
  212. int pci_ven, pci_dev, pci_subven, pci_subdev;
  213. int domain, bus, dev, fn;
  214. int dev_prev = -1;
  215. char tmp[MAXLEN];
  216. char frontend[MAXLEN];
  217. char fedev[MAXLEN];
  218. int fd, ret;
  219. struct dvb_frontend_info info;
  220. static char *fe_type[] = {
  221. [0] = "FE_QPSK",
  222. [1] = "FE_QAM",
  223. [2] = "FE_OFDM",
  224. [3] = "FE_ATSC",
  225. };
  226. fprintf(stderr, "\n\t\tlsdvb: Simple utility to list PCI/PCIe DVB devices\n");
  227. fprintf(stderr, "\t\tVersion: 0.0.4\n");
  228. fprintf(stderr, "\t\tCopyright (C) Manu Abraham\n");
  229. sys_dir = opendir(DVB_SYSFS_DIR);
  230. if (!sys_dir) {
  231. fprintf(stderr, "ERROR: Opening %s directory\n", DVB_SYSFS_DIR);
  232. return - 1;
  233. }
  234. while (1) {
  235. entry = get_frontend_entry(sys_dir, frontend_dev);
  236. if (entry == 0) {
  237. read_device_uevent(frontend_dev,
  238. drv,
  239. &pci_ven,
  240. &pci_dev,
  241. &pci_subven,
  242. &pci_subdev,
  243. &domain,
  244. &bus,
  245. &dev,
  246. &fn);
  247. read_frontend_uevent(frontend_dev, &device, &adapter);
  248. if (device != dev_prev) {
  249. fprintf(stderr, "\n%s (%d:%d %d:%d) on PCI Domain:%d Bus:%d Device:%d Function:%d\n",
  250. drv, pci_ven, pci_dev, pci_subven, pci_subdev, domain, bus, dev, fn);
  251. }
  252. fprintf(stderr, "\tDEVICE:%d ADAPTER:%d ", device, adapter);
  253. dev_prev = device;
  254. get_frontend_info(adapter, frontend);
  255. sprintf(fedev, "%s/adapter%d/%s", DVB_DIR, adapter, frontend);
  256. fd = open(fedev, O_RDWR | O_NONBLOCK);
  257. if (fd < 0) {
  258. fprintf(stderr, "ERROR: Open %s failed\n", frontend);
  259. return -1;
  260. }
  261. ret = ioctl(fd, FE_GET_INFO, &info);
  262. if (ret < 0) {
  263. fprintf(stderr, "ERROR: IOCTL failed\n");
  264. return -1;
  265. }
  266. strncpy(tmp, frontend + 8, 1);
  267. fprintf(stderr, "FRONTEND:%d (%s) \n\t\t %s Fmin=%dMHz Fmax=%dMHz\n",
  268. atoi(tmp),
  269. info.name,
  270. fe_type[info.type],
  271. info.type == 0 ? info.frequency_min / 1000: info.frequency_min / 1000000,
  272. info.type == 0 ? info.frequency_max / 1000: info.frequency_max / 1000000);
  273. }
  274. if (entry == -1)
  275. break;
  276. if (entry == -2)
  277. continue;
  278. }
  279. closedir(sys_dir);
  280. return 0;
  281. }