1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Device physical location support 4 * 5 * Author: Won Chung <wonchung@google.com> 6 */ 7 8 #include <linux/acpi.h> 9 #include <linux/sysfs.h> 10 11 #include "physical_location.h" 12 13 bool dev_add_physical_location(struct device *dev) 14 { 15 struct acpi_pld_info *pld; 16 acpi_status status; 17 18 if (!has_acpi_companion(dev)) 19 return false; 20 21 status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld); 22 if (ACPI_FAILURE(status)) 23 return false; 24 25 dev->physical_location = 26 kzalloc(sizeof(*dev->physical_location), GFP_KERNEL); 27 if (!dev->physical_location) 28 return false; 29 dev->physical_location->panel = pld->panel; 30 dev->physical_location->vertical_position = pld->vertical_position; 31 dev->physical_location->horizontal_position = pld->horizontal_position; 32 dev->physical_location->dock = pld->dock; 33 dev->physical_location->lid = pld->lid; 34 35 ACPI_FREE(pld); 36 return true; 37 } 38 39 static ssize_t panel_show(struct device *dev, struct device_attribute *attr, 40 char *buf) 41 { 42 const char *panel; 43 44 switch (dev->physical_location->panel) { 45 case DEVICE_PANEL_TOP: 46 panel = "top"; 47 break; 48 case DEVICE_PANEL_BOTTOM: 49 panel = "bottom"; 50 break; 51 case DEVICE_PANEL_LEFT: 52 panel = "left"; 53 break; 54 case DEVICE_PANEL_RIGHT: 55 panel = "right"; 56 break; 57 case DEVICE_PANEL_FRONT: 58 panel = "front"; 59 break; 60 case DEVICE_PANEL_BACK: 61 panel = "back"; 62 break; 63 default: 64 panel = "unknown"; 65 } 66 return sysfs_emit(buf, "%s\n", panel); 67 } 68 static DEVICE_ATTR_RO(panel); 69 70 static ssize_t vertical_position_show(struct device *dev, 71 struct device_attribute *attr, char *buf) 72 { 73 const char *vertical_position; 74 75 switch (dev->physical_location->vertical_position) { 76 case DEVICE_VERT_POS_UPPER: 77 vertical_position = "upper"; 78 break; 79 case DEVICE_VERT_POS_CENTER: 80 vertical_position = "center"; 81 break; 82 case DEVICE_VERT_POS_LOWER: 83 vertical_position = "lower"; 84 break; 85 default: 86 vertical_position = "unknown"; 87 } 88 return sysfs_emit(buf, "%s\n", vertical_position); 89 } 90 static DEVICE_ATTR_RO(vertical_position); 91 92 static ssize_t horizontal_position_show(struct device *dev, 93 struct device_attribute *attr, char *buf) 94 { 95 const char *horizontal_position; 96 97 switch (dev->physical_location->horizontal_position) { 98 case DEVICE_HORI_POS_LEFT: 99 horizontal_position = "left"; 100 break; 101 case DEVICE_HORI_POS_CENTER: 102 horizontal_position = "center"; 103 break; 104 case DEVICE_HORI_POS_RIGHT: 105 horizontal_position = "right"; 106 break; 107 default: 108 horizontal_position = "unknown"; 109 } 110 return sysfs_emit(buf, "%s\n", horizontal_position); 111 } 112 static DEVICE_ATTR_RO(horizontal_position); 113 114 static ssize_t dock_show(struct device *dev, struct device_attribute *attr, 115 char *buf) 116 { 117 return sysfs_emit(buf, "%s\n", 118 dev->physical_location->dock ? "yes" : "no"); 119 } 120 static DEVICE_ATTR_RO(dock); 121 122 static ssize_t lid_show(struct device *dev, struct device_attribute *attr, 123 char *buf) 124 { 125 return sysfs_emit(buf, "%s\n", 126 dev->physical_location->lid ? "yes" : "no"); 127 } 128 static DEVICE_ATTR_RO(lid); 129 130 static struct attribute *dev_attr_physical_location[] = { 131 &dev_attr_panel.attr, 132 &dev_attr_vertical_position.attr, 133 &dev_attr_horizontal_position.attr, 134 &dev_attr_dock.attr, 135 &dev_attr_lid.attr, 136 NULL, 137 }; 138 139 const struct attribute_group dev_attr_physical_location_group = { 140 .name = "physical_location", 141 .attrs = dev_attr_physical_location, 142 }; 143 144