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

source code of linux/drivers/base/physical_location.c