GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / base / physical_location.c
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);
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                 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, "%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, "%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, "%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, "%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, "%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