view.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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. size_t i;
  13. void *ptr;
  14. if (!n) {
  15. // No padding between array elements
  16. ptr = (void*)desc;
  17. while (1) {
  18. const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr;
  19. if (v->name) n++;
  20. else break;
  21. ptr += v->api->description_size;
  22. }
  23. }
  24. if ((ctx->num_views + n + 1) > ctx->alloc_views) {
  25. size_t size;
  26. pcilib_view_description_t **views;
  27. for (size = ctx->alloc_views; size < 2 * (n + ctx->num_views + 1); size<<=1);
  28. views = (pcilib_view_description_t**)realloc(ctx->views, size * sizeof(pcilib_view_description_t*));
  29. if (!views) return PCILIB_ERROR_MEMORY;
  30. ctx->views = views;
  31. ctx->alloc_views = size;
  32. ctx->model_info.views = (const pcilib_view_description_t**)views;
  33. }
  34. // No padding between array elements
  35. ptr = (void*)desc;
  36. for (i = 0; i < n; i++) {
  37. const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr;
  38. ctx->views[ctx->num_views + i] = (pcilib_view_description_t*)malloc(v->api->description_size);
  39. if (!ctx->views[ctx->num_views + i]) {
  40. size_t j;
  41. for (j = 0; j < i; j++)
  42. free(ctx->views[ctx->num_views + j]);
  43. ctx->views[ctx->num_views] = NULL;
  44. pcilib_error("Error allocating %zu bytes of memory for the view description", v->api->description_size);
  45. return PCILIB_ERROR_MEMORY;
  46. }
  47. memcpy(ctx->views[ctx->num_views + i], v, v->api->description_size);
  48. ptr += v->api->description_size;
  49. }
  50. ctx->views[ctx->num_views + i] = NULL;
  51. ctx->num_views += n;
  52. return 0;
  53. }
  54. pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *name) {
  55. pcilib_view_t i;
  56. for(i = 0; ctx->views[i]; i++) {
  57. if (!strcasecmp(ctx->views[i]->name, name))
  58. return i;
  59. }
  60. return PCILIB_VIEW_INVALID;
  61. }
  62. pcilib_view_t pcilib_find_register_view_by_name(pcilib_t *ctx, pcilib_register_t reg, const char *name) {
  63. pcilib_view_t i;
  64. pcilib_register_context_t *regctx = &ctx->register_ctx[reg];
  65. if (!regctx->views) return PCILIB_VIEW_INVALID;
  66. for (i = 0; regctx->views[i].name; i++) {
  67. if (strcasecmp(name, regctx->views[i].name)) {
  68. return pcilib_find_view_by_name(ctx, regctx->views[i].view);
  69. }
  70. }
  71. return PCILIB_VIEW_INVALID;
  72. }
  73. // We expect symmetric units. Therefore, we don't distringuish if we read or write
  74. pcilib_view_t pcilib_find_register_view(pcilib_t *ctx, pcilib_register_t reg, const char *name) {
  75. pcilib_view_t i;
  76. pcilib_register_context_t *regctx = &ctx->register_ctx[reg];
  77. if (!regctx->views) return PCILIB_VIEW_INVALID;
  78. // Check if view is just a name of listed view
  79. i = pcilib_find_register_view_by_name(ctx, reg, name);
  80. if (i != PCILIB_VIEW_INVALID) return i;
  81. // Check if view is a unit
  82. for (i = 0; regctx->views[i].name; i++) {
  83. pcilib_unit_transform_t *trans;
  84. pcilib_view_t view = pcilib_find_view_by_name(ctx, regctx->views[i].view);
  85. if (view == PCILIB_VIEW_INVALID) continue;
  86. if (ctx->views[view]->unit) {
  87. trans = pcilib_find_transform_by_unit_names(ctx, ctx->views[view]->unit, name);
  88. if (trans) return view;
  89. }
  90. }
  91. return PCILIB_VIEW_INVALID;
  92. }
  93. typedef struct {
  94. pcilib_register_t reg;
  95. pcilib_view_t view;
  96. pcilib_unit_transform_t *trans;
  97. } pcilib_view_configuration_t;
  98. 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) {
  99. pcilib_view_t view;
  100. pcilib_register_t reg = PCILIB_REGISTER_INVALID;
  101. pcilib_unit_transform_t *trans = NULL;
  102. char *view_name = alloca(strlen(view_cname) + 1);
  103. char *unit_name;
  104. strcpy(view_name, view_cname);
  105. unit_name = strchr(view_name, ':');
  106. if (unit_name) {
  107. *unit_name = 0;
  108. unit_name++;
  109. }
  110. if (regname) {
  111. reg = pcilib_find_register(ctx, bank, regname);
  112. if (reg == PCILIB_REGISTER_INVALID) {
  113. pcilib_error("Can't find the specified register %s", regname);
  114. return PCILIB_ERROR_NOTFOUND;
  115. }
  116. // get value
  117. if (unit_name) view = pcilib_find_register_view_by_name(ctx, reg, view_name);
  118. else view = pcilib_find_register_view(ctx, reg, view_name);
  119. if (view == PCILIB_VIEW_INVALID) {
  120. pcilib_error("Can't find the specified view %s for register %s", view_name, regname);
  121. return PCILIB_ERROR_NOTFOUND;
  122. }
  123. } else {
  124. view = pcilib_find_view_by_name(ctx, view_name);
  125. if (view == PCILIB_VIEW_INVALID) {
  126. pcilib_error("Can't find the specified view %s", view_name);
  127. return PCILIB_ERROR_NOTFOUND;
  128. }
  129. }
  130. if (unit_name) {
  131. if (write_direction) trans = pcilib_find_transform_by_unit_names(ctx, unit_name, ctx->views[view]->unit);
  132. else trans = pcilib_find_transform_by_unit_names(ctx, ctx->views[view]->unit, unit_name);
  133. if (!trans) {
  134. pcilib_error("Don't know how to get the requested unit %s for view %s", unit_name, ctx->views[view]->name);
  135. return PCILIB_ERROR_NOTFOUND;
  136. }
  137. // No transform is required
  138. if (!trans->transform) trans = NULL;
  139. }
  140. cfg->reg = reg;
  141. cfg->view = view;
  142. cfg->trans = trans;
  143. return 0;
  144. }
  145. int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, pcilib_value_t *val) {
  146. int err;
  147. pcilib_view_configuration_t cfg;
  148. pcilib_register_value_t regvalue = 0;
  149. err = pcilib_detect_view_configuration(ctx, bank, regname, view, 0, &cfg);
  150. if (err) return err;
  151. if (!ctx->views[cfg.view]->api->read_from_reg) {
  152. pcilib_error("The view (%s) does not support reading from the register", view);
  153. return PCILIB_ERROR_NOTSUPPORTED;
  154. }
  155. if (regname) {
  156. err = pcilib_read_register_by_id(ctx, cfg.reg, &regvalue);
  157. if (err) {
  158. pcilib_error("Error (%i) reading register %s", err, regname);
  159. return err;
  160. }
  161. }
  162. pcilib_clean_value(ctx, val);
  163. err = ctx->views[cfg.view]->api->read_from_reg(ctx, NULL /*???*/, &regvalue, val);
  164. if (err) {
  165. if (regname)
  166. pcilib_error("Error (%i) computing view (%s) of register %s", err, view, regname);
  167. else
  168. pcilib_error("Error (%i) computing view %s", err, view);
  169. return err;
  170. }
  171. if (cfg.trans) {
  172. err = pcilib_transform_unit(ctx, cfg.trans, val);
  173. if (err) return err;
  174. }
  175. return 0;
  176. }
  177. int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, const pcilib_value_t *valarg) {
  178. int err;
  179. pcilib_value_t val;
  180. pcilib_view_configuration_t cfg;
  181. pcilib_register_value_t regvalue = 0;
  182. err = pcilib_detect_view_configuration(ctx, bank, regname, view, 1, &cfg);
  183. if (err) return err;
  184. if (!ctx->views[cfg.view]->api->write_to_reg) {
  185. pcilib_error("The view (%s) does not support reading from the register", view);
  186. return PCILIB_ERROR_NOTSUPPORTED;
  187. }
  188. err = pcilib_copy_value(ctx, &val, valarg);
  189. if (err) return err;
  190. err = pcilib_convert_value_type(ctx, &val, ctx->views[cfg.view]->type);
  191. if (err) {
  192. 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(ctx->views[cfg.view]->type), view);
  193. return err;
  194. }
  195. if (cfg.trans) {
  196. err = pcilib_transform_unit(ctx, cfg.trans, &val);
  197. if (err) return err;
  198. }
  199. err = ctx->views[cfg.view]->api->write_to_reg(ctx, NULL /*???*/, &regvalue, &val);
  200. if (err) {
  201. if (regname)
  202. pcilib_error("Error (%i) computing view (%s) of register %s", err, view, regname);
  203. else
  204. pcilib_error("Error (%i) computing view %s", err, view);
  205. return err;
  206. }
  207. if (regname) {
  208. err = pcilib_write_register_by_id(ctx, cfg.reg, regvalue);
  209. if (err) {
  210. pcilib_error("Error (%i) reading register %s", err, regname);
  211. return err;
  212. }
  213. }
  214. return 0;
  215. }