acpi_configfs.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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. static struct config_group *acpi_table_group;
  16. struct acpi_table {
  17. struct config_item cfg;
  18. struct acpi_table_header *header;
  19. };
  20. static ssize_t acpi_table_aml_write(struct config_item *cfg,
  21. const void *data, size_t size)
  22. {
  23. const struct acpi_table_header *header = data;
  24. struct acpi_table *table;
  25. int ret;
  26. table = container_of(cfg, struct acpi_table, cfg);
  27. if (table->header) {
  28. pr_err("table already loaded\n");
  29. return -EBUSY;
  30. }
  31. if (header->length != size) {
  32. pr_err("invalid table length\n");
  33. return -EINVAL;
  34. }
  35. if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) {
  36. pr_err("invalid table signature\n");
  37. return -EINVAL;
  38. }
  39. table = container_of(cfg, struct acpi_table, cfg);
  40. table->header = kmemdup(header, header->length, GFP_KERNEL);
  41. if (!table->header)
  42. return -ENOMEM;
  43. ret = acpi_load_table(table->header);
  44. if (ret) {
  45. kfree(table->header);
  46. table->header = NULL;
  47. }
  48. return ret;
  49. }
  50. static inline struct acpi_table_header *get_header(struct config_item *cfg)
  51. {
  52. struct acpi_table *table = container_of(cfg, struct acpi_table, cfg);
  53. if (!table->header)
  54. pr_err("table not loaded\n");
  55. return table->header;
  56. }
  57. static ssize_t acpi_table_aml_read(struct config_item *cfg,
  58. void *data, size_t size)
  59. {
  60. struct acpi_table_header *h = get_header(cfg);
  61. if (!h)
  62. return -EINVAL;
  63. if (data)
  64. memcpy(data, h, h->length);
  65. return h->length;
  66. }
  67. #define MAX_ACPI_TABLE_SIZE (128 * 1024)
  68. CONFIGFS_BIN_ATTR(acpi_table_, aml, NULL, MAX_ACPI_TABLE_SIZE);
  69. struct configfs_bin_attribute *acpi_table_bin_attrs[] = {
  70. &acpi_table_attr_aml,
  71. NULL,
  72. };
  73. ssize_t acpi_table_signature_show(struct config_item *cfg, char *str)
  74. {
  75. struct acpi_table_header *h = get_header(cfg);
  76. if (!h)
  77. return -EINVAL;
  78. return sprintf(str, "%.*s\n", ACPI_NAME_SIZE, h->signature);
  79. }
  80. ssize_t acpi_table_length_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, "%d\n", h->length);
  86. }
  87. ssize_t acpi_table_revision_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->revision);
  93. }
  94. ssize_t acpi_table_oem_id_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, "%.*s\n", ACPI_OEM_ID_SIZE, h->oem_id);
  100. }
  101. ssize_t acpi_table_oem_table_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_TABLE_ID_SIZE, h->oem_table_id);
  107. }
  108. ssize_t acpi_table_oem_revision_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, "%d\n", h->oem_revision);
  114. }
  115. ssize_t acpi_table_asl_compiler_id_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, "%.*s\n", ACPI_NAME_SIZE, h->asl_compiler_id);
  121. }
  122. ssize_t acpi_table_asl_compiler_revision_show(struct config_item *cfg,
  123. char *str)
  124. {
  125. struct acpi_table_header *h = get_header(cfg);
  126. if (!h)
  127. return -EINVAL;
  128. return sprintf(str, "%d\n", h->asl_compiler_revision);
  129. }
  130. CONFIGFS_ATTR_RO(acpi_table_, signature);
  131. CONFIGFS_ATTR_RO(acpi_table_, length);
  132. CONFIGFS_ATTR_RO(acpi_table_, revision);
  133. CONFIGFS_ATTR_RO(acpi_table_, oem_id);
  134. CONFIGFS_ATTR_RO(acpi_table_, oem_table_id);
  135. CONFIGFS_ATTR_RO(acpi_table_, oem_revision);
  136. CONFIGFS_ATTR_RO(acpi_table_, asl_compiler_id);
  137. CONFIGFS_ATTR_RO(acpi_table_, asl_compiler_revision);
  138. struct configfs_attribute *acpi_table_attrs[] = {
  139. &acpi_table_attr_signature,
  140. &acpi_table_attr_length,
  141. &acpi_table_attr_revision,
  142. &acpi_table_attr_oem_id,
  143. &acpi_table_attr_oem_table_id,
  144. &acpi_table_attr_oem_revision,
  145. &acpi_table_attr_asl_compiler_id,
  146. &acpi_table_attr_asl_compiler_revision,
  147. NULL,
  148. };
  149. static struct config_item_type acpi_table_type = {
  150. .ct_owner = THIS_MODULE,
  151. .ct_bin_attrs = acpi_table_bin_attrs,
  152. .ct_attrs = acpi_table_attrs,
  153. };
  154. static struct config_item *acpi_table_make_item(struct config_group *group,
  155. const char *name)
  156. {
  157. struct acpi_table *table;
  158. table = kzalloc(sizeof(*table), GFP_KERNEL);
  159. if (!table)
  160. return ERR_PTR(-ENOMEM);
  161. config_item_init_type_name(&table->cfg, name, &acpi_table_type);
  162. return &table->cfg;
  163. }
  164. struct configfs_group_operations acpi_table_group_ops = {
  165. .make_item = acpi_table_make_item,
  166. };
  167. static struct config_item_type acpi_tables_type = {
  168. .ct_owner = THIS_MODULE,
  169. .ct_group_ops = &acpi_table_group_ops,
  170. };
  171. static struct config_item_type acpi_root_group_type = {
  172. .ct_owner = THIS_MODULE,
  173. };
  174. static struct configfs_subsystem acpi_configfs = {
  175. .su_group = {
  176. .cg_item = {
  177. .ci_namebuf = "acpi",
  178. .ci_type = &acpi_root_group_type,
  179. },
  180. },
  181. .su_mutex = __MUTEX_INITIALIZER(acpi_configfs.su_mutex),
  182. };
  183. static int __init acpi_configfs_init(void)
  184. {
  185. int ret;
  186. struct config_group *root = &acpi_configfs.su_group;
  187. config_group_init(root);
  188. ret = configfs_register_subsystem(&acpi_configfs);
  189. if (ret)
  190. return ret;
  191. acpi_table_group = configfs_register_default_group(root, "table",
  192. &acpi_tables_type);
  193. return PTR_ERR_OR_ZERO(acpi_table_group);
  194. }
  195. module_init(acpi_configfs_init);
  196. static void __exit acpi_configfs_exit(void)
  197. {
  198. configfs_unregister_default_group(acpi_table_group);
  199. configfs_unregister_subsystem(&acpi_configfs);
  200. }
  201. module_exit(acpi_configfs_exit);
  202. MODULE_AUTHOR("Octavian Purdila <octavian.purdila@intel.com>");
  203. MODULE_DESCRIPTION("ACPI configfs support");
  204. MODULE_LICENSE("GPL v2");