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