acpi_configfs.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * ACPI configfs support
  3. *
  4. * Copyright (c) 2016 Intel Corporation
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published by
  8. * the Free Software Foundation.
  9. */
  10. #define pr_fmt(fmt) "ACPI configfs: " fmt
  11. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/configfs.h>
  14. #include <linux/acpi.h>
  15. #include "acpica/accommon.h"
  16. #include "acpica/actables.h"
  17. static struct config_group *acpi_table_group;
  18. struct acpi_table {
  19. struct config_item cfg;
  20. struct acpi_table_header *header;
  21. u32 index;
  22. };
  23. static ssize_t acpi_table_aml_write(struct config_item *cfg,
  24. const void *data, size_t size)
  25. {
  26. const struct acpi_table_header *header = data;
  27. struct acpi_table *table;
  28. int ret;
  29. table = container_of(cfg, struct acpi_table, cfg);
  30. if (table->header) {
  31. pr_err("table already loaded\n");
  32. return -EBUSY;
  33. }
  34. if (header->length != size) {
  35. pr_err("invalid table length\n");
  36. return -EINVAL;
  37. }
  38. if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) {
  39. pr_err("invalid table signature\n");
  40. return -EINVAL;
  41. }
  42. table = container_of(cfg, struct acpi_table, cfg);
  43. table->header = kmemdup(header, header->length, GFP_KERNEL);
  44. if (!table->header)
  45. return -ENOMEM;
  46. ACPI_INFO(("Host-directed Dynamic ACPI Table Load:"));
  47. ret = acpi_tb_install_and_load_table(
  48. ACPI_PTR_TO_PHYSADDR(table->header),
  49. ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, FALSE,
  50. &table->index);
  51. if (ret) {
  52. kfree(table->header);
  53. table->header = NULL;
  54. }
  55. return ret;
  56. }
  57. static inline struct acpi_table_header *get_header(struct config_item *cfg)
  58. {
  59. struct acpi_table *table = container_of(cfg, struct acpi_table, cfg);
  60. if (!table->header)
  61. pr_err("table not loaded\n");
  62. return table->header;
  63. }
  64. static ssize_t acpi_table_aml_read(struct config_item *cfg,
  65. void *data, size_t size)
  66. {
  67. struct acpi_table_header *h = get_header(cfg);
  68. if (!h)
  69. return -EINVAL;
  70. if (data)
  71. memcpy(data, h, h->length);
  72. return h->length;
  73. }
  74. #define MAX_ACPI_TABLE_SIZE (128 * 1024)
  75. CONFIGFS_BIN_ATTR(acpi_table_, aml, NULL, MAX_ACPI_TABLE_SIZE);
  76. struct configfs_bin_attribute *acpi_table_bin_attrs[] = {
  77. &acpi_table_attr_aml,
  78. NULL,
  79. };
  80. ssize_t acpi_table_signature_show(struct config_item *cfg, char *str)
  81. {
  82. struct acpi_table_header *h = get_header(cfg);
  83. if (!h)
  84. return -EINVAL;
  85. return sprintf(str, "%.*s\n", ACPI_NAME_SIZE, h->signature);
  86. }
  87. ssize_t acpi_table_length_show(struct config_item *cfg, char *str)
  88. {
  89. struct acpi_table_header *h = get_header(cfg);
  90. if (!h)
  91. return -EINVAL;
  92. return sprintf(str, "%d\n", h->length);
  93. }
  94. ssize_t acpi_table_revision_show(struct config_item *cfg, char *str)
  95. {
  96. struct acpi_table_header *h = get_header(cfg);
  97. if (!h)
  98. return -EINVAL;
  99. return sprintf(str, "%d\n", h->revision);
  100. }
  101. ssize_t acpi_table_oem_id_show(struct config_item *cfg, char *str)
  102. {
  103. struct acpi_table_header *h = get_header(cfg);
  104. if (!h)
  105. return -EINVAL;
  106. return sprintf(str, "%.*s\n", ACPI_OEM_ID_SIZE, h->oem_id);
  107. }
  108. ssize_t acpi_table_oem_table_id_show(struct config_item *cfg, char *str)
  109. {
  110. struct acpi_table_header *h = get_header(cfg);
  111. if (!h)
  112. return -EINVAL;
  113. return sprintf(str, "%.*s\n", ACPI_OEM_TABLE_ID_SIZE, h->oem_table_id);
  114. }
  115. ssize_t acpi_table_oem_revision_show(struct config_item *cfg, char *str)
  116. {
  117. struct acpi_table_header *h = get_header(cfg);
  118. if (!h)
  119. return -EINVAL;
  120. return sprintf(str, "%d\n", h->oem_revision);
  121. }
  122. ssize_t acpi_table_asl_compiler_id_show(struct config_item *cfg, char *str)
  123. {
  124. struct acpi_table_header *h = get_header(cfg);
  125. if (!h)
  126. return -EINVAL;
  127. return sprintf(str, "%.*s\n", ACPI_NAME_SIZE, h->asl_compiler_id);
  128. }
  129. ssize_t acpi_table_asl_compiler_revision_show(struct config_item *cfg,
  130. char *str)
  131. {
  132. struct acpi_table_header *h = get_header(cfg);
  133. if (!h)
  134. return -EINVAL;
  135. return sprintf(str, "%d\n", h->asl_compiler_revision);
  136. }
  137. CONFIGFS_ATTR_RO(acpi_table_, signature);
  138. CONFIGFS_ATTR_RO(acpi_table_, length);
  139. CONFIGFS_ATTR_RO(acpi_table_, revision);
  140. CONFIGFS_ATTR_RO(acpi_table_, oem_id);
  141. CONFIGFS_ATTR_RO(acpi_table_, oem_table_id);
  142. CONFIGFS_ATTR_RO(acpi_table_, oem_revision);
  143. CONFIGFS_ATTR_RO(acpi_table_, asl_compiler_id);
  144. CONFIGFS_ATTR_RO(acpi_table_, asl_compiler_revision);
  145. struct configfs_attribute *acpi_table_attrs[] = {
  146. &acpi_table_attr_signature,
  147. &acpi_table_attr_length,
  148. &acpi_table_attr_revision,
  149. &acpi_table_attr_oem_id,
  150. &acpi_table_attr_oem_table_id,
  151. &acpi_table_attr_oem_revision,
  152. &acpi_table_attr_asl_compiler_id,
  153. &acpi_table_attr_asl_compiler_revision,
  154. NULL,
  155. };
  156. static const struct config_item_type acpi_table_type = {
  157. .ct_owner = THIS_MODULE,
  158. .ct_bin_attrs = acpi_table_bin_attrs,
  159. .ct_attrs = acpi_table_attrs,
  160. };
  161. static struct config_item *acpi_table_make_item(struct config_group *group,
  162. const char *name)
  163. {
  164. struct acpi_table *table;
  165. table = kzalloc(sizeof(*table), GFP_KERNEL);
  166. if (!table)
  167. return ERR_PTR(-ENOMEM);
  168. config_item_init_type_name(&table->cfg, name, &acpi_table_type);
  169. return &table->cfg;
  170. }
  171. static void acpi_table_drop_item(struct config_group *group,
  172. struct config_item *cfg)
  173. {
  174. struct acpi_table *table = container_of(cfg, struct acpi_table, cfg);
  175. ACPI_INFO(("Host-directed Dynamic ACPI Table Unload"));
  176. acpi_tb_unload_table(table->index);
  177. }
  178. struct configfs_group_operations acpi_table_group_ops = {
  179. .make_item = acpi_table_make_item,
  180. .drop_item = acpi_table_drop_item,
  181. };
  182. static const struct config_item_type acpi_tables_type = {
  183. .ct_owner = THIS_MODULE,
  184. .ct_group_ops = &acpi_table_group_ops,
  185. };
  186. static const struct config_item_type acpi_root_group_type = {
  187. .ct_owner = THIS_MODULE,
  188. };
  189. static struct configfs_subsystem acpi_configfs = {
  190. .su_group = {
  191. .cg_item = {
  192. .ci_namebuf = "acpi",
  193. .ci_type = &acpi_root_group_type,
  194. },
  195. },
  196. .su_mutex = __MUTEX_INITIALIZER(acpi_configfs.su_mutex),
  197. };
  198. static int __init acpi_configfs_init(void)
  199. {
  200. int ret;
  201. struct config_group *root = &acpi_configfs.su_group;
  202. config_group_init(root);
  203. ret = configfs_register_subsystem(&acpi_configfs);
  204. if (ret)
  205. return ret;
  206. acpi_table_group = configfs_register_default_group(root, "table",
  207. &acpi_tables_type);
  208. if (IS_ERR(acpi_table_group)) {
  209. configfs_unregister_subsystem(&acpi_configfs);
  210. return PTR_ERR(acpi_table_group);
  211. }
  212. return 0;
  213. }
  214. module_init(acpi_configfs_init);
  215. static void __exit acpi_configfs_exit(void)
  216. {
  217. configfs_unregister_default_group(acpi_table_group);
  218. configfs_unregister_subsystem(&acpi_configfs);
  219. }
  220. module_exit(acpi_configfs_exit);
  221. MODULE_AUTHOR("Octavian Purdila <octavian.purdila@intel.com>");
  222. MODULE_DESCRIPTION("ACPI configfs support");
  223. MODULE_LICENSE("GPL v2");