view.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. #include "property.h"
  12. int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc, pcilib_view_context_t **refs) {
  13. int err;
  14. size_t i;
  15. void *ptr;
  16. if (!n) {
  17. // No padding between array elements
  18. ptr = (void*)desc;
  19. while (1) {
  20. const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr;
  21. if (v->name) n++;
  22. else break;
  23. ptr += v->api->description_size;
  24. }
  25. }
  26. if (!refs) {
  27. refs = (pcilib_view_context_t**)alloca(n * sizeof(pcilib_view_context_t*));
  28. if (!refs) return PCILIB_ERROR_MEMORY;
  29. }
  30. if ((ctx->num_views + n + 1) > ctx->alloc_views) {
  31. size_t size;
  32. pcilib_view_description_t **views;
  33. for (size = ctx->alloc_views; size < 2 * (n + ctx->num_views + 1); size<<=1);
  34. views = (pcilib_view_description_t**)realloc(ctx->views, size * sizeof(pcilib_view_description_t*));
  35. if (!views) return PCILIB_ERROR_MEMORY;
  36. ctx->views = views;
  37. ctx->alloc_views = size;
  38. ctx->model_info.views = (const pcilib_view_description_t**)views;
  39. }
  40. // No padding between array elements
  41. ptr = (void*)desc;
  42. for (i = 0; i < n; i++) {
  43. const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr;
  44. pcilib_view_description_t *cur;
  45. pcilib_view_context_t *view_ctx;
  46. pcilib_view_t view = pcilib_find_view_by_name(ctx, v->name);
  47. if (view != PCILIB_VIEW_INVALID) {
  48. ctx->views[ctx->num_views + i] = NULL;
  49. pcilib_clean_views(ctx, ctx->num_views);
  50. pcilib_error("View %s is already defined in the model", v->name);
  51. return PCILIB_ERROR_EXIST;
  52. }
  53. cur = (pcilib_view_description_t*)malloc(v->api->description_size);
  54. if (!cur) {
  55. ctx->views[ctx->num_views + i] = NULL;
  56. pcilib_clean_views(ctx, ctx->num_views);
  57. return PCILIB_ERROR_MEMORY;
  58. }
  59. memcpy(cur, v, v->api->description_size);
  60. ctx->views[ctx->num_views + i] = cur;
  61. if (v->api->init)
  62. view_ctx = v->api->init(ctx, ctx->num_views + i);
  63. else {
  64. view_ctx = (pcilib_view_context_t*)malloc(sizeof(pcilib_view_context_t));
  65. if (view_ctx) memset(view_ctx, 0, sizeof(pcilib_view_context_t));
  66. }
  67. if (!view_ctx) {
  68. free(cur);
  69. ctx->views[ctx->num_views + i] = NULL;
  70. pcilib_clean_views(ctx, ctx->num_views);
  71. return PCILIB_ERROR_FAILED;
  72. }
  73. view_ctx->view = ctx->num_views + i;
  74. view_ctx->name = v->name;
  75. HASH_ADD_KEYPTR(hh, ctx->view_hash, view_ctx->name, strlen(view_ctx->name), view_ctx);
  76. if (refs) refs[i] = view_ctx;
  77. ptr += v->api->description_size;
  78. }
  79. ctx->views[ctx->num_views + n] = NULL;
  80. err = pcilib_add_registers_from_properties(ctx, n, refs, ctx->views + ctx->num_views);
  81. if (err) {
  82. pcilib_clean_views(ctx, ctx->num_views);
  83. return err;
  84. }
  85. ctx->num_views += n;
  86. return 0;
  87. }
  88. int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc) {
  89. return pcilib_add_views_custom(ctx, n, desc, NULL);
  90. }
  91. void pcilib_clean_views(pcilib_t *ctx, pcilib_view_t start) {
  92. pcilib_view_t i;
  93. pcilib_view_context_t *view_ctx, *tmp;
  94. if (ctx->view_hash) {
  95. HASH_ITER(hh, ctx->view_hash, view_ctx, tmp) {
  96. const pcilib_view_description_t *v = ctx->views[view_ctx->view];
  97. if (view_ctx->view >= start) {
  98. HASH_DEL(ctx->view_hash, view_ctx);
  99. if (v->api->free) v->api->free(ctx, view_ctx);
  100. else free(view_ctx);
  101. }
  102. }
  103. }
  104. for (i = start; ctx->views[i]; i++) {
  105. if (ctx->views[i]->api->free_description) {
  106. ctx->views[i]->api->free_description(ctx, ctx->views[i]);
  107. } else {
  108. free(ctx->views[i]);
  109. }
  110. }
  111. ctx->views[start] = NULL;
  112. ctx->num_views = start;
  113. }
  114. pcilib_view_context_t *pcilib_find_view_context_by_name(pcilib_t *ctx, const char *name) {
  115. pcilib_view_context_t *view_ctx = NULL;
  116. HASH_FIND_STR(ctx->view_hash, name, view_ctx);
  117. return view_ctx;
  118. }
  119. pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *name) {
  120. pcilib_view_context_t *view_ctx = pcilib_find_view_context_by_name(ctx, name);
  121. if (view_ctx) return view_ctx->view;
  122. return PCILIB_VIEW_INVALID;
  123. }
  124. pcilib_view_context_t *pcilib_find_register_view_context_by_name(pcilib_t *ctx, pcilib_register_t reg, const char *name) {
  125. pcilib_view_t i;
  126. pcilib_register_context_t *regctx = &ctx->register_ctx[reg];
  127. if (!regctx->views) return NULL;
  128. for (i = 0; regctx->views[i].name; i++) {
  129. if (!strcasecmp(name, regctx->views[i].name)) {
  130. return pcilib_find_view_context_by_name(ctx, regctx->views[i].view);
  131. }
  132. }
  133. return NULL;
  134. }
  135. // We expect symmetric units. Therefore, we don't distringuish if we read or write
  136. 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) {
  137. pcilib_view_t i;
  138. pcilib_view_context_t *view_ctx;
  139. pcilib_view_description_t *view_desc;
  140. pcilib_register_context_t *regctx = &ctx->register_ctx[reg];
  141. if (!regctx->views) return PCILIB_ERROR_NOTFOUND;
  142. // Check if view is just a name of listed view
  143. view_ctx = pcilib_find_register_view_context_by_name(ctx, reg, name);
  144. if (view_ctx) {
  145. if (ret_view) *ret_view = view_ctx;
  146. if (ret_trans) *ret_trans = NULL;
  147. return 0;
  148. }
  149. // Check if view is a unit
  150. for (i = 0; regctx->views[i].name; i++) {
  151. pcilib_unit_transform_t *trans;
  152. view_ctx = pcilib_find_view_context_by_name(ctx, regctx->views[i].view);
  153. if (!view_ctx) continue;
  154. view_desc = ctx->views[view_ctx->view];
  155. if (view_desc->unit) {
  156. if (write_direction)
  157. trans = pcilib_find_transform_by_unit_names(ctx, name, view_desc->unit);
  158. else
  159. trans = pcilib_find_transform_by_unit_names(ctx, view_desc->unit, name);
  160. if (trans) {
  161. if (ret_trans) *ret_trans = trans;
  162. if (ret_view) *ret_view = pcilib_find_view_context_by_name(ctx, view_desc->name);
  163. return 0;
  164. }
  165. }
  166. }
  167. return PCILIB_ERROR_NOTFOUND;
  168. }
  169. pcilib_view_context_t *pcilib_find_register_view_context(pcilib_t *ctx, pcilib_register_t reg, const char *name) {
  170. int err;
  171. pcilib_view_context_t *view;
  172. err = pcilib_detect_register_view_and_unit(ctx, reg, name, 0, &view, NULL);
  173. if (err) return NULL;
  174. return view;
  175. }
  176. typedef struct {
  177. pcilib_register_t reg;
  178. pcilib_view_context_t *view;
  179. pcilib_unit_transform_t *trans;
  180. } pcilib_view_configuration_t;
  181. static int pcilib_detect_view_configuration(pcilib_t *ctx, pcilib_register_t reg, const char *view_cname, const char *unit_cname, int write_direction, pcilib_view_configuration_t *cfg) {
  182. int err = 0;
  183. pcilib_view_t view;
  184. const char *regname;
  185. pcilib_view_context_t *view_ctx;
  186. pcilib_unit_transform_t *trans = NULL;
  187. char *view_name = alloca(strlen(view_cname) + 1);
  188. const char *unit_name;
  189. strcpy(view_name, view_cname);
  190. if (unit_cname) unit_name = unit_cname;
  191. else {
  192. unit_name = strchr(view_name, ':');
  193. if (unit_name) {
  194. *(char*)unit_name = 0;
  195. unit_name++;
  196. }
  197. }
  198. if (reg == PCILIB_REGISTER_INVALID) regname = NULL;
  199. else regname = ctx->registers[reg].name;
  200. if (regname) {
  201. if (unit_name) view_ctx = pcilib_find_register_view_context_by_name(ctx, reg, view_name);
  202. else err = pcilib_detect_register_view_and_unit(ctx, reg, view_name, write_direction, &view_ctx, &trans);
  203. if ((err)||(!view_ctx)) {
  204. pcilib_error("Can't find the specified view %s for register %s", view_name, regname);
  205. return PCILIB_ERROR_NOTFOUND;
  206. }
  207. } else {
  208. view_ctx = pcilib_find_view_context_by_name(ctx, view_name);
  209. if (!view_ctx) {
  210. pcilib_error("Can't find the specified view %s", view_name);
  211. return PCILIB_ERROR_NOTFOUND;
  212. }
  213. }
  214. view = view_ctx->view;
  215. if (unit_name) {
  216. if (write_direction) trans = pcilib_find_transform_by_unit_names(ctx, unit_name, ctx->views[view]->unit);
  217. else trans = pcilib_find_transform_by_unit_names(ctx, ctx->views[view]->unit, unit_name);
  218. if (!trans) {
  219. pcilib_error("Don't know how to get the requested unit %s for view %s", unit_name, ctx->views[view]->name);
  220. return PCILIB_ERROR_NOTFOUND;
  221. }
  222. }
  223. // No transform is required
  224. if ((trans)&&(!trans->transform)) trans = NULL;
  225. cfg->reg = reg;
  226. cfg->view = view_ctx;
  227. cfg->trans = trans;
  228. return 0;
  229. }
  230. int pcilib_read_register_view_by_id(pcilib_t *ctx, pcilib_register_t reg, const char *view, pcilib_value_t *val) {
  231. int err;
  232. const char *regname;
  233. pcilib_view_description_t *v;
  234. pcilib_view_configuration_t cfg;
  235. pcilib_register_value_t regvalue = 0;
  236. if (reg == PCILIB_REGISTER_INVALID) regname = NULL;
  237. else regname = ctx->registers[reg].name;
  238. err = pcilib_detect_view_configuration(ctx, reg, view, NULL, 0, &cfg);
  239. if (err) return err;
  240. v = ctx->views[cfg.view->view];
  241. if (!v->api->read_from_reg) {
  242. pcilib_error("The view (%s) does not support reading from the register", view);
  243. return PCILIB_ERROR_NOTSUPPORTED;
  244. }
  245. if ((v->mode & PCILIB_REGISTER_R) == 0) {
  246. pcilib_error("The view (%s) does not allow reading from the register", view);
  247. return PCILIB_ERROR_NOTPERMITED;
  248. }
  249. if (regname) {
  250. err = pcilib_read_register_by_id(ctx, cfg.reg, &regvalue);
  251. if (err) {
  252. pcilib_error("Error (%i) reading register %s", err, regname);
  253. return err;
  254. }
  255. }
  256. pcilib_clean_value(ctx, val);
  257. err = v->api->read_from_reg(ctx, cfg.view, regvalue, val);
  258. if (err) {
  259. if (regname)
  260. pcilib_error("Error (%i) computing view (%s) of register %s", err, view, regname);
  261. else
  262. pcilib_error("Error (%i) computing view %s", err, view);
  263. return err;
  264. }
  265. if (v->unit) {
  266. val->unit = v->unit;
  267. }
  268. if (cfg.trans) {
  269. err = pcilib_transform_unit(ctx, cfg.trans, val);
  270. if (err) return err;
  271. }
  272. return 0;
  273. }
  274. int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, pcilib_value_t *val) {
  275. pcilib_register_t reg;
  276. if (regname) {
  277. reg = pcilib_find_register(ctx, bank, regname);
  278. if (reg == PCILIB_REGISTER_INVALID) {
  279. pcilib_error("Register (%s) is not found", regname);
  280. return PCILIB_ERROR_NOTFOUND;
  281. }
  282. } else {
  283. reg = PCILIB_REGISTER_INVALID;
  284. }
  285. return pcilib_read_register_view_by_id(ctx, reg, view, val);
  286. }
  287. int pcilib_write_register_view_by_id(pcilib_t *ctx, pcilib_register_t reg, const char *view, const pcilib_value_t *valarg) {
  288. int err;
  289. pcilib_value_t val = {0};
  290. const char *regname;
  291. pcilib_view_description_t *v;
  292. pcilib_view_configuration_t cfg;
  293. pcilib_register_value_t regvalue = 0;
  294. if (reg == PCILIB_REGISTER_INVALID) regname = NULL;
  295. else regname = ctx->registers[reg].name;
  296. err = pcilib_detect_view_configuration(ctx, reg, view, valarg->unit, 1, &cfg);
  297. if (err) return err;
  298. v = ctx->views[cfg.view->view];
  299. if (!v->api->write_to_reg) {
  300. pcilib_error("The view (%s) does not support writting to the register", view);
  301. return PCILIB_ERROR_NOTSUPPORTED;
  302. }
  303. if ((v->mode & PCILIB_REGISTER_W) == 0) {
  304. pcilib_error("The view (%s) does not allow writting to the register", view);
  305. return PCILIB_ERROR_NOTPERMITED;
  306. }
  307. err = pcilib_copy_value(ctx, &val, valarg);
  308. if (err) return err;
  309. err = pcilib_convert_value_type(ctx, &val, v->type);
  310. if (err) {
  311. 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);
  312. return err;
  313. }
  314. if (cfg.trans) {
  315. err = pcilib_transform_unit(ctx, cfg.trans, &val);
  316. if (err) return err;
  317. }
  318. err = v->api->write_to_reg(ctx, cfg.view, &regvalue, &val);
  319. if (err) {
  320. if (regname)
  321. pcilib_error("Error (%i) computing view (%s) of register %s", err, view, regname);
  322. else
  323. pcilib_error("Error (%i) computing view %s", err, view);
  324. return err;
  325. }
  326. if (regname) {
  327. err = pcilib_write_register_by_id(ctx, cfg.reg, regvalue);
  328. if (err) {
  329. pcilib_error("Error (%i) reading register %s", err, regname);
  330. return err;
  331. }
  332. }
  333. return 0;
  334. }
  335. int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, const pcilib_value_t *val) {
  336. pcilib_register_t reg;
  337. if (regname) {
  338. reg = pcilib_find_register(ctx, bank, regname);
  339. if (reg == PCILIB_REGISTER_INVALID) {
  340. pcilib_error("Register (%s) is not found", regname);
  341. return PCILIB_ERROR_NOTFOUND;
  342. }
  343. } else {
  344. reg = PCILIB_REGISTER_INVALID;
  345. }
  346. return pcilib_write_register_view_by_id(ctx, reg, view, val);
  347. }