2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* acpi_bus.h - ACPI Bus Driver ($Revision: 22 $)
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
|
|
|
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
|
|
|
*
|
|
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or (at
|
|
|
|
* your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
|
|
*
|
|
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __ACPI_BUS_H__
|
|
|
|
#define __ACPI_BUS_H__
|
|
|
|
|
2006-05-10 22:33:00 +08:00
|
|
|
#include <linux/device.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <acpi/acpi.h>
|
|
|
|
|
|
|
|
/* TBD: Make dynamic */
|
|
|
|
#define ACPI_MAX_HANDLES 10
|
|
|
|
struct acpi_handle_list {
|
2005-08-05 12:44:28 +08:00
|
|
|
u32 count;
|
|
|
|
acpi_handle handles[ACPI_MAX_HANDLES];
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* acpi_utils.h */
|
|
|
|
acpi_status
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_extract_package(union acpi_object *package,
|
|
|
|
struct acpi_buffer *format, struct acpi_buffer *buffer);
|
2005-04-17 06:20:36 +08:00
|
|
|
acpi_status
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_evaluate_integer(acpi_handle handle,
|
|
|
|
acpi_string pathname,
|
2008-10-10 14:22:59 +08:00
|
|
|
struct acpi_object_list *arguments, unsigned long long *data);
|
2005-04-17 06:20:36 +08:00
|
|
|
acpi_status
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_evaluate_reference(acpi_handle handle,
|
|
|
|
acpi_string pathname,
|
|
|
|
struct acpi_object_list *arguments,
|
|
|
|
struct acpi_handle_list *list);
|
2012-05-24 10:25:19 +08:00
|
|
|
acpi_status
|
|
|
|
acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
|
|
|
|
u32 status_code, struct acpi_buffer *status_buf);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-05-11 16:08:26 +08:00
|
|
|
acpi_status
|
2012-08-21 09:56:58 +08:00
|
|
|
acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld);
|
2013-06-29 00:24:38 +08:00
|
|
|
|
|
|
|
bool acpi_has_method(acpi_handle handle, char *name);
|
2013-06-29 00:24:39 +08:00
|
|
|
acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
|
|
|
|
u64 arg);
|
2013-06-29 00:24:40 +08:00
|
|
|
acpi_status acpi_evaluate_ej0(acpi_handle handle);
|
|
|
|
acpi_status acpi_evaluate_lck(acpi_handle handle, int lock);
|
2013-06-29 00:24:41 +08:00
|
|
|
bool acpi_ata_match(acpi_handle handle);
|
|
|
|
bool acpi_bay_match(acpi_handle handle);
|
|
|
|
bool acpi_dock_match(acpi_handle handle);
|
2013-06-29 00:24:38 +08:00
|
|
|
|
2005-08-25 00:10:49 +08:00
|
|
|
#ifdef CONFIG_ACPI
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
|
|
|
|
#define ACPI_BUS_FILE_ROOT "acpi"
|
2005-08-05 12:44:28 +08:00
|
|
|
extern struct proc_dir_entry *acpi_root_dir;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
enum acpi_bus_device_type {
|
2005-08-05 12:44:28 +08:00
|
|
|
ACPI_BUS_TYPE_DEVICE = 0,
|
2005-04-17 06:20:36 +08:00
|
|
|
ACPI_BUS_TYPE_POWER,
|
|
|
|
ACPI_BUS_TYPE_PROCESSOR,
|
|
|
|
ACPI_BUS_TYPE_THERMAL,
|
|
|
|
ACPI_BUS_TYPE_POWER_BUTTON,
|
|
|
|
ACPI_BUS_TYPE_SLEEP_BUTTON,
|
|
|
|
ACPI_BUS_DEVICE_TYPE_COUNT
|
|
|
|
};
|
|
|
|
|
|
|
|
struct acpi_driver;
|
|
|
|
struct acpi_device;
|
|
|
|
|
2013-01-30 21:27:29 +08:00
|
|
|
/*
|
|
|
|
* ACPI Scan Handler
|
|
|
|
* -----------------
|
|
|
|
*/
|
|
|
|
|
2013-03-04 06:05:29 +08:00
|
|
|
enum acpi_hotplug_mode {
|
|
|
|
AHM_GENERIC = 0,
|
|
|
|
AHM_CONTAINER,
|
|
|
|
AHM_COUNT
|
|
|
|
};
|
|
|
|
|
|
|
|
struct acpi_hotplug_profile {
|
2013-03-04 06:08:16 +08:00
|
|
|
struct kobject kobj;
|
2013-03-04 06:05:29 +08:00
|
|
|
bool enabled:1;
|
|
|
|
enum acpi_hotplug_mode mode;
|
|
|
|
};
|
|
|
|
|
2013-03-04 06:08:16 +08:00
|
|
|
static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile(
|
|
|
|
struct kobject *kobj)
|
|
|
|
{
|
|
|
|
return container_of(kobj, struct acpi_hotplug_profile, kobj);
|
|
|
|
}
|
|
|
|
|
2013-01-30 21:27:29 +08:00
|
|
|
struct acpi_scan_handler {
|
|
|
|
const struct acpi_device_id *ids;
|
|
|
|
struct list_head list_node;
|
|
|
|
int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
|
|
|
|
void (*detach)(struct acpi_device *dev);
|
2013-03-04 06:05:29 +08:00
|
|
|
struct acpi_hotplug_profile hotplug;
|
2013-01-30 21:27:29 +08:00
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* ACPI Driver
|
|
|
|
* -----------
|
|
|
|
*/
|
|
|
|
|
2005-08-05 12:44:28 +08:00
|
|
|
typedef int (*acpi_op_add) (struct acpi_device * device);
|
2013-01-24 07:24:48 +08:00
|
|
|
typedef int (*acpi_op_remove) (struct acpi_device * device);
|
2009-03-31 01:48:13 +08:00
|
|
|
typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
struct acpi_device_ops {
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_op_add add;
|
|
|
|
acpi_op_remove remove;
|
2009-03-31 01:48:13 +08:00
|
|
|
acpi_op_notify notify;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2009-04-30 23:35:37 +08:00
|
|
|
#define ACPI_DRIVER_ALL_NOTIFY_EVENTS 0x1 /* system AND device events */
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_driver {
|
2005-08-05 12:44:28 +08:00
|
|
|
char name[80];
|
|
|
|
char class[80];
|
2007-07-23 20:43:32 +08:00
|
|
|
const struct acpi_device_id *ids; /* Supported Hardware IDs */
|
2009-04-30 23:35:37 +08:00
|
|
|
unsigned int flags;
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_device_ops ops;
|
2006-12-07 20:56:23 +08:00
|
|
|
struct device_driver drv;
|
2006-12-07 20:56:31 +08:00
|
|
|
struct module *owner;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ACPI Device
|
|
|
|
* -----------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Status (_STA) */
|
|
|
|
|
|
|
|
struct acpi_device_status {
|
2005-08-05 12:44:28 +08:00
|
|
|
u32 present:1;
|
|
|
|
u32 enabled:1;
|
|
|
|
u32 show_in_ui:1;
|
|
|
|
u32 functional:1;
|
|
|
|
u32 battery_present:1;
|
|
|
|
u32 reserved:27;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Flags */
|
|
|
|
|
|
|
|
struct acpi_device_flags {
|
2005-08-05 12:44:28 +08:00
|
|
|
u32 dynamic_status:1;
|
|
|
|
u32 removable:1;
|
|
|
|
u32 ejectable:1;
|
|
|
|
u32 power_manageable:1;
|
2012-12-21 07:36:48 +08:00
|
|
|
u32 match_driver:1;
|
2013-08-29 03:41:07 +08:00
|
|
|
u32 reserved:27;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* File System */
|
|
|
|
|
|
|
|
struct acpi_device_dir {
|
2005-08-05 12:44:28 +08:00
|
|
|
struct proc_dir_entry *entry;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#define acpi_device_dir(d) ((d)->dir.entry)
|
|
|
|
|
|
|
|
/* Plug and Play */
|
|
|
|
|
2009-05-21 16:25:35 +08:00
|
|
|
typedef char acpi_bus_id[8];
|
2005-08-05 12:44:28 +08:00
|
|
|
typedef unsigned long acpi_bus_address;
|
|
|
|
typedef char acpi_device_name[40];
|
|
|
|
typedef char acpi_device_class[20];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-09-22 03:35:19 +08:00
|
|
|
struct acpi_hardware_id {
|
|
|
|
struct list_head list;
|
|
|
|
char *id;
|
|
|
|
};
|
|
|
|
|
2013-03-05 05:30:41 +08:00
|
|
|
struct acpi_pnp_type {
|
|
|
|
u32 hardware_id:1;
|
|
|
|
u32 bus_address:1;
|
|
|
|
u32 reserved:30;
|
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_device_pnp {
|
2013-03-05 05:30:41 +08:00
|
|
|
acpi_bus_id bus_id; /* Object name */
|
|
|
|
struct acpi_pnp_type type; /* ID type */
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_bus_address bus_address; /* _ADR */
|
2013-03-05 05:30:41 +08:00
|
|
|
char *unique_id; /* _UID */
|
2009-09-22 03:35:19 +08:00
|
|
|
struct list_head ids; /* _HID and _CIDs */
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_device_name device_name; /* Driver-determined */
|
|
|
|
acpi_device_class device_class; /* " */
|
2012-10-03 02:43:23 +08:00
|
|
|
union acpi_object *str_obj; /* unicode string for _STR method */
|
2012-11-16 09:56:59 +08:00
|
|
|
unsigned long sun; /* _SUN */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#define acpi_device_bid(d) ((d)->pnp.bus_id)
|
|
|
|
#define acpi_device_adr(d) ((d)->pnp.bus_address)
|
2010-10-01 16:54:00 +08:00
|
|
|
const char *acpi_device_hid(struct acpi_device *device);
|
2005-04-17 06:20:36 +08:00
|
|
|
#define acpi_device_name(d) ((d)->pnp.device_name)
|
|
|
|
#define acpi_device_class(d) ((d)->pnp.device_class)
|
|
|
|
|
|
|
|
/* Power Management */
|
|
|
|
|
|
|
|
struct acpi_device_power_flags {
|
2005-08-05 12:44:28 +08:00
|
|
|
u32 explicit_get:1; /* _PSC present? */
|
|
|
|
u32 power_resources:1; /* Power resources */
|
|
|
|
u32 inrush_current:1; /* Serialize Dx->D0 */
|
|
|
|
u32 power_removed:1; /* Optimize Dx->D0 */
|
|
|
|
u32 reserved:28;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct acpi_device_power_state {
|
|
|
|
struct {
|
2005-08-05 12:44:28 +08:00
|
|
|
u8 valid:1;
|
2012-11-22 06:33:40 +08:00
|
|
|
u8 os_accessible:1;
|
2005-08-05 12:44:28 +08:00
|
|
|
u8 explicit_set:1; /* _PSx present? */
|
|
|
|
u8 reserved:6;
|
|
|
|
} flags;
|
|
|
|
int power; /* % Power (compared to D0) */
|
|
|
|
int latency; /* Dx->D0 time (microseconds) */
|
2013-01-17 21:11:06 +08:00
|
|
|
struct list_head resources; /* Power resources referenced */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct acpi_device_power {
|
2005-08-05 12:44:28 +08:00
|
|
|
int state; /* Current state */
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_device_power_flags flags;
|
2011-06-01 23:54:02 +08:00
|
|
|
struct acpi_device_power_state states[ACPI_D_STATE_COUNT]; /* Power states (D0-D3Cold) */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Performance Management */
|
|
|
|
|
|
|
|
struct acpi_device_perf_flags {
|
2005-08-05 12:44:28 +08:00
|
|
|
u8 reserved:8;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct acpi_device_perf_state {
|
|
|
|
struct {
|
2005-08-05 12:44:28 +08:00
|
|
|
u8 valid:1;
|
|
|
|
u8 reserved:7;
|
|
|
|
} flags;
|
|
|
|
u8 power; /* % Power (compared to P0) */
|
|
|
|
u8 performance; /* % Performance ( " ) */
|
|
|
|
int latency; /* Px->P0 time (microseconds) */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct acpi_device_perf {
|
2005-08-05 12:44:28 +08:00
|
|
|
int state;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_device_perf_flags flags;
|
2005-08-05 12:44:28 +08:00
|
|
|
int state_count;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_device_perf_state *states;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Wakeup Management */
|
|
|
|
struct acpi_device_wakeup_flags {
|
2005-08-05 12:44:28 +08:00
|
|
|
u8 valid:1; /* Can successfully enable wakeup? */
|
|
|
|
u8 run_wake:1; /* Run-Wake GPE devices */
|
2010-02-18 06:44:09 +08:00
|
|
|
u8 notifier_present:1; /* Wake-up notify handler has been installed */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct acpi_device_wakeup {
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_handle gpe_device;
|
2010-01-28 10:53:19 +08:00
|
|
|
u64 gpe_number;
|
|
|
|
u64 sleep_state;
|
2013-01-17 21:11:06 +08:00
|
|
|
struct list_head resources;
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_device_wakeup_flags flags;
|
2009-09-09 05:15:31 +08:00
|
|
|
int prepare_count;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2012-08-17 14:44:09 +08:00
|
|
|
struct acpi_device_physical_node {
|
2013-08-06 20:32:54 +08:00
|
|
|
unsigned int node_id;
|
2012-08-17 14:44:09 +08:00
|
|
|
struct list_head node;
|
|
|
|
struct device *dev;
|
2013-05-03 06:26:16 +08:00
|
|
|
bool put_online:1;
|
2012-08-17 14:44:09 +08:00
|
|
|
};
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-08-17 14:44:09 +08:00
|
|
|
/* Device */
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_device {
|
2009-09-22 03:29:10 +08:00
|
|
|
int device_type;
|
|
|
|
acpi_handle handle; /* no handle for fixed hardware */
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_device *parent;
|
|
|
|
struct list_head children;
|
|
|
|
struct list_head node;
|
|
|
|
struct list_head wakeup_list;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_device_status status;
|
|
|
|
struct acpi_device_flags flags;
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_device_pnp pnp;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_device_power power;
|
|
|
|
struct acpi_device_wakeup wakeup;
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_device_perf performance;
|
|
|
|
struct acpi_device_dir dir;
|
2013-01-30 21:27:29 +08:00
|
|
|
struct acpi_scan_handler *handler;
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_driver *driver;
|
|
|
|
void *driver_data;
|
2006-05-10 22:33:00 +08:00
|
|
|
struct device dev;
|
2013-08-06 20:32:54 +08:00
|
|
|
unsigned int physical_node_count;
|
2012-08-17 14:44:09 +08:00
|
|
|
struct list_head physical_node_list;
|
|
|
|
struct mutex physical_node_lock;
|
2013-01-24 19:50:09 +08:00
|
|
|
void (*remove)(struct acpi_device *);
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2008-09-23 05:37:34 +08:00
|
|
|
static inline void *acpi_driver_data(struct acpi_device *d)
|
|
|
|
{
|
|
|
|
return d->driver_data;
|
|
|
|
}
|
|
|
|
|
2006-12-07 20:56:23 +08:00
|
|
|
#define to_acpi_device(d) container_of(d, struct acpi_device, dev)
|
|
|
|
#define to_acpi_driver(d) container_of(d, struct acpi_driver, drv)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-08 15:28:35 +08:00
|
|
|
/* acpi_device.dev.bus == &acpi_bus_type */
|
|
|
|
extern struct bus_type acpi_bus_type;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Events
|
|
|
|
* ------
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct acpi_bus_event {
|
2005-08-05 12:44:28 +08:00
|
|
|
struct list_head node;
|
|
|
|
acpi_device_class device_class;
|
|
|
|
acpi_bus_id bus_id;
|
|
|
|
u32 type;
|
|
|
|
u32 data;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2012-05-24 10:25:20 +08:00
|
|
|
struct acpi_eject_event {
|
2013-01-12 06:40:41 +08:00
|
|
|
struct acpi_device *device;
|
2012-05-24 10:25:20 +08:00
|
|
|
u32 event;
|
|
|
|
};
|
|
|
|
|
2013-01-22 05:20:47 +08:00
|
|
|
struct acpi_hp_work {
|
|
|
|
struct work_struct work;
|
|
|
|
acpi_handle handle;
|
|
|
|
u32 type;
|
|
|
|
void *context;
|
|
|
|
};
|
|
|
|
void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
|
|
|
|
void (*func)(struct work_struct *work));
|
|
|
|
|
2007-11-03 07:19:59 +08:00
|
|
|
extern struct kobject *acpi_kobj;
|
2007-08-23 01:24:31 +08:00
|
|
|
extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
|
2009-06-29 13:43:27 +08:00
|
|
|
void acpi_bus_private_data_handler(acpi_handle, void *);
|
2008-01-17 15:51:21 +08:00
|
|
|
int acpi_bus_get_private_data(acpi_handle, void **);
|
2008-01-25 14:48:06 +08:00
|
|
|
extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
|
|
|
|
extern int register_acpi_notifier(struct notifier_block *);
|
|
|
|
extern int unregister_acpi_notifier(struct notifier_block *);
|
2008-08-28 10:04:29 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* External Functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
|
2009-09-22 03:30:01 +08:00
|
|
|
acpi_status acpi_bus_get_status_handle(acpi_handle handle,
|
|
|
|
unsigned long long *sta);
|
2005-08-05 12:44:28 +08:00
|
|
|
int acpi_bus_get_status(struct acpi_device *device);
|
2013-01-17 21:11:08 +08:00
|
|
|
|
2005-08-05 12:44:28 +08:00
|
|
|
int acpi_bus_set_power(acpi_handle handle, int state);
|
2013-01-17 21:11:08 +08:00
|
|
|
const char *acpi_power_state_string(int state);
|
2013-01-17 21:11:08 +08:00
|
|
|
int acpi_device_get_power(struct acpi_device *device, int *state);
|
2012-11-02 08:40:45 +08:00
|
|
|
int acpi_device_set_power(struct acpi_device *device, int state);
|
2013-01-17 21:11:08 +08:00
|
|
|
int acpi_bus_init_power(struct acpi_device *device);
|
2013-06-19 06:45:34 +08:00
|
|
|
int acpi_device_fix_up_power(struct acpi_device *device);
|
2010-11-25 07:09:15 +08:00
|
|
|
int acpi_bus_update_power(acpi_handle handle, int *state_p);
|
2008-07-07 09:30:55 +08:00
|
|
|
bool acpi_bus_power_manageable(acpi_handle handle);
|
2013-05-17 04:29:28 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_PM
|
2008-07-07 09:34:48 +08:00
|
|
|
bool acpi_bus_can_wakeup(acpi_handle handle);
|
2013-05-17 04:29:28 +08:00
|
|
|
#else
|
|
|
|
static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; }
|
|
|
|
#endif
|
2013-01-17 21:11:08 +08:00
|
|
|
|
ACPI / hotplug: Fix concurrency issues and memory leaks
This changeset is aimed at fixing a few different but related
problems in the ACPI hotplug infrastructure.
First of all, since notify handlers may be run in parallel with
acpi_bus_scan(), acpi_bus_trim() and acpi_bus_hot_remove_device()
and some of them are installed for ACPI handles that have no struct
acpi_device objects attached (i.e. before those objects are created),
those notify handlers have to take acpi_scan_lock to prevent races
from taking place (e.g. a struct acpi_device is found to be present
for the given ACPI handle, but right after that it is removed by
acpi_bus_trim() running in parallel to the given notify handler).
Moreover, since some of them call acpi_bus_scan() and
acpi_bus_trim(), this leads to the conclusion that acpi_scan_lock
should be acquired by the callers of these two funtions rather by
these functions themselves.
For these reasons, make all notify handlers that can handle device
addition and eject events take acpi_scan_lock and remove the
acpi_scan_lock locking from acpi_bus_scan() and acpi_bus_trim().
Accordingly, update all of their users to make sure that they
are always called under acpi_scan_lock.
Furthermore, since eject operations are carried out asynchronously
with respect to the notify events that trigger them, with the help
of acpi_bus_hot_remove_device(), even if notify handlers take the
ACPI scan lock, it still is possible that, for example,
acpi_bus_trim() will run between acpi_bus_hot_remove_device() and
the notify handler that scheduled its execution and that
acpi_bus_trim() will remove the device node passed to
acpi_bus_hot_remove_device() for ejection. In that case, the struct
acpi_device object obtained by acpi_bus_hot_remove_device() will be
invalid and not-so-funny things will ensue. To protect agaist that,
make the users of acpi_bus_hot_remove_device() run get_device() on
ACPI device node objects that are about to be passed to it and make
acpi_bus_hot_remove_device() run put_device() on them and check if
their ACPI handles are not NULL (make acpi_device_unregister() clear
the device nodes' ACPI handles for that check to work).
Finally, observe that acpi_os_hotplug_execute() actually can fail,
in which case its caller ought to free memory allocated for the
context object to prevent leaks from happening. It also needs to
run put_device() on the device node that it ran get_device() on
previously in that case. Modify the code accordingly.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Yinghai Lu <yinghai@kernel.org>
2013-02-13 21:36:47 +08:00
|
|
|
void acpi_scan_lock_acquire(void);
|
|
|
|
void acpi_scan_lock_release(void);
|
2013-01-30 21:27:29 +08:00
|
|
|
int acpi_scan_add_handler(struct acpi_scan_handler *handler);
|
2005-08-05 12:44:28 +08:00
|
|
|
int acpi_bus_register_driver(struct acpi_driver *driver);
|
2006-04-27 17:25:00 +08:00
|
|
|
void acpi_bus_unregister_driver(struct acpi_driver *driver);
|
2013-01-19 08:27:35 +08:00
|
|
|
int acpi_bus_scan(acpi_handle handle);
|
2012-05-24 10:25:20 +08:00
|
|
|
void acpi_bus_hot_remove_device(void *context);
|
2013-01-26 07:27:44 +08:00
|
|
|
void acpi_bus_trim(struct acpi_device *start);
|
2007-05-10 11:34:35 +08:00
|
|
|
acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
|
2007-07-23 20:43:32 +08:00
|
|
|
int acpi_match_device_ids(struct acpi_device *device,
|
|
|
|
const struct acpi_device_id *ids);
|
2005-04-17 06:20:36 +08:00
|
|
|
int acpi_create_dir(struct acpi_device *);
|
|
|
|
void acpi_remove_dir(struct acpi_device *);
|
|
|
|
|
2012-09-07 15:31:38 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver
|
|
|
|
* @__acpi_driver: acpi_driver struct
|
|
|
|
*
|
|
|
|
* Helper macro for ACPI drivers which do not do anything special in module
|
|
|
|
* init/exit. This eliminates a lot of boilerplate. Each module may only
|
|
|
|
* use this macro once, and calling it replaces module_init() and module_exit()
|
|
|
|
*/
|
|
|
|
#define module_acpi_driver(__acpi_driver) \
|
|
|
|
module_driver(__acpi_driver, acpi_bus_register_driver, \
|
|
|
|
acpi_bus_unregister_driver)
|
|
|
|
|
2005-03-19 07:45:35 +08:00
|
|
|
/*
|
|
|
|
* Bind physical devices with ACPI devices
|
|
|
|
*/
|
|
|
|
struct acpi_bus_type {
|
2005-08-05 12:44:28 +08:00
|
|
|
struct list_head list;
|
2013-03-04 05:35:20 +08:00
|
|
|
const char *name;
|
|
|
|
bool (*match)(struct device *dev);
|
2005-08-05 12:44:28 +08:00
|
|
|
int (*find_device) (struct device *, acpi_handle *);
|
2012-12-23 07:02:13 +08:00
|
|
|
void (*setup)(struct device *);
|
|
|
|
void (*cleanup)(struct device *);
|
2005-03-19 07:45:35 +08:00
|
|
|
};
|
|
|
|
int register_acpi_bus_type(struct acpi_bus_type *);
|
|
|
|
int unregister_acpi_bus_type(struct acpi_bus_type *);
|
2008-08-01 23:37:54 +08:00
|
|
|
|
2009-07-24 07:03:00 +08:00
|
|
|
struct acpi_pci_root {
|
|
|
|
struct acpi_device * device;
|
|
|
|
struct pci_bus *bus;
|
|
|
|
u16 segment;
|
2010-03-12 03:20:06 +08:00
|
|
|
struct resource secondary; /* downstream bus range */
|
2009-07-24 07:03:00 +08:00
|
|
|
|
|
|
|
u32 osc_support_set; /* _OSC state of support bits */
|
|
|
|
u32 osc_control_set; /* _OSC state of control bits */
|
2012-06-22 14:55:16 +08:00
|
|
|
phys_addr_t mcfg_addr;
|
2009-07-24 07:03:00 +08:00
|
|
|
};
|
|
|
|
|
2005-03-19 07:45:35 +08:00
|
|
|
/* helper */
|
ACPI: Try harder to resolve _ADR collisions for bridges
In theory, under a given ACPI namespace node there should be only
one child device object with _ADR whose value matches a given bus
address exactly. In practice, however, there are systems in which
multiple child device objects under a given parent have _ADR matching
exactly the same address. In those cases we use _STA to determine
which of the multiple matching devices is enabled, since some systems
are known to indicate which ACPI device object to associate with the
given physical (usually PCI) device this way.
Unfortunately, as it turns out, there are systems in which many
device objects under the same parent have _ADR matching exactly the
same bus address and none of them has _STA, in which case they all
should be regarded as enabled according to the spec. Still, if
those device objects are supposed to represent bridges (e.g. this
is the case for device objects corresponding to PCIe ports), we can
try harder and skip the ones that have no child device objects in the
ACPI namespace. With luck, we can avoid using device objects that we
are not expected to use this way.
Although this only works for bridges whose children also have ACPI
namespace representation, it is sufficient to address graphics
adapter detection issues on some systems, so rework the code finding
a matching device ACPI handle for a given bus address to implement
this idea.
Introduce a new function, acpi_find_child(), taking three arguments:
the ACPI handle of the device's parent, a bus address suitable for
the device's bus type and a bool indicating if the device is a
bridge and make it work as outlined above. Reimplement the function
currently used for this purpose, acpi_get_child(), as a call to
acpi_find_child() with the last argument set to 'false' and make
the PCI subsystem use acpi_find_child() with the bridge information
passed as the last argument to it. [Lan Tianyu notices that it is
not sufficient to use pci_is_bridge() for that, because the device's
subordinate pointer hasn't been set yet at this point, so use
hdr_type instead.]
This change fixes a regression introduced inadvertently by commit
33f767d (ACPI: Rework acpi_get_child() to be more efficient) which
overlooked the fact that for acpi_walk_namespace() "post-order" means
"after all children have been visited" rather than "on the way back",
so for device objects without children and for namespace walks of
depth 1, as in the acpi_get_child() case, the "post-order" callbacks
ordering is actually the same as the ordering of "pre-order" ones.
Since that commit changed the namespace walk in acpi_get_child() to
terminate after finding the first matching object instead of going
through all of them and returning the last one, it effectively
changed the result returned by that function in some rare cases and
that led to problems (the switch from a "pre-order" to a "post-order"
callback was supposed to prevent that from happening, but it was
ineffective).
As it turns out, the systems where the change made by commit
33f767d actually matters are those where there are multiple ACPI
device objects representing the same PCIe port (which effectively
is a bridge). Moreover, only one of them, and the one we are
expected to use, has child device objects in the ACPI namespace,
so the regression can be addressed as described above.
References: https://bugzilla.kernel.org/show_bug.cgi?id=60561
Reported-by: Peter Wu <lekensteyn@gmail.com>
Tested-by: Vladimir Lalov <mail@vlalov.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: 3.9+ <stable@vger.kernel.org> # 3.9+
2013-08-08 04:55:00 +08:00
|
|
|
acpi_handle acpi_find_child(acpi_handle, u64, bool);
|
|
|
|
static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr)
|
|
|
|
{
|
|
|
|
return acpi_find_child(handle, addr, false);
|
|
|
|
}
|
2009-06-11 03:55:14 +08:00
|
|
|
int acpi_is_root_bridge(acpi_handle);
|
2009-07-24 07:03:00 +08:00
|
|
|
struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
|
2012-11-21 07:21:50 +08:00
|
|
|
#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev))
|
2005-03-19 07:45:35 +08:00
|
|
|
|
2010-02-18 06:44:09 +08:00
|
|
|
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
|
|
|
|
int acpi_disable_wakeup_device_power(struct acpi_device *dev);
|
|
|
|
|
2011-02-11 07:06:54 +08:00
|
|
|
#ifdef CONFIG_PM
|
2012-11-02 08:40:09 +08:00
|
|
|
acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
|
|
|
|
acpi_notify_handler handler, void *context);
|
|
|
|
acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
|
|
|
|
acpi_notify_handler handler);
|
2012-06-23 10:23:48 +08:00
|
|
|
int acpi_pm_device_sleep_state(struct device *, int *, int);
|
2010-10-15 05:24:13 +08:00
|
|
|
#else
|
2012-11-02 08:40:09 +08:00
|
|
|
static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
|
|
|
|
acpi_notify_handler handler,
|
|
|
|
void *context)
|
|
|
|
{
|
|
|
|
return AE_SUPPORT;
|
|
|
|
}
|
|
|
|
static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
|
|
|
|
acpi_notify_handler handler)
|
|
|
|
{
|
|
|
|
return AE_SUPPORT;
|
|
|
|
}
|
2013-06-16 06:37:42 +08:00
|
|
|
static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
|
2007-07-30 05:27:18 +08:00
|
|
|
{
|
|
|
|
if (p)
|
|
|
|
*p = ACPI_STATE_D0;
|
2013-06-16 06:37:42 +08:00
|
|
|
|
2013-07-30 20:36:20 +08:00
|
|
|
return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ?
|
|
|
|
m : ACPI_STATE_D0;
|
2007-07-30 05:27:18 +08:00
|
|
|
}
|
2010-10-15 05:24:13 +08:00
|
|
|
#endif
|
|
|
|
|
2012-10-26 19:40:04 +08:00
|
|
|
#ifdef CONFIG_PM_RUNTIME
|
ACPI / PM: Split device wakeup management routines
Two device wakeup management routines in device_pm.c and sleep.c,
acpi_pm_device_run_wake() and acpi_pm_device_sleep_wake(), take a
device pointer argument and use it to obtain the ACPI handle of the
corresponding ACPI namespace node. That handle is then used to get
the address of the struct acpi_device object corresponding to the
struct device passed as the argument.
Unfortunately, that last operation may be costly, because it involves
taking the global ACPI namespace mutex, so it shouldn't be carried
out too often. However, the callers of those routines usually call
them in a row with acpi_pm_device_sleep_state() which also takes that
mutex for the same reason, so it would be more efficient if they ran
acpi_bus_get_device() themselves to obtain a pointer to the struct
acpi_device object in question and then passed that pointer to the
appropriate PM routines.
To make that possible, split each of the PM routines mentioned above
in two parts, one taking a struct acpi_device pointer argument and
the other implementing the current interface for compatibility.
Additionally, change acpi_pm_device_run_wake() to actually return
an error code if there is an error while setting up runtime remote
wakeup for the device.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2012-11-02 08:40:36 +08:00
|
|
|
int __acpi_device_run_wake(struct acpi_device *, bool);
|
2012-03-27 15:43:25 +08:00
|
|
|
int acpi_pm_device_run_wake(struct device *, bool);
|
2010-10-15 05:24:13 +08:00
|
|
|
#else
|
ACPI / PM: Split device wakeup management routines
Two device wakeup management routines in device_pm.c and sleep.c,
acpi_pm_device_run_wake() and acpi_pm_device_sleep_wake(), take a
device pointer argument and use it to obtain the ACPI handle of the
corresponding ACPI namespace node. That handle is then used to get
the address of the struct acpi_device object corresponding to the
struct device passed as the argument.
Unfortunately, that last operation may be costly, because it involves
taking the global ACPI namespace mutex, so it shouldn't be carried
out too often. However, the callers of those routines usually call
them in a row with acpi_pm_device_sleep_state() which also takes that
mutex for the same reason, so it would be more efficient if they ran
acpi_bus_get_device() themselves to obtain a pointer to the struct
acpi_device object in question and then passed that pointer to the
appropriate PM routines.
To make that possible, split each of the PM routines mentioned above
in two parts, one taking a struct acpi_device pointer argument and
the other implementing the current interface for compatibility.
Additionally, change acpi_pm_device_run_wake() to actually return
an error code if there is an error while setting up runtime remote
wakeup for the device.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2012-11-02 08:40:36 +08:00
|
|
|
static inline int __acpi_device_run_wake(struct acpi_device *adev, bool en)
|
|
|
|
{
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2012-03-27 15:43:25 +08:00
|
|
|
static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
|
|
|
|
{
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2012-10-26 19:40:04 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
ACPI / PM: Split device wakeup management routines
Two device wakeup management routines in device_pm.c and sleep.c,
acpi_pm_device_run_wake() and acpi_pm_device_sleep_wake(), take a
device pointer argument and use it to obtain the ACPI handle of the
corresponding ACPI namespace node. That handle is then used to get
the address of the struct acpi_device object corresponding to the
struct device passed as the argument.
Unfortunately, that last operation may be costly, because it involves
taking the global ACPI namespace mutex, so it shouldn't be carried
out too often. However, the callers of those routines usually call
them in a row with acpi_pm_device_sleep_state() which also takes that
mutex for the same reason, so it would be more efficient if they ran
acpi_bus_get_device() themselves to obtain a pointer to the struct
acpi_device object in question and then passed that pointer to the
appropriate PM routines.
To make that possible, split each of the PM routines mentioned above
in two parts, one taking a struct acpi_device pointer argument and
the other implementing the current interface for compatibility.
Additionally, change acpi_pm_device_run_wake() to actually return
an error code if there is an error while setting up runtime remote
wakeup for the device.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2012-11-02 08:40:36 +08:00
|
|
|
int __acpi_device_sleep_wake(struct acpi_device *, u32, bool);
|
2012-10-26 19:40:04 +08:00
|
|
|
int acpi_pm_device_sleep_wake(struct device *, bool);
|
|
|
|
#else
|
ACPI / PM: Split device wakeup management routines
Two device wakeup management routines in device_pm.c and sleep.c,
acpi_pm_device_run_wake() and acpi_pm_device_sleep_wake(), take a
device pointer argument and use it to obtain the ACPI handle of the
corresponding ACPI namespace node. That handle is then used to get
the address of the struct acpi_device object corresponding to the
struct device passed as the argument.
Unfortunately, that last operation may be costly, because it involves
taking the global ACPI namespace mutex, so it shouldn't be carried
out too often. However, the callers of those routines usually call
them in a row with acpi_pm_device_sleep_state() which also takes that
mutex for the same reason, so it would be more efficient if they ran
acpi_bus_get_device() themselves to obtain a pointer to the struct
acpi_device object in question and then passed that pointer to the
appropriate PM routines.
To make that possible, split each of the PM routines mentioned above
in two parts, one taking a struct acpi_device pointer argument and
the other implementing the current interface for compatibility.
Additionally, change acpi_pm_device_run_wake() to actually return
an error code if there is an error while setting up runtime remote
wakeup for the device.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2012-11-02 08:40:36 +08:00
|
|
|
static inline int __acpi_device_sleep_wake(struct acpi_device *adev,
|
|
|
|
u32 target_state, bool enable)
|
|
|
|
{
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2008-07-08 22:00:54 +08:00
|
|
|
static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
|
|
|
|
{
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2010-10-15 05:24:13 +08:00
|
|
|
#endif
|
2007-07-18 04:40:25 +08:00
|
|
|
|
2012-11-11 05:48:33 +08:00
|
|
|
#ifdef CONFIG_ACPI_SLEEP
|
|
|
|
u32 acpi_target_system_state(void);
|
|
|
|
#else
|
|
|
|
static inline u32 acpi_target_system_state(void) { return ACPI_STATE_S0; }
|
|
|
|
#endif
|
|
|
|
|
2012-11-02 08:40:45 +08:00
|
|
|
static inline bool acpi_device_power_manageable(struct acpi_device *adev)
|
|
|
|
{
|
|
|
|
return adev->flags.power_manageable;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool acpi_device_can_wakeup(struct acpi_device *adev)
|
|
|
|
{
|
|
|
|
return adev->wakeup.flags.valid;
|
|
|
|
}
|
|
|
|
|
2012-11-22 06:33:40 +08:00
|
|
|
static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
|
|
|
|
{
|
|
|
|
return adev->power.states[ACPI_STATE_D3_COLD].flags.os_accessible;
|
|
|
|
}
|
|
|
|
|
2012-05-11 16:08:25 +08:00
|
|
|
#else /* CONFIG_ACPI */
|
|
|
|
|
2012-06-04 12:29:11 +08:00
|
|
|
static inline int register_acpi_bus_type(void *bus) { return 0; }
|
|
|
|
static inline int unregister_acpi_bus_type(void *bus) { return 0; }
|
2012-05-11 16:08:25 +08:00
|
|
|
|
2007-05-10 11:34:35 +08:00
|
|
|
#endif /* CONFIG_ACPI */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#endif /*__ACPI_BUS_H__*/
|