123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #include "impl/sysfs.h"
  2. #include "light.h"
  3. #include "helpers.h"
  4. #include <stdio.h> //snprintf
  5. #include <stdlib.h> // malloc, free
  6. #include <dirent.h> // opendir, readdir
  7. static bool _impl_sysfs_init_leds(light_device_enumerator_t *enumerator)
  8. {
  9. // Create a new backlight device
  10. light_device_t *leds_device = malloc(sizeof(light_device_t));
  11. snprintf(leds_device->name, sizeof(leds_device->name), "%s", "leds");
  12. // Add it to the enumerator
  13. light_add_enumerator_device(enumerator, leds_device);
  14. // Iterate through the led controllers and create a device_target for each controller
  15. DIR *leds_dir;
  16. struct dirent *curr_entry;
  17. if((leds_dir = opendir("/sys/class/leds")) == NULL)
  18. {
  19. LIGHT_ERR("failed to open leds controller directory for reading");
  20. return false;
  21. }
  22. while((curr_entry = readdir(leds_dir)) != NULL)
  23. {
  24. // Skip dot entries
  25. if(curr_entry->d_name[0] == '.')
  26. {
  27. continue;
  28. }
  29. // Create a new device target for the controller
  30. light_device_target_t *led_controller = malloc(sizeof(light_device_target_t));
  31. snprintf(led_controller->name, sizeof(led_controller->name), "%s", curr_entry->d_name);
  32. // Setup the function bindings
  33. led_controller->set_value = impl_sysfs_set;
  34. led_controller->get_value = impl_sysfs_get;
  35. led_controller->get_max_value = impl_sysfs_getmax;
  36. led_controller->custom_command = impl_sysfs_command;
  37. // Setup the target data
  38. impl_sysfs_data_t *dev_data = malloc(sizeof(impl_sysfs_data_t));
  39. led_controller->device_target_data = dev_data;
  40. snprintf(dev_data->brightness, sizeof(dev_data->brightness), "/sys/class/leds/%s/brightness", curr_entry->d_name);
  41. snprintf(dev_data->max_brightness, sizeof(dev_data->max_brightness), "/sys/class/leds/%s/max_brightness", curr_entry->d_name);
  42. // Add it to the device
  43. light_add_device_target(leds_device, led_controller);
  44. }
  45. return true;
  46. }
  47. static bool _impl_sysfs_init_backlight(light_device_enumerator_t *enumerator)
  48. {
  49. // Create a new backlight device
  50. light_device_t *backlight_device = malloc(sizeof(light_device_t));
  51. snprintf(backlight_device->name, sizeof(backlight_device->name), "%s", "backlight");
  52. // Add it to the enumerator
  53. light_add_enumerator_device(enumerator, backlight_device);
  54. // Iterate through the backlight controllers and create a device_target for each controller
  55. DIR *backlight_dir;
  56. struct dirent *curr_entry;
  57. // Keep track of the best controller, and create an autodevice from that
  58. char best_controller[NAME_MAX];
  59. uint64_t best_value = 0;
  60. if((backlight_dir = opendir("/sys/class/backlight")) == NULL)
  61. {
  62. LIGHT_ERR("failed to open backlight controller directory for reading");
  63. return false;
  64. }
  65. while((curr_entry = readdir(backlight_dir)) != NULL)
  66. {
  67. // Skip dot entries
  68. if(curr_entry->d_name[0] == '.')
  69. {
  70. continue;
  71. }
  72. // Create a new device target for the controller
  73. light_device_target_t *backlight_controller = malloc(sizeof(light_device_target_t));
  74. snprintf(backlight_controller->name, sizeof(backlight_controller->name), "%s", curr_entry->d_name);
  75. // Setup the function bindings
  76. backlight_controller->set_value = impl_sysfs_set;
  77. backlight_controller->get_value = impl_sysfs_get;
  78. backlight_controller->get_max_value = impl_sysfs_getmax;
  79. backlight_controller->custom_command = impl_sysfs_command;
  80. // Setup the target data
  81. impl_sysfs_data_t *dev_data = malloc(sizeof(impl_sysfs_data_t));
  82. backlight_controller->device_target_data = dev_data;
  83. snprintf(dev_data->brightness, sizeof(dev_data->brightness), "/sys/class/backlight/%s/brightness", curr_entry->d_name);
  84. snprintf(dev_data->max_brightness, sizeof(dev_data->max_brightness), "/sys/class/backlight/%s/max_brightness", curr_entry->d_name);
  85. // Read the max brightness to get the best one
  86. uint64_t curr_value = 0;
  87. if(light_file_read_uint64(dev_data->max_brightness, &curr_value))
  88. {
  89. if(curr_value > best_value)
  90. {
  91. best_value = curr_value;
  92. snprintf(best_controller, sizeof(best_controller), "%s", backlight_controller->name);
  93. }
  94. }
  95. // Add it to the device
  96. light_add_device_target(backlight_device, backlight_controller);
  97. }
  98. // Create an auto controller
  99. light_device_target_t *auto_controller = malloc(sizeof(light_device_target_t));
  100. snprintf(auto_controller->name, sizeof(auto_controller->name), "%s", "auto");
  101. // Setup the function bindings
  102. auto_controller->set_value = impl_sysfs_set;
  103. auto_controller->get_value = impl_sysfs_get;
  104. auto_controller->get_max_value = impl_sysfs_getmax;
  105. auto_controller->custom_command = impl_sysfs_command;
  106. // Setup the target data
  107. impl_sysfs_data_t *dev_data = malloc(sizeof(impl_sysfs_data_t));
  108. auto_controller->device_target_data = dev_data;
  109. snprintf(dev_data->brightness, sizeof(dev_data->brightness), "/sys/class/backlight/%s/brightness", best_controller);
  110. snprintf(dev_data->max_brightness, sizeof(dev_data->max_brightness), "/sys/class/backlight/%s/max_brightness", best_controller);
  111. // Add it to the device
  112. light_add_device_target(backlight_device, auto_controller);
  113. return true;
  114. }
  115. bool impl_sysfs_init(light_device_enumerator_t *enumerator)
  116. {
  117. // Create a device for the backlight
  118. _impl_sysfs_init_backlight(enumerator);
  119. // Create devices for the leds
  120. _impl_sysfs_init_leds(enumerator);
  121. return true;
  122. }
  123. bool impl_sysfs_free(light_device_enumerator_t *enumerator)
  124. {
  125. // Iterate through the devices in the enumerator
  126. for(uint64_t d = 0; d < enumerator->num_devices; d++)
  127. {
  128. light_device_t *curr_device = enumerator->devices[d];
  129. // If the given device points to NULL, we can safely skip it
  130. if(curr_device == NULL)
  131. {
  132. continue;
  133. }
  134. // If the given device has a targets array that isnt NULL, iterate through it to free the targets, then free the array
  135. if(curr_device->targets != NULL)
  136. {
  137. for(uint64_t t = 0; t < curr_device->num_targets; t++)
  138. {
  139. light_device_target_t *curr_target = curr_device->targets[t];
  140. if(curr_target == NULL)
  141. {
  142. continue;
  143. }
  144. if(curr_target->device_target_data != NULL)
  145. {
  146. free(curr_target->device_target_data);
  147. }
  148. free(curr_target);
  149. }
  150. free(curr_device->targets);
  151. }
  152. // If the given device has any device_data, free it
  153. if(curr_device->device_data != NULL)
  154. {
  155. free(curr_device->device_data);
  156. }
  157. // Free the device
  158. free(curr_device);
  159. }
  160. // Free the devices array
  161. free(enumerator->devices);
  162. enumerator->devices = NULL;
  163. enumerator->num_devices = 0;
  164. return true;
  165. }
  166. bool impl_sysfs_set(light_device_target_t *target, uint64_t in_value)
  167. {
  168. impl_sysfs_data_t *data = (impl_sysfs_data_t*)target->device_target_data;
  169. if(!light_file_write_uint64(data->brightness, in_value))
  170. {
  171. LIGHT_ERR("failed to write to sysfs device");
  172. return false;
  173. }
  174. return true;
  175. }
  176. bool impl_sysfs_get(light_device_target_t *target, uint64_t *out_value)
  177. {
  178. impl_sysfs_data_t *data = (impl_sysfs_data_t*)target->device_target_data;
  179. if(!light_file_read_uint64(data->brightness, out_value))
  180. {
  181. LIGHT_ERR("failed to read from sysfs device");
  182. return false;
  183. }
  184. return true;
  185. }
  186. bool impl_sysfs_getmax(light_device_target_t *target, uint64_t *out_value)
  187. {
  188. impl_sysfs_data_t *data = (impl_sysfs_data_t*)target->device_target_data;
  189. if(!light_file_read_uint64(data->max_brightness, out_value))
  190. {
  191. LIGHT_ERR("failed to read from sysfs device");
  192. return false;
  193. }
  194. return true;
  195. }
  196. bool impl_sysfs_command(light_device_target_t *target, char const *command_string)
  197. {
  198. // No current need for custom commands in sysfs enumerator
  199. // To implement support, simply parse the command string to your liking, and return false on invalid input or results!
  200. return true;
  201. }