view.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <strings.h>
  5. #include <alloca.h>
  6. #include "pci.h"
  7. #include "pcilib.h"
  8. #include "view.h"
  9. #include "error.h"
  10. #include "value.h"
  11. int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc) {
  12. int err = 0;
  13. size_t i;
  14. void *ptr;
  15. if (!n) {
  16. // No padding between array elements
  17. ptr = (void*)desc;
  18. while (1) {
  19. const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr;
  20. if (v->name) n++;
  21. else break;
  22. ptr += v->api->description_size;
  23. }
  24. }
  25. if ((ctx->num_views + n + 1) > ctx->alloc_views) {
  26. size_t size;
  27. pcilib_view_description_t **views;
  28. for (size = ctx->alloc_views; size < 2 * (n + ctx->num_views + 1); size<<=1);
  29. views = (pcilib_view_description_t**)realloc(ctx->views, size * sizeof(pcilib_view_description_t*));
  30. if (!views) return PCILIB_ERROR_MEMORY;
  31. ctx->views = views;
  32. ctx->alloc_views = size;
  33. ctx->model_info.views = (const pcilib_view_description_t**)views;
  34. }
  35. // No padding between array elements
  36. ptr = (void*)desc;
  37. for (i = 0; i < n; i++) {
  38. const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr;
  39. pcilib_view_context_t *view_ctx;
  40. ctx->views[ctx->num_views + i] = (pcilib_view_description_t*)malloc(v->api->description_size);
  41. if (!ctx->views[ctx->num_views + i]) {
  42. err = PCILIB_ERROR_MEMORY;
  43. break;
  44. }
  45. if (v->api->init)
  46. view_ctx = v->api->init(ctx);
  47. else {
  48. view_ctx = (pcilib_view_context_t*)malloc(sizeof(pcilib_view_context_t));
  49. memset(view_ctx, 0, sizeof(pcilib_view_context_t));
  50. }
  51. view_ctx->view = ctx->num_views + i;
  52. view_ctx->name = v->name;
  53. if (!view_ctx) {
  54. free(ctx->views[ctx->num_views + i]);
  55. err = PCILIB_ERROR_MEMORY;
  56. break;
  57. }
  58. HASH_ADD_KEYPTR(hh, ctx->view_hash, view_ctx->name, strlen(view_ctx->name), view_ctx);
  59. memcpy(ctx->views[ctx->num_views + i], v, v->api->description_size);
  60. ptr += v->api->description_size;
  61. }
  62. ctx->views[ctx->num_views + i] = NULL;
  63. ctx->num_views += i;
  64. return err;
  65. }
  66. void pcilib_clean_views(pcilib_t *ctx) {
  67. pcilib_view_t i;
  68. pcilib_view_context_t *view_ctx, *tmp;
  69. if (ctx->unit_hash) {
  70. HASH_ITER(hh, ctx->view_hash, view_ctx, tmp) {
  71. const pcilib_view_description_t *v = ctx->views[view_ctx->view];
  72. HASH_DEL(ctx->view_hash, view_ctx);
  73. if (v->api->free) v->api->free(ctx, view_ctx);
  74. else free(view_ctx);
  75. }
  76. }
  77. for (i = 0; ctx->views[i]; i++) {
  78. if (ctx->views[i]->api->free_description) {
  79. ctx->views[i]->api->free_description(ctx, ctx->views[i]);
  80. } else {
  81. free(ctx->views[i]);
  82. }
  83. }
  84. ctx->views[0] = NULL;
  85. ctx->num_views = 0;
  86. }
  87. pcilib_view_context_t *pcilib_find_view_context_by_name(pcilib_t *ctx, const char *name) {
  88. pcilib_view_context_t *view_ctx = NULL;
  89. HASH_FIND_STR(ctx->view_hash, name, view_ctx);
  90. return view_ctx;
  91. }
  92. pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *name) {
  93. pcilib_view_context_t *view_ctx = pcilib_find_view_context_by_name(ctx, name);
  94. if (view_ctx) return view_ctx->view;
  95. return PCILIB_VIEW_INVALID;
  96. }
  97. pcilib_view_context_t *pcilib_find_register_view_context_by_name(pcilib_t *ctx, pcilib_register_t reg, const char *name) {
  98. pcilib_view_t i;
  99. pcilib_register_context_t *regctx = &ctx->register_ctx[reg];
  100. if (!regctx->views) return NULL;
  101. for (i = 0; regctx->views[i].name; i++) {
  102. if (!strcasecmp(name, regctx->views[i].name)) {
  103. return pcilib_find_view_context_by_name(ctx, regctx->views[i].view);
  104. }
  105. }
  106. return NULL;
  107. }
  108. // We expect symmetric units. Therefore, we don't distringuish if we read or write
  109. static int pcilib_detect_register_view_and_unit(pcilib_t *ctx, pcilib_register_t reg, const char *name, int write_direction, pcilib_view_context_t **ret_view, pcilib_unit_transform_t **ret_trans) {
  110. pcilib_view_t i;
  111. pcilib_view_context_t *view_ctx;
  112. pcilib_view_description_t *view_desc;
  113. pcilib_register_context_t *regctx = &ctx->register_ctx[reg];
  114. if (!regctx->views) return PCILIB_ERROR_NOTFOUND;
  115. // Check if view is just a name of listed view
  116. view_ctx = pcilib_find_register_view_context_by_name(ctx, reg, name);
  117. if (view_ctx) {
  118. if (ret_view) *ret_view = view_ctx;
  119. if (ret_trans) *ret_trans = NULL;
  120. return 0;
  121. }
  122. // Check if view is a unit
  123. for (i = 0; regctx->views[i].name; i++) {
  124. pcilib_unit_transform_t *trans;
  125. view_ctx = pcilib_find_view_context_by_name(ctx, regctx->views[i].view);
  126. if (!view_ctx) continue;
  127. view_desc = ctx->views[view_ctx->view];
  128. if (view_desc->unit) {
  129. if (write_direction)
  130. trans = pcilib_find_transform_by_unit_names(ctx, name, view_desc->unit);
  131. else
  132. trans = pcilib_find_transform_by_unit_names(ctx, view_desc->unit, name);
  133. if (trans) {
  134. if (ret_trans) *ret_trans = trans;
  135. if (ret_view) *ret_view = pcilib_find_view_context_by_name(ctx, view_desc->name);
  136. return 0;
  137. }
  138. }
  139. }
  140. return PCILIB_ERROR_NOTFOUND;
  141. }
  142. pcilib_view_context_t *pcilib_find_register_view_context(pcilib_t *ctx, pcilib_register_t reg, const char *name) {
  143. int err;
  144. pcilib_view_context_t *view;
  145. err = pcilib_detect_register_view_and_unit(ctx, reg, name, 0, &view, NULL);
  146. if (err) return NULL;
  147. return view;
  148. }
  149. typedef struct {
  150. pcilib_register_t reg;
  151. pcilib_view_context_t *view;
  152. pcilib_unit_transform_t *trans;
  153. } pcilib_view_configuration_t;
  154. static int pcilib_detect_view_configuration(pcilib_t *ctx, const char *bank, const char *regname, const char *view_cname, int write_direction, pcilib_view_configuration_t *cfg) {
  155. int err = 0;
  156. pcilib_view_t view;
  157. pcilib_view_context_t *view_ctx;
  158. pcilib_unit_transform_t *trans = NULL;
  159. pcilib_register_t reg = PCILIB_REGISTER_INVALID;
  160. char *view_name = alloca(strlen(view_cname) + 1);
  161. char *unit_name;
  162. strcpy(view_name, view_cname);
  163. unit_name = strchr(view_name, ':');
  164. if (unit_name) {
  165. *unit_name = 0;
  166. unit_name++;
  167. }
  168. if (regname) {
  169. reg = pcilib_find_register(ctx, bank, regname);
  170. if (reg == PCILIB_REGISTER_INVALID) {
  171. pcilib_error("Can't find the specified register %s", regname);
  172. return PCILIB_ERROR_NOTFOUND;
  173. }
  174. if (unit_name) view_ctx = pcilib_find_register_view_context_by_name(ctx, reg, view_name);
  175. else err = pcilib_detect_register_view_and_unit(ctx, reg, view_name, write_direction, &view_ctx, &trans);
  176. if ((err)||(!view_ctx)) {
  177. pcilib_error("Can't find the specified view %s for register %s", view_name, regname);
  178. return PCILIB_ERROR_NOTFOUND;
  179. }
  180. } else {
  181. view_ctx = pcilib_find_view_context_by_name(ctx, view_name);
  182. if (!view_ctx) {
  183. pcilib_error("Can't find the specified view %s", view_name);
  184. return PCILIB_ERROR_NOTFOUND;
  185. }
  186. }
  187. view = view_ctx->view;
  188. if (unit_name) {
  189. if (write_direction) trans = pcilib_find_transform_by_unit_names(ctx, unit_name, ctx->views[view]->unit);
  190. else trans = pcilib_find_transform_by_unit_names(ctx, ctx->views[view]->unit, unit_name);
  191. if (!trans) {
  192. pcilib_error("Don't know how to get the requested unit %s for view %s", unit_name, ctx->views[view]->name);
  193. return PCILIB_ERROR_NOTFOUND;
  194. }
  195. }
  196. // No transform is required
  197. if (!trans->transform) trans = NULL;
  198. cfg->reg = reg;
  199. cfg->view = view_ctx;
  200. cfg->trans = trans;
  201. return 0;
  202. }
  203. int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, pcilib_value_t *val) {
  204. int err;
  205. pcilib_view_description_t *v;
  206. pcilib_view_configuration_t cfg;
  207. pcilib_register_value_t regvalue = 0;
  208. err = pcilib_detect_view_configuration(ctx, bank, regname, view, 0, &cfg);
  209. if (err) return err;
  210. v = ctx->views[cfg.view->view];
  211. if (!v->api->read_from_reg) {
  212. pcilib_error("The view (%s) does not support reading from the register", view);
  213. return PCILIB_ERROR_NOTSUPPORTED;
  214. }
  215. if (regname) {
  216. err = pcilib_read_register_by_id(ctx, cfg.reg, &regvalue);
  217. if (err) {
  218. pcilib_error("Error (%i) reading register %s", err, regname);
  219. return err;
  220. }
  221. }
  222. pcilib_clean_value(ctx, val);
  223. err = v->api->read_from_reg(ctx, cfg.view, regvalue, val);
  224. if (err) {
  225. if (regname)
  226. pcilib_error("Error (%i) computing view (%s) of register %s", err, view, regname);
  227. else
  228. pcilib_error("Error (%i) computing view %s", err, view);
  229. return err;
  230. }
  231. if (cfg.trans) {
  232. err = pcilib_transform_unit(ctx, cfg.trans, val);
  233. if (err) return err;
  234. }
  235. return 0;
  236. }
  237. int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, const pcilib_value_t *valarg) {
  238. int err;
  239. pcilib_value_t val = {0};
  240. pcilib_view_description_t *v;
  241. pcilib_view_configuration_t cfg;
  242. pcilib_register_value_t regvalue = 0;
  243. err = pcilib_detect_view_configuration(ctx, bank, regname, view, 1, &cfg);
  244. if (err) return err;
  245. v = ctx->views[cfg.view->view];
  246. if (!v->api->write_to_reg) {
  247. pcilib_error("The view (%s) does not support reading from the register", view);
  248. return PCILIB_ERROR_NOTSUPPORTED;
  249. }
  250. err = pcilib_copy_value(ctx, &val, valarg);
  251. if (err) return err;
  252. err = pcilib_convert_value_type(ctx, &val, v->type);
  253. if (err) {
  254. pcilib_error("Error (%i) converting the value of type (%s) to type (%s) used by view (%s)", pcilib_get_type_name(val.type), pcilib_get_type_name(v->type), view);
  255. return err;
  256. }
  257. if (cfg.trans) {
  258. err = pcilib_transform_unit(ctx, cfg.trans, &val);
  259. if (err) return err;
  260. }
  261. err = v->api->write_to_reg(ctx, cfg.view, &regvalue, &val);
  262. if (err) {
  263. if (regname)
  264. pcilib_error("Error (%i) computing view (%s) of register %s", err, view, regname);
  265. else
  266. pcilib_error("Error (%i) computing view %s", err, view);
  267. return err;
  268. }
  269. if (regname) {
  270. err = pcilib_write_register_by_id(ctx, cfg.reg, regvalue);
  271. if (err) {
  272. pcilib_error("Error (%i) reading register %s", err, regname);
  273. return err;
  274. }
  275. }
  276. return 0;
  277. }