147 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * Device physical location support
 | |
|  *
 | |
|  * Author: Won Chung <wonchung@google.com>
 | |
|  */
 | |
| 
 | |
| #include <linux/acpi.h>
 | |
| #include <linux/sysfs.h>
 | |
| 
 | |
| #include "physical_location.h"
 | |
| 
 | |
| bool dev_add_physical_location(struct device *dev)
 | |
| {
 | |
| 	struct acpi_pld_info *pld;
 | |
| 	acpi_status status;
 | |
| 
 | |
| 	if (!has_acpi_companion(dev))
 | |
| 		return false;
 | |
| 
 | |
| 	status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld);
 | |
| 	if (ACPI_FAILURE(status))
 | |
| 		return false;
 | |
| 
 | |
| 	dev->physical_location =
 | |
| 		kzalloc(sizeof(*dev->physical_location), GFP_KERNEL);
 | |
| 	if (!dev->physical_location) {
 | |
| 		ACPI_FREE(pld);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	dev->physical_location->panel = pld->panel;
 | |
| 	dev->physical_location->vertical_position = pld->vertical_position;
 | |
| 	dev->physical_location->horizontal_position = pld->horizontal_position;
 | |
| 	dev->physical_location->dock = pld->dock;
 | |
| 	dev->physical_location->lid = pld->lid;
 | |
| 
 | |
| 	ACPI_FREE(pld);
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static ssize_t panel_show(struct device *dev, struct device_attribute *attr,
 | |
| 	char *buf)
 | |
| {
 | |
| 	const char *panel;
 | |
| 
 | |
| 	switch (dev->physical_location->panel) {
 | |
| 	case DEVICE_PANEL_TOP:
 | |
| 		panel = "top";
 | |
| 		break;
 | |
| 	case DEVICE_PANEL_BOTTOM:
 | |
| 		panel = "bottom";
 | |
| 		break;
 | |
| 	case DEVICE_PANEL_LEFT:
 | |
| 		panel = "left";
 | |
| 		break;
 | |
| 	case DEVICE_PANEL_RIGHT:
 | |
| 		panel = "right";
 | |
| 		break;
 | |
| 	case DEVICE_PANEL_FRONT:
 | |
| 		panel = "front";
 | |
| 		break;
 | |
| 	case DEVICE_PANEL_BACK:
 | |
| 		panel = "back";
 | |
| 		break;
 | |
| 	default:
 | |
| 		panel = "unknown";
 | |
| 	}
 | |
| 	return sysfs_emit(buf, "%s\n", panel);
 | |
| }
 | |
| static DEVICE_ATTR_RO(panel);
 | |
| 
 | |
| static ssize_t vertical_position_show(struct device *dev,
 | |
| 	struct device_attribute *attr, char *buf)
 | |
| {
 | |
| 	const char *vertical_position;
 | |
| 
 | |
| 	switch (dev->physical_location->vertical_position) {
 | |
| 	case DEVICE_VERT_POS_UPPER:
 | |
| 		vertical_position = "upper";
 | |
| 		break;
 | |
| 	case DEVICE_VERT_POS_CENTER:
 | |
| 		vertical_position = "center";
 | |
| 		break;
 | |
| 	case DEVICE_VERT_POS_LOWER:
 | |
| 		vertical_position = "lower";
 | |
| 		break;
 | |
| 	default:
 | |
| 		vertical_position = "unknown";
 | |
| 	}
 | |
| 	return sysfs_emit(buf, "%s\n", vertical_position);
 | |
| }
 | |
| static DEVICE_ATTR_RO(vertical_position);
 | |
| 
 | |
| static ssize_t horizontal_position_show(struct device *dev,
 | |
| 	struct device_attribute *attr, char *buf)
 | |
| {
 | |
| 	const char *horizontal_position;
 | |
| 
 | |
| 	switch (dev->physical_location->horizontal_position) {
 | |
| 	case DEVICE_HORI_POS_LEFT:
 | |
| 		horizontal_position = "left";
 | |
| 		break;
 | |
| 	case DEVICE_HORI_POS_CENTER:
 | |
| 		horizontal_position = "center";
 | |
| 		break;
 | |
| 	case DEVICE_HORI_POS_RIGHT:
 | |
| 		horizontal_position = "right";
 | |
| 		break;
 | |
| 	default:
 | |
| 		horizontal_position = "unknown";
 | |
| 	}
 | |
| 	return sysfs_emit(buf, "%s\n", horizontal_position);
 | |
| }
 | |
| static DEVICE_ATTR_RO(horizontal_position);
 | |
| 
 | |
| static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
 | |
| 	char *buf)
 | |
| {
 | |
| 	return sysfs_emit(buf, "%s\n",
 | |
| 		dev->physical_location->dock ? "yes" : "no");
 | |
| }
 | |
| static DEVICE_ATTR_RO(dock);
 | |
| 
 | |
| static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
 | |
| 	char *buf)
 | |
| {
 | |
| 	return sysfs_emit(buf, "%s\n",
 | |
| 		dev->physical_location->lid ? "yes" : "no");
 | |
| }
 | |
| static DEVICE_ATTR_RO(lid);
 | |
| 
 | |
| static struct attribute *dev_attr_physical_location[] = {
 | |
| 	&dev_attr_panel.attr,
 | |
| 	&dev_attr_vertical_position.attr,
 | |
| 	&dev_attr_horizontal_position.attr,
 | |
| 	&dev_attr_dock.attr,
 | |
| 	&dev_attr_lid.attr,
 | |
| 	NULL,
 | |
| };
 | |
| 
 | |
| const struct attribute_group dev_attr_physical_location_group = {
 | |
| 	.name = "physical_location",
 | |
| 	.attrs = dev_attr_physical_location,
 | |
| };
 | |
| 
 |