1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * pnpacpi -- PnP ACPI driver
5 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
6 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
9 #include <linux/export.h>
10 #include <linux/acpi.h>
11 #include <linux/pnp.h>
12 #include <linux/slab.h>
13 #include <linux/mod_devicetable.h>
21 * Compatible Device IDs
24 if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
26 #define TEST_ALPHA(c) \
27 if (!('A' <= (c) && (c) <= 'Z')) \
29 static int __init
ispnpidacpi(const char *id
)
43 static int pnpacpi_get_resources(struct pnp_dev
*dev
)
45 pnp_dbg(&dev
->dev
, "get resources\n");
46 return pnpacpi_parse_allocated_resource(dev
);
49 static int pnpacpi_set_resources(struct pnp_dev
*dev
)
51 struct acpi_device
*acpi_dev
;
55 pnp_dbg(&dev
->dev
, "set resources\n");
57 acpi_dev
= ACPI_COMPANION(&dev
->dev
);
59 dev_dbg(&dev
->dev
, "ACPI device not found in %s!\n", __func__
);
63 if (WARN_ON_ONCE(acpi_dev
!= dev
->data
))
66 handle
= acpi_dev
->handle
;
67 if (acpi_has_method(handle
, METHOD_NAME__SRS
)) {
68 struct acpi_buffer buffer
;
70 ret
= pnpacpi_build_resource_template(dev
, &buffer
);
74 ret
= pnpacpi_encode_resources(dev
, &buffer
);
78 status
= acpi_set_current_resources(handle
, &buffer
);
79 if (ACPI_FAILURE(status
))
82 kfree(buffer
.pointer
);
84 if (!ret
&& acpi_device_power_manageable(acpi_dev
))
85 ret
= acpi_device_set_power(acpi_dev
, ACPI_STATE_D0
);
90 static int pnpacpi_disable_resources(struct pnp_dev
*dev
)
92 struct acpi_device
*acpi_dev
;
95 dev_dbg(&dev
->dev
, "disable resources\n");
97 acpi_dev
= ACPI_COMPANION(&dev
->dev
);
99 dev_dbg(&dev
->dev
, "ACPI device not found in %s!\n", __func__
);
103 /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
104 if (acpi_device_power_manageable(acpi_dev
))
105 acpi_device_set_power(acpi_dev
, ACPI_STATE_D3_COLD
);
107 /* continue even if acpi_device_set_power() fails */
108 status
= acpi_evaluate_object(acpi_dev
->handle
, "_DIS", NULL
, NULL
);
109 if (ACPI_FAILURE(status
) && status
!= AE_NOT_FOUND
)
115 #ifdef CONFIG_ACPI_SLEEP
116 static bool pnpacpi_can_wakeup(struct pnp_dev
*dev
)
118 struct acpi_device
*acpi_dev
= ACPI_COMPANION(&dev
->dev
);
121 dev_dbg(&dev
->dev
, "ACPI device not found in %s!\n", __func__
);
125 return acpi_bus_can_wakeup(acpi_dev
->handle
);
128 static int pnpacpi_suspend(struct pnp_dev
*dev
, pm_message_t state
)
130 struct acpi_device
*acpi_dev
= ACPI_COMPANION(&dev
->dev
);
134 dev_dbg(&dev
->dev
, "ACPI device not found in %s!\n", __func__
);
138 if (device_can_wakeup(&dev
->dev
)) {
139 error
= acpi_pm_set_device_wakeup(&dev
->dev
,
140 device_may_wakeup(&dev
->dev
));
145 if (acpi_device_power_manageable(acpi_dev
)) {
146 int power_state
= acpi_pm_device_sleep_state(&dev
->dev
, NULL
,
149 power_state
= (state
.event
== PM_EVENT_ON
) ?
150 ACPI_STATE_D0
: ACPI_STATE_D3_COLD
;
153 * acpi_device_set_power() can fail (keyboard port can't be
154 * powered-down?), and in any case, our return value is ignored
155 * by pnp_bus_suspend(). Hence we don't revert the wakeup
156 * setting if the set_power fails.
158 error
= acpi_device_set_power(acpi_dev
, power_state
);
164 static int pnpacpi_resume(struct pnp_dev
*dev
)
166 struct acpi_device
*acpi_dev
= ACPI_COMPANION(&dev
->dev
);
170 dev_dbg(&dev
->dev
, "ACPI device not found in %s!\n", __func__
);
174 if (device_may_wakeup(&dev
->dev
))
175 acpi_pm_set_device_wakeup(&dev
->dev
, false);
177 if (acpi_device_power_manageable(acpi_dev
))
178 error
= acpi_device_set_power(acpi_dev
, ACPI_STATE_D0
);
184 struct pnp_protocol pnpacpi_protocol
= {
185 .name
= "Plug and Play ACPI",
186 .get
= pnpacpi_get_resources
,
187 .set
= pnpacpi_set_resources
,
188 .disable
= pnpacpi_disable_resources
,
189 #ifdef CONFIG_ACPI_SLEEP
190 .can_wakeup
= pnpacpi_can_wakeup
,
191 .suspend
= pnpacpi_suspend
,
192 .resume
= pnpacpi_resume
,
195 EXPORT_SYMBOL(pnpacpi_protocol
);
197 static const char *__init
pnpacpi_get_id(struct acpi_device
*device
)
199 struct acpi_hardware_id
*id
;
201 list_for_each_entry(id
, &device
->pnp
.ids
, list
) {
202 if (ispnpidacpi(id
->id
))
209 static int __init
pnpacpi_add_device(struct acpi_device
*device
)
213 struct acpi_hardware_id
*id
;
216 /* Skip devices that are already bound */
217 if (device
->physical_node_count
)
221 * If a PnPacpi device is not present , the device
222 * driver should not be loaded.
224 if (!acpi_has_method(device
->handle
, "_CRS"))
227 pnpid
= pnpacpi_get_id(device
);
231 if (!device
->status
.present
)
234 dev
= pnp_alloc_dev(&pnpacpi_protocol
, num
, pnpid
);
238 ACPI_COMPANION_SET(&dev
->dev
, device
);
240 /* .enabled means the device can decode the resources */
241 dev
->active
= device
->status
.enabled
;
242 if (acpi_has_method(device
->handle
, "_SRS"))
243 dev
->capabilities
|= PNP_CONFIGURABLE
;
244 dev
->capabilities
|= PNP_READ
;
245 if (device
->flags
.dynamic_status
&& (dev
->capabilities
& PNP_CONFIGURABLE
))
246 dev
->capabilities
|= PNP_WRITE
;
247 if (device
->flags
.removable
)
248 dev
->capabilities
|= PNP_REMOVABLE
;
249 if (acpi_has_method(device
->handle
, "_DIS"))
250 dev
->capabilities
|= PNP_DISABLE
;
252 if (strlen(acpi_device_name(device
)))
253 strncpy(dev
->name
, acpi_device_name(device
), sizeof(dev
->name
));
255 strncpy(dev
->name
, acpi_device_bid(device
), sizeof(dev
->name
));
258 pnpacpi_parse_allocated_resource(dev
);
260 if (dev
->capabilities
& PNP_CONFIGURABLE
)
261 pnpacpi_parse_resource_option_data(dev
);
263 list_for_each_entry(id
, &device
->pnp
.ids
, list
) {
264 if (!strcmp(id
->id
, pnpid
))
266 if (!ispnpidacpi(id
->id
))
268 pnp_add_id(dev
, id
->id
);
271 /* clear out the damaged flags */
273 pnp_init_resources(dev
);
275 error
= pnp_add_device(dev
);
277 put_device(&dev
->dev
);
286 static acpi_status __init
pnpacpi_add_device_handler(acpi_handle handle
,
287 u32 lvl
, void *context
,
290 struct acpi_device
*device
;
292 if (acpi_bus_get_device(handle
, &device
))
293 return AE_CTRL_DEPTH
;
294 if (acpi_is_pnp_device(device
))
295 pnpacpi_add_device(device
);
299 int pnpacpi_disabled __initdata
;
300 static int __init
pnpacpi_init(void)
302 if (acpi_disabled
|| pnpacpi_disabled
) {
303 printk(KERN_INFO
"pnp: PnP ACPI: disabled\n");
306 printk(KERN_INFO
"pnp: PnP ACPI init\n");
307 pnp_register_protocol(&pnpacpi_protocol
);
308 acpi_get_devices(NULL
, pnpacpi_add_device_handler
, NULL
, NULL
);
309 printk(KERN_INFO
"pnp: PnP ACPI: found %d devices\n", num
);
310 pnp_platform_devices
= 1;
314 fs_initcall(pnpacpi_init
);
316 static int __init
pnpacpi_setup(char *str
)
320 if (!strncmp(str
, "off", 3))
321 pnpacpi_disabled
= 1;
325 __setup("pnpacpi=", pnpacpi_setup
);