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