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