1
2
3
4
5
6
7
8
9
10
11#include <linux/acpi.h>
12#include <linux/efi.h>
13#include <linux/pci.h>
14
15static long __init parse_acpi_path(const struct efi_dev_path *node,
16 struct device *parent, struct device **child)
17{
18 char hid[ACPI_ID_LEN], uid[11];
19 struct acpi_device *adev;
20 struct device *phys_dev;
21
22 if (node->header.length != 12)
23 return -EINVAL;
24
25 sprintf(hid, "%c%c%c%04X",
26 'A' + ((node->acpi.hid >> 10) & 0x1f) - 1,
27 'A' + ((node->acpi.hid >> 5) & 0x1f) - 1,
28 'A' + ((node->acpi.hid >> 0) & 0x1f) - 1,
29 node->acpi.hid >> 16);
30 sprintf(uid, "%u", node->acpi.uid);
31
32 for_each_acpi_dev_match(adev, hid, NULL, -1) {
33 if (adev->pnp.unique_id && !strcmp(adev->pnp.unique_id, uid))
34 break;
35 if (!adev->pnp.unique_id && node->acpi.uid == 0)
36 break;
37 }
38 if (!adev)
39 return -ENODEV;
40
41 phys_dev = acpi_get_first_physical_node(adev);
42 if (phys_dev) {
43 *child = get_device(phys_dev);
44 acpi_dev_put(adev);
45 } else
46 *child = &adev->dev;
47
48 return 0;
49}
50
51static int __init match_pci_dev(struct device *dev, void *data)
52{
53 unsigned int devfn = *(unsigned int *)data;
54
55 return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn;
56}
57
58static long __init parse_pci_path(const struct efi_dev_path *node,
59 struct device *parent, struct device **child)
60{
61 unsigned int devfn;
62
63 if (node->header.length != 6)
64 return -EINVAL;
65 if (!parent)
66 return -EINVAL;
67
68 devfn = PCI_DEVFN(node->pci.dev, node->pci.fn);
69
70 *child = device_find_child(parent, &devfn, match_pci_dev);
71 if (!*child)
72 return -ENODEV;
73
74 return 0;
75}
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94static long __init parse_end_path(const struct efi_dev_path *node,
95 struct device *parent, struct device **child)
96{
97 if (node->header.length != 4)
98 return -EINVAL;
99 if (node->header.sub_type != EFI_DEV_END_INSTANCE &&
100 node->header.sub_type != EFI_DEV_END_ENTIRE)
101 return -EINVAL;
102 if (!parent)
103 return -ENODEV;
104
105 *child = get_device(parent);
106 return node->header.sub_type;
107}
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145struct device * __init efi_get_device_by_path(const struct efi_dev_path **node,
146 size_t *len)
147{
148 struct device *parent = NULL, *child;
149 long ret = 0;
150
151 if (!*len)
152 return NULL;
153
154 while (!ret) {
155 if (*len < 4 || *len < (*node)->header.length)
156 ret = -EINVAL;
157 else if ((*node)->header.type == EFI_DEV_ACPI &&
158 (*node)->header.sub_type == EFI_DEV_BASIC_ACPI)
159 ret = parse_acpi_path(*node, parent, &child);
160 else if ((*node)->header.type == EFI_DEV_HW &&
161 (*node)->header.sub_type == EFI_DEV_PCI)
162 ret = parse_pci_path(*node, parent, &child);
163 else if (((*node)->header.type == EFI_DEV_END_PATH ||
164 (*node)->header.type == EFI_DEV_END_PATH2))
165 ret = parse_end_path(*node, parent, &child);
166 else
167 ret = -ENOTSUPP;
168
169 put_device(parent);
170 if (ret < 0)
171 return ERR_PTR(ret);
172
173 parent = child;
174 *node = (void *)*node + (*node)->header.length;
175 *len -= (*node)->header.length;
176 }
177
178 if (ret == EFI_DEV_END_ENTIRE)
179 *len = 0;
180
181 return child;
182}
183