1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Device physical location support 4 * 5 * Author: Won Chung <[email protected]> 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 default: 61 panel = "unknown"; 62 } 63 return sysfs_emit(buf, "%s\n", panel); 64 } 65 static DEVICE_ATTR_RO(panel); 66 67 static ssize_t vertical_position_show(struct device *dev, 68 struct device_attribute *attr, char *buf) 69 { 70 const char *vertical_position; 71 72 switch (dev->physical_location->vertical_position) { 73 case DEVICE_VERT_POS_UPPER: 74 vertical_position = "upper"; 75 break; 76 case DEVICE_VERT_POS_CENTER: 77 vertical_position = "center"; 78 break; 79 case DEVICE_VERT_POS_LOWER: 80 vertical_position = "lower"; 81 break; 82 default: 83 vertical_position = "unknown"; 84 } 85 return sysfs_emit(buf, "%s\n", vertical_position); 86 } 87 static DEVICE_ATTR_RO(vertical_position); 88 89 static ssize_t horizontal_position_show(struct device *dev, 90 struct device_attribute *attr, char *buf) 91 { 92 const char *horizontal_position; 93 94 switch (dev->physical_location->horizontal_position) { 95 case DEVICE_HORI_POS_LEFT: 96 horizontal_position = "left"; 97 break; 98 case DEVICE_HORI_POS_CENTER: 99 horizontal_position = "center"; 100 break; 101 case DEVICE_HORI_POS_RIGHT: 102 horizontal_position = "right"; 103 break; 104 default: 105 horizontal_position = "unknown"; 106 } 107 return sysfs_emit(buf, "%s\n", horizontal_position); 108 } 109 static DEVICE_ATTR_RO(horizontal_position); 110 111 static ssize_t dock_show(struct device *dev, struct device_attribute *attr, 112 char *buf) 113 { 114 return sysfs_emit(buf, "%s\n", 115 dev->physical_location->dock ? "yes" : "no"); 116 } 117 static DEVICE_ATTR_RO(dock); 118 119 static ssize_t lid_show(struct device *dev, struct device_attribute *attr, 120 char *buf) 121 { 122 return sysfs_emit(buf, "%s\n", 123 dev->physical_location->lid ? "yes" : "no"); 124 } 125 static DEVICE_ATTR_RO(lid); 126 127 static struct attribute *dev_attr_physical_location[] = { 128 &dev_attr_panel.attr, 129 &dev_attr_vertical_position.attr, 130 &dev_attr_horizontal_position.attr, 131 &dev_attr_dock.attr, 132 &dev_attr_lid.attr, 133 NULL, 134 }; 135 136 const struct attribute_group dev_attr_physical_location_group = { 137 .name = "physical_location", 138 .attrs = dev_attr_physical_location, 139 }; 140 141