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 | 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 | |
42 | static 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 | } |
71 | static DEVICE_ATTR_RO(panel); |
72 | |
73 | static 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 | } |
93 | static DEVICE_ATTR_RO(vertical_position); |
94 | |
95 | static 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 | } |
115 | static DEVICE_ATTR_RO(horizontal_position); |
116 | |
117 | static 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 | } |
123 | static DEVICE_ATTR_RO(dock); |
124 | |
125 | static 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 | } |
131 | static DEVICE_ATTR_RO(lid); |
132 | |
133 | static 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 | |
142 | const struct attribute_group dev_attr_physical_location_group = { |
143 | .name = "physical_location" , |
144 | .attrs = dev_attr_physical_location, |
145 | }; |
146 | |
147 | |