0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/acpi.h>
0012 #include <linux/adxl.h>
0013
0014 #define ADXL_REVISION 0x1
0015 #define ADXL_IDX_GET_ADDR_PARAMS 0x1
0016 #define ADXL_IDX_FORWARD_TRANSLATE 0x2
0017 #define ACPI_ADXL_PATH "\\_SB.ADXL"
0018
0019
0020
0021
0022
0023
0024
0025 #define ADXL_MAX_COMPONENTS 500
0026
0027 #undef pr_fmt
0028 #define pr_fmt(fmt) "ADXL: " fmt
0029
0030 static acpi_handle handle;
0031 static union acpi_object *params;
0032 static const guid_t adxl_guid =
0033 GUID_INIT(0xAA3C050A, 0x7EA4, 0x4C1F,
0034 0xAF, 0xDA, 0x12, 0x67, 0xDF, 0xD3, 0xD4, 0x8D);
0035
0036 static int adxl_count;
0037 static char **adxl_component_names;
0038
0039 static union acpi_object *adxl_dsm(int cmd, union acpi_object argv[])
0040 {
0041 union acpi_object *obj, *o;
0042
0043 obj = acpi_evaluate_dsm_typed(handle, &adxl_guid, ADXL_REVISION,
0044 cmd, argv, ACPI_TYPE_PACKAGE);
0045 if (!obj) {
0046 pr_info("DSM call failed for cmd=%d\n", cmd);
0047 return NULL;
0048 }
0049
0050 if (obj->package.count != 2) {
0051 pr_info("Bad pkg count %d\n", obj->package.count);
0052 goto err;
0053 }
0054
0055 o = obj->package.elements;
0056 if (o->type != ACPI_TYPE_INTEGER) {
0057 pr_info("Bad 1st element type %d\n", o->type);
0058 goto err;
0059 }
0060 if (o->integer.value) {
0061 pr_info("Bad ret val %llu\n", o->integer.value);
0062 goto err;
0063 }
0064
0065 o = obj->package.elements + 1;
0066 if (o->type != ACPI_TYPE_PACKAGE) {
0067 pr_info("Bad 2nd element type %d\n", o->type);
0068 goto err;
0069 }
0070 return obj;
0071
0072 err:
0073 ACPI_FREE(obj);
0074 return NULL;
0075 }
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 const char * const *adxl_get_component_names(void)
0087 {
0088 return (const char * const *)adxl_component_names;
0089 }
0090 EXPORT_SYMBOL_GPL(adxl_get_component_names);
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 int adxl_decode(u64 addr, u64 component_values[])
0104 {
0105 union acpi_object argv4[2], *results, *r;
0106 int i, cnt;
0107
0108 if (!adxl_component_names)
0109 return -EOPNOTSUPP;
0110
0111 argv4[0].type = ACPI_TYPE_PACKAGE;
0112 argv4[0].package.count = 1;
0113 argv4[0].package.elements = &argv4[1];
0114 argv4[1].integer.type = ACPI_TYPE_INTEGER;
0115 argv4[1].integer.value = addr;
0116
0117 results = adxl_dsm(ADXL_IDX_FORWARD_TRANSLATE, argv4);
0118 if (!results)
0119 return -EINVAL;
0120
0121 r = results->package.elements + 1;
0122 cnt = r->package.count;
0123 if (cnt != adxl_count) {
0124 ACPI_FREE(results);
0125 return -EINVAL;
0126 }
0127 r = r->package.elements;
0128
0129 for (i = 0; i < cnt; i++)
0130 component_values[i] = r[i].integer.value;
0131
0132 ACPI_FREE(results);
0133
0134 return 0;
0135 }
0136 EXPORT_SYMBOL_GPL(adxl_decode);
0137
0138 static int __init adxl_init(void)
0139 {
0140 char *path = ACPI_ADXL_PATH;
0141 union acpi_object *p;
0142 acpi_status status;
0143 int i;
0144
0145 status = acpi_get_handle(NULL, path, &handle);
0146 if (ACPI_FAILURE(status)) {
0147 pr_debug("No ACPI handle for path %s\n", path);
0148 return -ENODEV;
0149 }
0150
0151 if (!acpi_has_method(handle, "_DSM")) {
0152 pr_info("No DSM method\n");
0153 return -ENODEV;
0154 }
0155
0156 if (!acpi_check_dsm(handle, &adxl_guid, ADXL_REVISION,
0157 ADXL_IDX_GET_ADDR_PARAMS |
0158 ADXL_IDX_FORWARD_TRANSLATE)) {
0159 pr_info("DSM method does not support forward translate\n");
0160 return -ENODEV;
0161 }
0162
0163 params = adxl_dsm(ADXL_IDX_GET_ADDR_PARAMS, NULL);
0164 if (!params) {
0165 pr_info("Failed to get component names\n");
0166 return -ENODEV;
0167 }
0168
0169 p = params->package.elements + 1;
0170 adxl_count = p->package.count;
0171 if (adxl_count > ADXL_MAX_COMPONENTS) {
0172 pr_info("Insane number of address component names %d\n", adxl_count);
0173 ACPI_FREE(params);
0174 return -ENODEV;
0175 }
0176 p = p->package.elements;
0177
0178
0179
0180
0181 adxl_component_names = kcalloc(adxl_count + 1, sizeof(char *), GFP_KERNEL);
0182 if (!adxl_component_names) {
0183 ACPI_FREE(params);
0184 return -ENOMEM;
0185 }
0186
0187 for (i = 0; i < adxl_count; i++)
0188 adxl_component_names[i] = p[i].string.pointer;
0189
0190 return 0;
0191 }
0192 subsys_initcall(adxl_init);