event.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. #define _POSIX_C_SOURCE 199309L
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <strings.h>
  5. #include <stdlib.h>
  6. #include <stdint.h>
  7. #include <stdarg.h>
  8. #include <fcntl.h>
  9. #include <unistd.h>
  10. #include <sys/ioctl.h>
  11. #include <sys/mman.h>
  12. #include <arpa/inet.h>
  13. #include <errno.h>
  14. #include <assert.h>
  15. #include <time.h>
  16. #include "pci.h"
  17. #include "tools.h"
  18. #include "error.h"
  19. /* Newer versions of glibc guard timespec with a different definition guard, compliant to linux/time.h
  20. * We need to check for both definition guards to prevent accidental redifinitions of struct timespec
  21. */
  22. #if (defined(__timespec_defined) && __timespec_defined) || \
  23. (defined(_STRUCT_TIMESPEC) && _STRUCT_TIMESPEC)
  24. #define PCILIB_DEFINE_TIMESPEC 0
  25. #else
  26. #define PCILIB_DEFINE_TIMESPEC 1
  27. #endif
  28. #if (defined(PCILIB_DEFINE_TIMESPEC) && PCILIB_DEFINE_TIMESPEC)
  29. struct timespec {
  30. time_t tv_sec;
  31. long tv_nsec;
  32. };
  33. #endif /* PCILIB_DEFINE_TIMESPEC */
  34. pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) {
  35. int i;
  36. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  37. const pcilib_event_description_t *events = model_info->events;
  38. for (i = 0; events[i].name; i++) {
  39. if (!strcasecmp(events[i].name, event)) return events[i].evid;
  40. }
  41. return (pcilib_event_t)-1;
  42. }
  43. pcilib_event_data_type_t pcilib_find_event_data_type(pcilib_t *ctx, pcilib_event_t event, const char *data_type) {
  44. int i;
  45. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  46. const pcilib_event_data_type_description_t *data_types = model_info->data_types;
  47. for (i = 0; data_types[i].name; i++) {
  48. if ((data_types[i].evid&event)&&(!strcasecmp(data_types[i].name, data_type))) return data_types[i].data_type;
  49. }
  50. return (pcilib_event_data_type_t)-1;
  51. }
  52. int pcilib_init_event_engine(pcilib_t *ctx) {
  53. const pcilib_event_api_description_t *api;
  54. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  55. api = model_info->api;
  56. if ((api)&&(api->init)) {
  57. ctx->event_ctx = api->init(ctx);
  58. if (ctx->event_ctx) {
  59. ctx->event_ctx->pcilib = ctx;
  60. }
  61. }
  62. return 0;
  63. }
  64. pcilib_context_t *pcilib_get_event_engine(pcilib_t *ctx) {
  65. return ctx->event_ctx;
  66. }
  67. int pcilib_reset(pcilib_t *ctx) {
  68. const pcilib_event_api_description_t *api;
  69. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  70. api = model_info->api;
  71. if (!api) {
  72. pcilib_error("Event API is not supported by the selected model");
  73. return PCILIB_ERROR_NOTSUPPORTED;
  74. }
  75. if (api->reset)
  76. return api->reset(ctx->event_ctx);
  77. return 0;
  78. }
  79. int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callback_t callback, void *user) {
  80. const pcilib_event_api_description_t *api;
  81. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  82. api = model_info->api;
  83. if (!api) {
  84. pcilib_error("Event API is not supported by the selected model");
  85. return PCILIB_ERROR_NOTSUPPORTED;
  86. }
  87. ctx->event_ctx->params.rawdata.callback = callback;
  88. ctx->event_ctx->params.rawdata.user = user;
  89. return 0;
  90. }
  91. int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t duration) {
  92. const pcilib_event_api_description_t *api;
  93. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  94. api = model_info->api;
  95. if (!api) {
  96. pcilib_error("Event API is not supported by the selected model");
  97. return PCILIB_ERROR_NOTSUPPORTED;
  98. }
  99. ctx->event_ctx->params.autostop.max_events = max_events;
  100. ctx->event_ctx->params.autostop.duration = duration;
  101. return 0;
  102. }
  103. int pcilib_configure_autotrigger(pcilib_t *ctx, pcilib_timeout_t interval, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
  104. /* To support hardware without autotriggering, we need to provide in event.c a code
  105. to generate multiple triggers in a thread (available in cli). The function should
  106. be re-enabled afterwards: just set parameters and let implementation decide if it
  107. can make triggering in hardware or will use our emulation */
  108. return PCILIB_ERROR_NOTSUPPORTED;
  109. }
  110. int pcilib_configure_preprocessing_threads(pcilib_t *ctx, size_t max_threads) {
  111. const pcilib_event_api_description_t *api;
  112. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  113. api = model_info->api;
  114. if (!api) {
  115. pcilib_error("Event API is not supported by the selected model");
  116. return PCILIB_ERROR_NOTSUPPORTED;
  117. }
  118. ctx->event_ctx->params.parallel.max_threads = max_threads;
  119. return 0;
  120. }
  121. int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) {
  122. int err;
  123. pcilib_register_value_t max_threads;
  124. const pcilib_event_api_description_t *api;
  125. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  126. api = model_info->api;
  127. if (!api) {
  128. pcilib_error("Event API is not supported by the selected model");
  129. return PCILIB_ERROR_NOTSUPPORTED;
  130. }
  131. err = pcilib_read_register(ctx, "conf", "max_threads", &max_threads);
  132. if (!err) {
  133. err = pcilib_configure_preprocessing_threads(ctx, max_threads);
  134. if (err) pcilib_warning("Error (%i) configuring number of preprocessing threads", err);
  135. }
  136. if (api->start)
  137. return api->start(ctx->event_ctx, event_mask, flags);
  138. return 0;
  139. }
  140. int pcilib_stop(pcilib_t *ctx, pcilib_event_flags_t flags) {
  141. const pcilib_event_api_description_t *api;
  142. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  143. api = model_info->api;
  144. if (!api) {
  145. pcilib_error("Event API is not supported by the selected model");
  146. return PCILIB_ERROR_NOTSUPPORTED;
  147. }
  148. if (api->stop)
  149. return api->stop(ctx->event_ctx, flags);
  150. return 0;
  151. }
  152. int pcilib_stream(pcilib_t *ctx, pcilib_event_callback_t callback, void *user) {
  153. const pcilib_event_api_description_t *api;
  154. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  155. api = model_info->api;
  156. if (!api) {
  157. pcilib_error("Event API is not supported by the selected model");
  158. return PCILIB_ERROR_NOTSUPPORTED;
  159. }
  160. if (api->stream)
  161. return api->stream(ctx->event_ctx, callback, user);
  162. if (api->next_event) {
  163. pcilib_error("Streaming using next_event API is not implemented yet");
  164. }
  165. pcilib_error("Event enumeration is not suppored by API");
  166. return PCILIB_ERROR_NOTSUPPORTED;
  167. }
  168. /*
  169. typedef struct {
  170. pcilib_event_id_t event_id;
  171. pcilib_event_info_t *info;
  172. } pcilib_return_event_callback_context_t;
  173. static int pcilib_return_event_callback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) {
  174. pcilib_return_event_callback_context_t *ctx = (pcilib_return_event_callback_context_t*)user;
  175. ctx->event_id = event_id;
  176. ctx->info = info;
  177. }
  178. */
  179. int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info) {
  180. const pcilib_event_api_description_t *api;
  181. // pcilib_return_event_callback_context_t user;
  182. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  183. api = model_info->api;
  184. if (!api) {
  185. pcilib_error("Event API is not supported by the selected model");
  186. return PCILIB_ERROR_NOTSUPPORTED;
  187. }
  188. if (api->next_event)
  189. return api->next_event(ctx->event_ctx, timeout, evid, info_size, info);
  190. /*
  191. if (api->stream) {
  192. err = api->stream(ctx->event_ctx, 1, timeout, pcilib_return_event_callback, &user);
  193. if (err) return err;
  194. if (evid) *evid = user->event_id;
  195. if (info) *info = user->info;
  196. return 0;
  197. }
  198. */
  199. pcilib_error("Event enumeration is not suppored by API");
  200. return PCILIB_ERROR_NOTSUPPORTED;
  201. }
  202. int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
  203. const pcilib_event_api_description_t *api;
  204. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  205. api = model_info->api;
  206. if (!api) {
  207. pcilib_error("Event API is not supported by the selected model");
  208. return PCILIB_ERROR_NOTSUPPORTED;
  209. }
  210. if (api->trigger)
  211. return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data);
  212. pcilib_error("Self triggering is not supported by the selected model");
  213. return PCILIB_ERROR_NOTSUPPORTED;
  214. }
  215. void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size) {
  216. int err;
  217. void *res = NULL;
  218. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  219. const pcilib_event_api_description_t *api = model_info->api;
  220. if (!api) {
  221. if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED;
  222. pcilib_error("Event API is not supported by the selected model");
  223. return NULL;
  224. }
  225. if (api->get_data) {
  226. err = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size, &res);
  227. if (err) {
  228. if (size) *size = (size_t)err;
  229. return NULL;
  230. }
  231. return res;
  232. }
  233. if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED;
  234. return NULL;
  235. }
  236. int pcilib_copy_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t size, void *buf, size_t *retsize) {
  237. int err;
  238. void *res = buf;
  239. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  240. const pcilib_event_api_description_t *api = model_info->api;
  241. if (!api) {
  242. pcilib_error("Event API is not supported by the selected model");
  243. return PCILIB_ERROR_NOTSUPPORTED;
  244. }
  245. if (api->get_data) {
  246. err = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, &size, &res);
  247. if (err) return err;
  248. if (buf != res) memcpy(buf, res, size);
  249. if (retsize) *retsize = size;
  250. return 0;
  251. }
  252. return PCILIB_ERROR_NOTSUPPORTED;
  253. }
  254. void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) {
  255. int err;
  256. void *res = NULL;
  257. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  258. const pcilib_event_api_description_t *api = model_info->api;
  259. if (!api) {
  260. pcilib_error("Event API is not supported by the selected model");
  261. if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED;
  262. return NULL;
  263. }
  264. if (api->get_data) {
  265. err = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size, &res);
  266. if (err) {
  267. if (size) *size = (size_t)err;
  268. return NULL;
  269. }
  270. return res;
  271. }
  272. if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED;
  273. return NULL;
  274. }
  275. int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t size, void *buf, size_t *ret_size) {
  276. int err;
  277. void *res = buf;
  278. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  279. const pcilib_event_api_description_t *api = model_info->api;
  280. if (!api) {
  281. pcilib_error("Event API is not supported by the selected model");
  282. return PCILIB_ERROR_NOTSUPPORTED;
  283. }
  284. if (api->get_data) {
  285. err = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, &size, &res);
  286. if (err) return err;
  287. if (buf != res) memcpy(buf, res, size);
  288. if (ret_size) *ret_size = size;
  289. return 0;
  290. }
  291. return PCILIB_ERROR_NOTSUPPORTED;
  292. }
  293. int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) {
  294. const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
  295. const pcilib_event_api_description_t *api = model_info->api;
  296. if (!api) {
  297. pcilib_error("Event API is not supported by the selected model");
  298. return PCILIB_ERROR_NOTSUPPORTED;
  299. }
  300. if (api->return_data)
  301. return api->return_data(ctx->event_ctx, event_id, data_type, data);
  302. return 0;
  303. }
  304. typedef struct {
  305. pcilib_t *ctx;
  306. size_t *size;
  307. void **data;
  308. } pcilib_grab_callback_user_data_t;
  309. static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) {
  310. int err;
  311. void *data;
  312. size_t size;
  313. int allocated = 0;
  314. pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser;
  315. data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size);
  316. if (!data) {
  317. pcilib_error("Error getting event data");
  318. return -(int)size;
  319. }
  320. if (*(user->data)) {
  321. if ((user->size)&&(*(user->size) < size)) {
  322. pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size);
  323. return -PCILIB_ERROR_MEMORY;
  324. }
  325. *(user->size) = size;
  326. } else {
  327. *(user->data) = malloc(size);
  328. if (!*(user->data)) {
  329. pcilib_error("Memory allocation (%i bytes) for event data is failed");
  330. return -PCILIB_ERROR_MEMORY;
  331. }
  332. if (*(user->size)) *(user->size) = size;
  333. allocated = 1;
  334. }
  335. memcpy(*(user->data), data, size);
  336. err = pcilib_return_data(user->ctx, event_id, PCILIB_EVENT_DATA, data);
  337. if (err) {
  338. if (allocated) {
  339. free(*(user->data));
  340. *(user->data) = NULL;
  341. }
  342. pcilib_error("The event data had been overwritten before it was returned, data corruption may occur");
  343. return -err;
  344. }
  345. return PCILIB_STREAMING_CONTINUE;
  346. }
  347. int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, pcilib_timeout_t timeout) {
  348. int err;
  349. pcilib_event_id_t eid;
  350. pcilib_grab_callback_user_data_t user = {ctx, size, data};
  351. err = pcilib_start(ctx, event_mask, PCILIB_EVENT_FLAGS_DEFAULT);
  352. if (!err) {
  353. if (timeout == PCILIB_TIMEOUT_IMMEDIATE) {
  354. err = pcilib_trigger(ctx, event_mask, 0, NULL);
  355. timeout = PCILIB_EVENT_TIMEOUT;
  356. }
  357. }
  358. if (!err) {
  359. err = pcilib_get_next_event(ctx, timeout, &eid, 0, NULL);
  360. if (!err) pcilib_grab_callback(event_mask, eid, &user);
  361. }
  362. pcilib_stop(ctx, PCILIB_EVENT_FLAGS_DEFAULT);
  363. return err;
  364. }