--- drivers/platform/x86/Kconfig | 12 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel-sar.c | 589 ++++++++++++++++++++ include/linux/platform_data/x86/intel-sar.h | 118 ++++ 4 files changed, 720 insertions(+) create mode 100644 drivers/platform/x86/intel-sar.c create mode 100644 include/linux/platform_data/x86/intel-sar.h diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 60592fb88e7a..6dfa89310677 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1313,6 +1313,18 @@ config INTEL_TELEMETRY directly via debugfs files. Various tools may use this interface for SoC state monitoring. +config INTEL_SAR + tristate "Intel Specific Absorption Rate Driver" + depends on ACPI + help + This driver limit the exposure of human body to RF frequency by informing + the Intel M.2 modem to regulate the RF power based on SAR data obtained + from the sensorscaptured in the BIOS. ACPI interface exposes this data + from the BIOS to SAR driver. The front end application in userspace + will interact with SAR driver to obtain information like the device mode, + Antenna index,baseband index, SAR table index and use available communication + like MBIM interface to enable data communication to modem for RF power regulation. + endif # X86_PLATFORM_DEVICES config PMC_ATOM diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index dcc8cdb95b4d..548ff663c4af 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -123,6 +123,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += intel_speed_select_if/ obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency.o +obj-$(CONFIG_INTEL_SAR) += intel-sar.o # Intel PMIC / PMC / P-Unit devices obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o diff --git a/drivers/platform/x86/intel-sar.c b/drivers/platform/x86/intel-sar.c new file mode 100644 index 000000000000..dd3056b11e53 --- /dev/null +++ b/drivers/platform/x86/intel-sar.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel Corporation - ACPI for Specific Absorption Rate + * Copyright (c) 2021, Intel Corporation. + */ + +#include <linux/platform_device.h> +#include <net/netlink.h> +#include <net/net_namespace.h> +#include <linux/acpi.h> +#include <uapi/linux/errno.h> +#include <linux/platform_data/x86/intel-sar.h> + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Platform device driver for INTEL MODEM BIOS SAR"); +MODULE_AUTHOR("Shravan S <s.shravan@xxxxxxxxx>"); + +static struct WWAN_SAR_CONTEXT *context; + +static long sar_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg); + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = sar_dev_ioctl, +}; + +static int sar_add(struct platform_device *device); +static int sar_remove(struct platform_device *device); +static void sar_shutdown(struct platform_device *device); +static void sar_notify(acpi_handle handle, u32 event, void *data); + +/** + * sar_send_notify - Send Device SAR information to userspace + * + * Send the sar data and device information to the userspace and later sent to modem + * by the userspace application. The data sent is collected from the BIOS. + * This data is used by userspace for further handling of the modem output. + */ +static void sar_send_notify(void) +{ + int result = 0; + struct sk_buff *skb; + struct nlmsghdr *nlh = NULL; + + pr_debug("Entering: %s\n", __func__); + if (!context->socket) { + pr_err("Socket is not valid\n"); + return; + } + skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct WWAN_DEVICE_MODE_INFO)), GFP_KERNEL); + if (!skb) { + pr_err("Failed to allocate a new skb\n"); + return; + } + nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, sizeof(struct WWAN_DEVICE_MODE_INFO), 0); + if (!nlh) { + pr_err("Error while nlmsg_put netlink is triggered\n"); + nlmsg_free(skb); + return; + } + memcpy(nlmsg_data(nlh), (const char *)&context->sar_data, + sizeof(context->sar_data)); + pr_debug("Device_mode: %d\n", context->sar_data.device_mode); + pr_debug("bandtable_index: %d\n", context->sar_data.bandtable_index); + pr_debug("antennatable_index : %d\n", context->sar_data.antennatable_index); + pr_debug("sartable_index: %d\n", context->sar_data.sartable_index); + + result = nlmsg_multicast(context->socket, skb, 0, NETLINK_SAR_GROUP, GFP_KERNEL); + if (result < 0) + pr_err("Error while sending bak to user: %d\n", result); +} + +/** + * clear_sar_dev_mode - Clear Device Mode by freeing the allocated data + * + * If the Device Mode Info is present and allocated, clear it. This is for + * dynamic allocated memory of device_mode_info + */ +static void clear_sar_dev_mode(void) +{ + int reg = 0; + + for (reg = 0; reg < MAX_REGULATORY; reg++) { + kfree(context->config_data[reg].device_mode_info); + context->config_data[reg].device_mode_info = NULL; + } +} + +/** + * get_int_value - Retrieve Integer values from ACPI Object + * @obj: acpi_object pointer which gets the integer value + * @out: output pointer for integer + * + * Value of the integer from the object of ACPI is obtained. + * returns 0 on success + */ +static int get_int_value(union acpi_object *obj, int *out) +{ + if (obj && obj->type == ACPI_TYPE_INTEGER) { + *out = (int)obj->integer.value; + return 0; + } else { + return -1; + } +} + +/** + * update_sar_data - sar data is updated based on reg_value + * + * sar_data is updated based on regulatory value + */ +static void update_sar_data(void) +{ + pr_debug("%s: Update SAR data\n", __func__); + if (context->config_data[context->reg_value].device_mode_info && + context->sar_data.device_mode <= + context->config_data[context->reg_value].total_dev_mode) { + context->sar_data.antennatable_index = + context->config_data[context->reg_value] + .device_mode_info[context->sar_data.device_mode].antennatable_index; + context->sar_data.bandtable_index = + context->config_data[context->reg_value] + .device_mode_info[context->sar_data.device_mode].bandtable_index; + context->sar_data.sartable_index = + context->config_data[context->reg_value] + .device_mode_info[context->sar_data.device_mode].sartable_index; + pr_debug("bandtable_index: %d\n", context->sar_data.bandtable_index); + pr_debug("antennatable_index : %d\n", context->sar_data.antennatable_index); + pr_debug("sartable_index: %d\n", context->sar_data.sartable_index); + } else { + pr_err("%s: sar data not assigned! Dev mode: %d, total_dev_mode: %d\n", + __func__, context->sar_data.device_mode, + context->config_data[context->reg_value].total_dev_mode); + } +} + +/** + * parse_guid - parse guid based on DSM UUID + * + * returns if success or error + */ +static acpi_status parse_guid(void) +{ + if (guid_parse(SAR_DSM_UUID, &context->guid)) { + pr_err("%s: UUID error\n", __func__); + return AE_ERROR; + } + context->parse = true; + return AE_OK; +} + +/** + * parse_package - parse package for SAR + * + * @item : acpi_object ptr + * @reg : integer - regulatory modes + * + * returns if success or error + */ +static acpi_status parse_package(union acpi_object *item, int reg) +{ + int value = 0, itr = 0; + union acpi_object *num; + + if (context->config_data[reg].total_dev_mode == 0) { + pr_err("Dev Mode count is zero, return\n"); + return AE_ERROR; + } + context->config_data[reg].device_mode_info = + kmalloc_array(context->config_data[reg].total_dev_mode, + sizeof(struct WWAN_DEVICE_MODE_INFO), GFP_KERNEL); + if (!context->config_data[reg].device_mode_info) { + pr_err("Cannot allocate memory in kernel\n"); + return AE_ERROR; + } + num = &item->package.elements[0]; + if (get_int_value(num, &value) == 0) + pr_debug("%s: Regulatory value : %d\n", __func__, value); + for (itr = 0; itr < context->config_data[reg].total_dev_mode; itr++) { + num = &item->package.elements[1]; + if (num && num->type == ACPI_TYPE_PACKAGE) { + if (get_int_value(&num->package.elements[0], &value) == 0) { + pr_debug("%s: Device Mode for mode %d: %d\n", __func__, itr, value); + context->config_data[reg].device_mode_info[itr].device_mode = value; + } + if (get_int_value(&num->package.elements[1], &value) == 0) { + pr_debug("%s: band_index mode %d: %d\n", __func__, itr, value); + context->config_data[reg].device_mode_info[itr].bandtable_index = + value; + } + if (get_int_value(&num->package.elements[2], &value) == 0) { + pr_debug("%s: antenna_index mode %d: %d\n", __func__, itr, value); + context->config_data[reg].device_mode_info[itr].antennatable_index = + value; + } + if (get_int_value(&num->package.elements[3], &value) == 0) { + pr_debug("%s: sar_index for mode %d: %d\n", __func__, itr, value); + context->config_data[reg].device_mode_info[itr].sartable_index = + value; + } + } + } + return AE_OK; +} + +/** + * sar_module_probe - Extraction of information from BIOS via DSM calls + * @device: ACPI device for which to retrieve the data + * + * Retrieve all values related to device mode and SAR Table index, + * Antenna Table index, Band Table index + * Returns AE_OK on success + */ +static acpi_status sar_module_probe(struct platform_device *device) +{ + acpi_status status = AE_OK; + union acpi_object *out, *item, req; + u32 rev = 0, reg = 0; + int value = 0; + + pr_alert("%s Triggered\n", __func__); + if (!device) { + pr_err("%s: platform driver is null\n", __func__); + return AE_ERROR; + } + if (!context) { + pr_err("%s: context is null\n", __func__); + return AE_ERROR; + } + pr_debug("ACPI_HANDLE : %p\n", ACPI_HANDLE(&device->dev)); + status = acpi_install_notify_handler(ACPI_HANDLE(&device->dev), ACPI_DEVICE_NOTIFY, + sar_notify, (void *)device); + if (!(context->parse)) { + status = parse_guid(); + if (status != AE_OK) + return status; + } + context->handle = ACPI_HANDLE(&device->dev); + out = acpi_evaluate_dsm(context->handle, &context->guid, rev, + COMMAND_ID_DEV_MODE, NULL); + pr_debug("%s: acpi_evaluate_dsm completed %d\n", __func__, out->type); + if (get_int_value(out, &value) == 0) { + pr_debug("%s: Device Mode is : %d\n", __func__, value); + context->sar_data.device_mode = value; + } else { + pr_err("%s: Cmd:%d Failed\n", __func__, COMMAND_ID_DEV_MODE); + return AE_ERROR; + } + ACPI_FREE(out); + if (!(context->data_read)) { + for (reg = 0; reg < MAX_REGULATORY; reg++) { + req.type = ACPI_TYPE_INTEGER; + req.integer.value = reg; + out = acpi_evaluate_dsm(context->handle, &context->guid, rev, + COMMAND_ID_CONFIG_TABLE, &req); + if (!out) { + pr_err("%s: Cmd:%d Failed\n", __func__, + COMMAND_ID_CONFIG_TABLE); + continue; + } + pr_debug("%s: acpi_evaluate_dsm for regulatory %d completed %d\n", + __func__, reg, out->type); + if (out->type == ACPI_TYPE_PACKAGE) { + pr_debug("%s: ACPI_TYPE_PACKAGE, count: %d, type: %d\n", + __func__, out->package.count, out->package.type); + item = &out->package.elements[0]; + if (get_int_value(item, &value) == 0) { + pr_debug("%s: version : %d\n", __func__, value); + context->config_data[reg].version = value; + } + item = &out->package.elements[1]; + if (get_int_value(item, &value) == 0) { + pr_debug("%s: No of Modes: %d\n", __func__, value); + context->config_data[reg].total_dev_mode = value; + } + if (context->config_data[reg].total_dev_mode <= 0 && + context->config_data[reg].total_dev_mode > + MAX_DEV_MODES) { + pr_err("total_dev_mode is not within range : %d\n", + context->config_data[reg].total_dev_mode); + ACPI_FREE(out); + return AE_ERROR; + } + item = &out->package.elements[2]; + if (item) + status = parse_package(item, reg); + else + status = AE_ERROR; + if (status != AE_OK) + return status; + } + ACPI_FREE(out); + } + update_sar_data(); + context->data_read = true; + } + sar_send_notify(); + return status; +} + +/** + * sar_set_device_mode - To set the device mode as BIOS handling test + * @device: ACPI device for which to retrieve the data + * @mode: Device Mode to be set + * + * Test Function call to BIOS for device mode handling of data sent via + * DSM calls. + */ +static acpi_status sar_set_device_mode(struct platform_device *device, int mode) +{ + union acpi_object *out, req; + u32 rev = 0; + int value = 0; + acpi_status status = AE_OK; + + pr_alert("%s Triggered : mode : %d\n", __func__, mode); + if (!device) { + pr_err("%s: Device is null\n", __func__); + return AE_ERROR; + } + if (!context->handle) { + pr_err("%s: Handle is null\n", __func__); + return AE_ERROR; + } + if (!(context->parse)) { + status = parse_guid(); + if (status != AE_OK) + return status; + } + + req.type = ACPI_TYPE_INTEGER; + req.integer.value = mode; + out = acpi_evaluate_dsm(context->handle, &context->guid, + rev, COMMAND_TEST_SET, &req); + if (get_int_value(out, &value) != 0) { + pr_err("%s: Cmd:%d Failed\n", __func__, COMMAND_ID_DEV_MODE); + return AE_ERROR; + } + pr_debug("%s: return value is : %d\n", __func__, value); + ACPI_FREE(out); + return status; +} + +/** + * sar_dev_ioctl - This function will be called when we perform ioctl calls to driver + * @file: file pointer + * @cmd: the command passed for action + * @arg: argument used in the commands + * + * Based on command this function + * WR_VALUE: writes specific Regulatory value, + * MODE_VALUE: changes device modes sent by userspace + * SUPPORT_VALUE: Sends the supported data back to userspace + * RD_VALUE: Get sar_data value from userspace + * Errors if not 0 is obtained from errno.h + */ +static long sar_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int value = 0; + unsigned long ret = 0; + acpi_status status = AE_OK; + + if (!context) { + pr_err("%s context is null\n", __func__); + return -EINVAL; + } + switch (cmd) { + case WR_VALUE: + ret = copy_from_user(&value, (void __user *)arg, sizeof(int32_t)); + if (ret != 0) { + pr_err("copy_from_user for %d fails = %ld\n", cmd, ret); + return -EFAULT; + } + pr_debug("Regulatory Value Set by User = %d\n", value); + if (value >= 0 && value < MAX_REGULATORY) { + context->reg_value = value; + update_sar_data(); + sar_send_notify(); + } + break; + case MODE_VALUE: + ret = copy_from_user(&value, (void __user *)arg, sizeof(int32_t)); + if (ret != 0) { + pr_err("copy_from_user for %d fails = %ld\n", cmd, ret); + return -EFAULT; + } + pr_debug("Change Device Mode from %d to %d\n", + context->sar_data.device_mode, value); + status = sar_set_device_mode(context->sar_device, value); + if (status != AE_OK) { + pr_err("sar_set_device_mode for %d failed\n", cmd); + return -EINVAL; + } + break; + case SUPPORT_VALUE: + ret = copy_from_user(&context->supported_data, (void __user *)arg, + sizeof(struct WWAN_SUPPORTED_INFO)); + if (ret != 0) { + pr_err("copy_from_user for %d fails = %ld\n", cmd, ret); + return -EFAULT; + } + pr_debug("reg set= %d\n", context->supported_data.reg_mode_needed); + if (context->supported_data.reg_mode_needed < 0 && + context->supported_data.reg_mode_needed > MAX_REGULATORY) { + context->supported_data.reg_mode_needed = 0; + return -EINVAL; + } + context->supported_data.bios_table_revision = + context->config_data[context->supported_data.reg_mode_needed] + .version; + context->supported_data.num_supported_modes = + context->config_data[context->supported_data.reg_mode_needed] + .total_dev_mode; + pr_debug("ver=%d, modes = %d", + context->supported_data.bios_table_revision, + context->supported_data.num_supported_modes); + ret = copy_to_user((void __user *)arg, &context->supported_data, + sizeof(context->supported_data)); + if (ret != 0) { + pr_err("copy_to_user for %d fails = %ld\n", cmd, ret); + return -EFAULT; + } + break; + case RD_VALUE: + ret = copy_to_user((void __user *)arg, &context->sar_data, + sizeof(context->sar_data)); + if (ret != 0) { + pr_err("copy_to_user for %d fails = %ld\n", cmd, ret); + return -EFAULT; + } + break; + default: + pr_err("%s command not handled = %d\n", __func__, cmd); + return -EINVAL; + } + return ret; +} + +static const struct acpi_device_id sar_device_ids[] = { + { "INTC1092", 0}, + { "", 0}, +}; + +MODULE_DEVICE_TABLE(acpi, sar_device_ids); + +static const struct platform_device_id sar_device_table[] = { + {"sar", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(platform, sar_device_table); + +static struct platform_driver sar_driver = { + .probe = sar_add, + .remove = sar_remove, + .shutdown = sar_shutdown, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + /* FOR ACPI HANDLING */ + .acpi_match_table = ACPI_PTR(sar_device_ids), + }, + .id_table = sar_device_table, +}; + +static int sar_add(struct platform_device *device) +{ + pr_debug("%s Triggered\n", __func__); + context->sar_device = device; + if (sar_module_probe(device) != AE_OK) + return -1; + return 0; +} + +static int sar_remove(struct platform_device *device) +{ + pr_debug("%s Triggered\n", __func__); + acpi_remove_notify_handler(ACPI_HANDLE(&device->dev), + ACPI_DEVICE_NOTIFY, sar_notify); + context->sar_device = NULL; + memset(&context->sar_data, 0, sizeof(context->sar_data)); + return 0; +} + +static void sar_shutdown(struct platform_device *device) +{ + sar_remove(device); + return; +} + +static void sar_notify(acpi_handle handle, u32 event, void *data) +{ + struct platform_device *device = data; + + pr_alert("%s Triggered: event: %d\n", __func__, event); + if (event == SAR_EVENT) { + pr_debug("%s event matched\n", __func__); + if (sar_module_probe(device) != AE_OK) + pr_err("sar_module_probe error"); + } +} + +static int sar_init(void) +{ + int result = 0; + + pr_alert("SAR Init Triggered\n"); + context = kmalloc(sizeof(*context), GFP_KERNEL); + if (!context) { + pr_err("Cannot allocate memory in kernel for WWAN_SAR_CONTEXT\n"); + return -1; + } + memset(context, 0, sizeof(struct WWAN_SAR_CONTEXT)); + if ((alloc_chrdev_region(&context->dev, 0, 1, DRVNAME)) < 0) { + pr_err("Cannot allocate major number for device\n"); + goto r_free; + } + pr_debug("Major = %d Minor = %d\n", MAJOR(context->dev), MINOR(context->dev)); + + /*Creating cdev structure*/ + cdev_init(&context->dev_cdev, &fops); + + /*Adding character device to the system*/ + if ((cdev_add(&context->dev_cdev, context->dev, 1)) < 0) { + pr_err("Cannot add the device to the system\n"); + goto r_char; + } + + /*Creating struct class*/ + context->dev_class = class_create(THIS_MODULE, DRVCLASS); + if (!context->dev_class) { + pr_err("Cannot create the struct class for device\n"); + goto r_cdev; + } + + /*Creating device*/ + if (!device_create(context->dev_class, NULL, context->dev, NULL, DRVNAME)) { + pr_err("Cannot create the Device\n"); + goto r_dev; + } + + pr_debug("created dev entry\n"); + context->socket = netlink_kernel_create(&init_net, NETLINK_SAR, NULL); + if (!context->socket) { + pr_err("Error creating socket\n"); + goto r_dev_class; + } + + result = platform_driver_register(&sar_driver); + if (result < 0) { + pr_err("Error registering driver\n"); + goto r_sock; + } + pr_debug("device registered\n"); + + return 0; + +r_sock: + netlink_kernel_release(context->socket); +r_dev_class: + device_destroy(context->dev_class, context->dev); +r_dev: + class_destroy(context->dev_class); +r_cdev: + cdev_del(&context->dev_cdev); +r_char: + unregister_chrdev_region(context->dev, 1); +r_free: + kfree(context); + return -1; +} + +static void sar_exit(void) +{ + pr_alert("SAR EXIT Triggered\n"); + if (context->socket) + netlink_kernel_release(context->socket); + platform_driver_unregister(&sar_driver); + device_destroy(context->dev_class, context->dev); + class_destroy(context->dev_class); + cdev_del(&context->dev_cdev); + unregister_chrdev_region(context->dev, 1); + clear_sar_dev_mode(); + kfree(context); + pr_debug("Kernel Module Removed Successfully.\n"); +} + +module_init(sar_init); +module_exit(sar_exit); diff --git a/include/linux/platform_data/x86/intel-sar.h b/include/linux/platform_data/x86/intel-sar.h new file mode 100644 index 000000000000..437a9774589b --- /dev/null +++ b/include/linux/platform_data/x86/intel-sar.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Intel Corporation Header File for Specific Absorption Rate + * Copyright (c) 2021, Intel Corporation. + */ +#ifndef INTEL_SAR_H +#define INTEL_SAR_H + +#include <linux/cdev.h> + +#define DRVNAME "sar" +#define DRVCLASS "sar_class" +#define SAR_DSM_UUID "82737E72-3A33-4C45-A9C7-57C0411A5F13" +#define COMMAND_ID_DEV_MODE 1 +#define COMMAND_ID_CONFIG_TABLE 2 +#define COMMAND_TEST_SET 31 +#define MAX_REGULATORY 3 +#define SAR_EVENT 0x80 +#define MAJOR_VER 1 +#define MINOR_VER 0 + +#define BUFFER_SIZE 256 +#define WR_VALUE _IOW('a', 'a', int32_t*) +#define RD_VALUE _IOR('a', 'b', int32_t*) +#define MODE_VALUE _IOW('a', 'd', int32_t*) +#define SUPPORT_VALUE _IOWR('a', 'e', struct WWAN_SUPPORTED_INFO*) +#define MAX_DEV_MODES 50 +#define NETLINK_SAR 25 +#define NETLINK_SAR_GROUP 2 + +/** + * Structure WWAN_DEVICE_MODE_INFO + * + * Holds the data that needs to be passed to userspace. + * The data is updated from the BIOS sensor information. + * + * @device_mode: Specific mode of the device + * @bandtable_index: Index of RF band + * @antennatable_index: Index of antenna + * @sartable_index: Index of SAR + */ +struct WWAN_DEVICE_MODE_INFO { + int device_mode; + int bandtable_index; + int antennatable_index; + int sartable_index; +}; + +/** + * Structure WWAN_DEVICE_MODE_CONFIGURATION + * + * Holds the data that is configured and obtained on probe event. + * The data is updated from the BIOS sensor information. + * + * @version: Mode configuration version + * @total_dev_mode: Total number of device modes + * @device_mode_info: pointer to structure WWAN_DEVICE_MODE_INFO + */ +struct WWAN_DEVICE_MODE_CONFIGURATION { + int version; + int total_dev_mode; + struct WWAN_DEVICE_MODE_INFO *device_mode_info; +}; + +/** + * Structure WWAN_SUPPORTED_INFO + * + * Holds the data that is obtained from userspace + * The data is updated from the userspace and send value back in the + * structure format that is mentioned here. + * + * @reg_mode_needed: regulatory mode set by user for tests + * @bios_table_revision: Version of SAR table + * @num_supported_modes: Total supported modes based on reg_mode + */ +struct WWAN_SUPPORTED_INFO { + int reg_mode_needed; + int bios_table_revision; + int num_supported_modes; +}; + +/** + * Structure WWAN_SAR_CONTEXT + * + * Holds the complete context as long as the driver is in existence + * The context holds instance of the data used for different cases. + * + * @dev: holds device data + * @parse: identifies if dsm is parsed + * @data_read: identifies if data is already read from BIOS + * @guid: Group id + * @handle: store acpi handle + * @dev_class: stores the dev_class context + * @dev_cdev: handle for device cdev type + * @socket: sock for netlink + * @reg_value: regulatory value + * Regulatory 0: FCC, 1: CE, 2: ISED + * @sar_device: platform_device type + * @supported_data: WWAN_SUPPORTED_INFO struct + * @sar_data: WWAN_DEVICE_MODE_INFO struct + * @config_data: WWAN_DEVICE_MODE_CONFIGURATION array struct + */ +struct WWAN_SAR_CONTEXT { + dev_t dev; + bool parse; + bool data_read; + guid_t guid; + acpi_handle handle; + struct class *dev_class; + struct cdev dev_cdev; + struct sock *socket; + int reg_value; + struct platform_device *sar_device; + struct WWAN_SUPPORTED_INFO supported_data; + struct WWAN_DEVICE_MODE_INFO sar_data; + struct WWAN_DEVICE_MODE_CONFIGURATION config_data[MAX_REGULATORY]; +}; +#endif /* INTEL_SAR_H */ -- 2.17.1