lowlevel.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * Copyright 2012-2013 Luke Dashjr
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the Free
  6. * Software Foundation; either version 3 of the License, or (at your option)
  7. * any later version. See COPYING for more details.
  8. */
  9. #include "config.h"
  10. #include <stdint.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <utlist.h>
  14. #include "logging.h"
  15. #include "lowlevel.h"
  16. static struct lowlevel_device_info *devinfo_list;
  17. void lowlevel_devinfo_semicpy(struct lowlevel_device_info * const dst, const struct lowlevel_device_info * const src)
  18. {
  19. #define COPYSTR(key) BFGINIT(dst->key, maybe_strdup(src->key))
  20. COPYSTR(manufacturer);
  21. COPYSTR(product);
  22. COPYSTR(serial);
  23. COPYSTR(path);
  24. COPYSTR(devid);
  25. BFGINIT(dst->vid, src->vid);
  26. BFGINIT(dst->pid, src->pid);
  27. }
  28. void lowlevel_devinfo_free(struct lowlevel_device_info * const info)
  29. {
  30. if (info->ref--)
  31. return;
  32. if (info->lowl->devinfo_free)
  33. info->lowl->devinfo_free(info);
  34. free(info->manufacturer);
  35. free(info->product);
  36. free(info->serial);
  37. free(info->path);
  38. free(info->devid);
  39. free(info);
  40. }
  41. struct lowlevel_device_info *lowlevel_ref(const struct lowlevel_device_info * const cinfo)
  42. {
  43. struct lowlevel_device_info * const info = (void*)cinfo;
  44. ++info->ref;
  45. return info;
  46. }
  47. void lowlevel_scan_free()
  48. {
  49. if (!devinfo_list)
  50. return;
  51. struct lowlevel_device_info *info, *tmp;
  52. struct lowlevel_device_info *info2, *tmp2;
  53. LL_FOREACH_SAFE(devinfo_list, info, tmp)
  54. {
  55. LL_DELETE(devinfo_list, info);
  56. LL_FOREACH_SAFE2(info, info2, tmp2, same_devid_next)
  57. {
  58. LL_DELETE(info, info2);
  59. lowlevel_devinfo_free(info2);
  60. }
  61. }
  62. }
  63. struct lowlevel_device_info *lowlevel_scan()
  64. {
  65. struct lowlevel_device_info *devinfo_mid_list;
  66. lowlevel_scan_free();
  67. #ifdef HAVE_LIBUSB
  68. devinfo_mid_list = lowl_usb.devinfo_scan();
  69. LL_CONCAT(devinfo_list, devinfo_mid_list);
  70. #endif
  71. #ifdef USE_X6500
  72. devinfo_mid_list = lowl_ft232r.devinfo_scan();
  73. LL_CONCAT(devinfo_list, devinfo_mid_list);
  74. #endif
  75. #ifdef NEED_BFG_LOWL_HID
  76. devinfo_mid_list = lowl_hid.devinfo_scan();
  77. LL_CONCAT(devinfo_list, devinfo_mid_list);
  78. #endif
  79. #ifdef USE_NANOFURY
  80. devinfo_mid_list = lowl_mcp2210.devinfo_scan();
  81. LL_CONCAT(devinfo_list, devinfo_mid_list);
  82. #endif
  83. #ifdef HAVE_FPGAUTILS
  84. devinfo_mid_list = lowl_vcom.devinfo_scan();
  85. LL_CONCAT(devinfo_list, devinfo_mid_list);
  86. #endif
  87. struct lowlevel_device_info *devinfo_same_prev_ht = NULL, *devinfo_same_list;
  88. LL_FOREACH(devinfo_list, devinfo_mid_list)
  89. {
  90. // Check for devid overlapping, and build a secondary linked list for them, only including the devid in the main list once (high level to low level)
  91. HASH_FIND_STR(devinfo_same_prev_ht, devinfo_mid_list->devid, devinfo_same_list);
  92. if (devinfo_same_list)
  93. {
  94. HASH_DEL(devinfo_same_prev_ht, devinfo_same_list);
  95. LL_DELETE(devinfo_list, devinfo_same_list);
  96. }
  97. LL_PREPEND2(devinfo_same_list, devinfo_mid_list, same_devid_next);
  98. HASH_ADD_KEYPTR(hh, devinfo_same_prev_ht, devinfo_mid_list->devid, strlen(devinfo_mid_list->devid), devinfo_same_list);
  99. applog(LOG_DEBUG, "%s: Found %s device at %s (path=%s, vid=%04x, pid=%04x, manuf=%s, prod=%s, serial=%s)",
  100. __func__,
  101. devinfo_mid_list->lowl->dname,
  102. devinfo_mid_list->devid,
  103. devinfo_mid_list->path,
  104. (unsigned)devinfo_mid_list->vid, (unsigned)devinfo_mid_list->pid,
  105. devinfo_mid_list->manufacturer, devinfo_mid_list->product, devinfo_mid_list->serial);
  106. }
  107. return devinfo_list;
  108. }
  109. bool _lowlevel_match_product(const struct lowlevel_device_info * const info, const char ** const needles)
  110. {
  111. if (!info->product)
  112. return false;
  113. for (int i = 0; needles[i]; ++i)
  114. if (!strstr(info->product, needles[i]))
  115. return false;
  116. return true;
  117. }
  118. bool lowlevel_match_id(const struct lowlevel_device_info * const info, const struct lowlevel_driver * const lowl, const int32_t vid, const int32_t pid)
  119. {
  120. if (info->lowl != lowl)
  121. return false;
  122. if (vid != -1 && vid != info->vid)
  123. return false;
  124. if (pid != -1 && pid != info->pid)
  125. return false;
  126. return true;
  127. }
  128. #define DETECT_BEGIN \
  129. struct lowlevel_device_info *info, *tmp; \
  130. int found = 0; \
  131. \
  132. LL_FOREACH_SAFE(devinfo_list, info, tmp) \
  133. { \
  134. // END DETECT_BEGIN
  135. #define DETECT_END \
  136. if (!cb(info, userp)) \
  137. continue; \
  138. LL_DELETE(devinfo_list, info); \
  139. ++found; \
  140. } \
  141. return found; \
  142. // END DETECT_END
  143. int _lowlevel_detect(lowl_found_devinfo_func_t cb, const char *serial, const char **product_needles, void * const userp)
  144. {
  145. DETECT_BEGIN
  146. if (serial && ((!info->serial) || strcmp(serial, info->serial)))
  147. continue;
  148. if (product_needles[0] && !_lowlevel_match_product(info, product_needles))
  149. continue;
  150. DETECT_END
  151. }
  152. int lowlevel_detect_id(const lowl_found_devinfo_func_t cb, void * const userp, const struct lowlevel_driver * const lowl, const int32_t vid, const int32_t pid)
  153. {
  154. DETECT_BEGIN
  155. if (!lowlevel_match_id(info, lowl, vid, pid))
  156. continue;
  157. DETECT_END
  158. }