1/* 2 * Link physical devices with ACPI devices support 3 * 4 * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com> 5 * Copyright (c) 2005 Intel Corp. 6 * 7 * This file is released under the GPLv2. 8 */ 9#include <linux/init.h> 10#include <linux/list.h> 11#include <linux/device.h> 12#include <linux/rwsem.h> 13#include <linux/acpi.h> 14 15#define ACPI_GLUE_DEBUG 0 16#if ACPI_GLUE_DEBUG 17#define DBG(x...) printk(PREFIX x) 18#else 19#define DBG(x...) 20#endif 21static LIST_HEAD(bus_type_list); 22static DECLARE_RWSEM(bus_type_sem); 23 24int register_acpi_bus_type(struct acpi_bus_type *type) 25{ 26 if (acpi_disabled) 27 return -ENODEV; 28 if (type && type->bus && type->find_device) { 29 down_write(&bus_type_sem); 30 list_add_tail(&type->list, &bus_type_list); 31 up_write(&bus_type_sem); 32 printk(KERN_INFO PREFIX "bus type %s registered\n", 33 type->bus->name); 34 return 0; 35 } 36 return -ENODEV; 37} 38 39EXPORT_SYMBOL(register_acpi_bus_type); 40 41int unregister_acpi_bus_type(struct acpi_bus_type *type) 42{ 43 if (acpi_disabled) 44 return 0; 45 if (type) { 46 down_write(&bus_type_sem); 47 list_del_init(&type->list); 48 up_write(&bus_type_sem); 49 printk(KERN_INFO PREFIX "ACPI bus type %s unregistered\n", 50 type->bus->name); 51 return 0; 52 } 53 return -ENODEV; 54} 55 56EXPORT_SYMBOL(unregister_acpi_bus_type); 57 58static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) 59{ 60 struct acpi_bus_type *tmp, *ret = NULL; 61 62 down_read(&bus_type_sem); 63 list_for_each_entry(tmp, &bus_type_list, list) { 64 if (tmp->bus == type) { 65 ret = tmp; 66 break; 67 } 68 } 69 up_read(&bus_type_sem); 70 return ret; 71} 72 73static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) 74{ 75 struct acpi_bus_type *tmp; 76 int ret = -ENODEV; 77 78 down_read(&bus_type_sem); 79 list_for_each_entry(tmp, &bus_type_list, list) { 80 if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) { 81 ret = 0; 82 break; 83 } 84 } 85 up_read(&bus_type_sem); 86 return ret; 87} 88 89/* Get device's handler per its address under its parent */ 90struct acpi_find_child { 91 acpi_handle handle; 92 acpi_integer address; 93}; 94 95static acpi_status 96do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) 97{ 98 acpi_status status; 99 struct acpi_device_info *info; 100 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 101 struct acpi_find_child *find = context; 102 103 status = acpi_get_object_info(handle, &buffer); 104 if (ACPI_SUCCESS(status)) { 105 info = buffer.pointer; 106 if (info->address == find->address) 107 find->handle = handle; 108 kfree(buffer.pointer); 109 } 110 return AE_OK; 111} 112 113acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address) 114{ 115 struct acpi_find_child find = { NULL, address }; 116 117 if (!parent) 118 return NULL; 119 acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 120 1, do_acpi_find_child, &find, NULL); 121 return find.handle; 122} 123 124EXPORT_SYMBOL(acpi_get_child); 125 126/* Link ACPI devices with physical devices */ 127static void acpi_glue_data_handler(acpi_handle handle, 128 u32 function, void *context) 129{ 130 /* we provide an empty handler */ 131} 132 133/* Note: a success call will increase reference count by one */ 134struct device *acpi_get_physical_device(acpi_handle handle) 135{ 136 acpi_status status; 137 struct device *dev; 138 139 status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev); 140 if (ACPI_SUCCESS(status)) 141 return get_device(dev); 142 return NULL; 143} 144 145EXPORT_SYMBOL(acpi_get_physical_device); 146 147static int acpi_bind_one(struct device *dev, acpi_handle handle) 148{ 149 acpi_status status; 150 151 if (dev->archdata.acpi_handle) { 152 printk(KERN_WARNING PREFIX 153 "Drivers changed 'acpi_handle' for %s\n", dev->bus_id); 154 return -EINVAL; 155 } 156 get_device(dev); 157 status = acpi_attach_data(handle, acpi_glue_data_handler, dev); 158 if (ACPI_FAILURE(status)) { 159 put_device(dev); 160 return -EINVAL; 161 } 162 dev->archdata.acpi_handle = handle; 163 164 return 0; 165} 166 167static int acpi_unbind_one(struct device *dev) 168{ 169 if (!dev->archdata.acpi_handle) 170 return 0; 171 if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { 172 /* acpi_get_physical_device increase refcnt by one */ 173 put_device(dev); 174 acpi_detach_data(dev->archdata.acpi_handle, 175 acpi_glue_data_handler); 176 dev->archdata.acpi_handle = NULL; 177 /* acpi_bind_one increase refcnt by one */ 178 put_device(dev); 179 } else { 180 printk(KERN_ERR PREFIX 181 "Oops, 'acpi_handle' corrupt for %s\n", dev->bus_id); 182 } 183 return 0; 184} 185 186static int acpi_platform_notify(struct device *dev) 187{ 188 struct acpi_bus_type *type; 189 acpi_handle handle; 190 int ret = -EINVAL; 191 192 if (!dev->bus || !dev->parent) { 193 /* bridge devices genernally haven't bus or parent */ 194 ret = acpi_find_bridge_device(dev, &handle); 195 goto end; 196 } 197 type = acpi_get_bus_type(dev->bus); 198 if (!type) { 199 DBG("No ACPI bus support for %s\n", dev->bus_id); 200 ret = -EINVAL; 201 goto end; 202 } 203 if ((ret = type->find_device(dev, &handle)) != 0) 204 DBG("Can't get handler for %s\n", dev->bus_id); 205 end: 206 if (!ret) 207 acpi_bind_one(dev, handle); 208 209#if ACPI_GLUE_DEBUG 210 if (!ret) { 211 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 212 213 acpi_get_name(dev->archdata.acpi_handle, 214 ACPI_FULL_PATHNAME, &buffer); 215 DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); 216 kfree(buffer.pointer); 217 } else 218 DBG("Device %s -> No ACPI support\n", dev->bus_id); 219#endif 220 221 return ret; 222} 223 224static int acpi_platform_notify_remove(struct device *dev) 225{ 226 acpi_unbind_one(dev); 227 return 0; 228} 229 230static int __init init_acpi_device_notify(void) 231{ 232 if (acpi_disabled) 233 return 0; 234 if (platform_notify || platform_notify_remove) { 235 printk(KERN_ERR PREFIX "Can't use platform_notify\n"); 236 return 0; 237 } 238 platform_notify = acpi_platform_notify; 239 platform_notify_remove = acpi_platform_notify_remove; 240 return 0; 241} 242 243arch_initcall(init_acpi_device_notify); 244 245 246#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) 247 248#ifdef CONFIG_PM 249static u32 rtc_handler(void *context) 250{ 251 acpi_clear_event(ACPI_EVENT_RTC); 252 acpi_disable_event(ACPI_EVENT_RTC, 0); 253 return ACPI_INTERRUPT_HANDLED; 254} 255 256static inline void rtc_wake_setup(void) 257{ 258 acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); 259} 260 261static void rtc_wake_on(struct device *dev) 262{ 263 acpi_clear_event(ACPI_EVENT_RTC); 264 acpi_enable_event(ACPI_EVENT_RTC, 0); 265} 266 267static void rtc_wake_off(struct device *dev) 268{ 269 acpi_disable_event(ACPI_EVENT_RTC, 0); 270} 271#else 272#define rtc_wake_setup() do{}while(0) 273#define rtc_wake_on NULL 274#define rtc_wake_off NULL 275#endif 276 277/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find 278 * its device node and pass extra config data. This helps its driver use 279 * capabilities that the now-obsolete mc146818 didn't have, and informs it 280 * that this board's RTC is wakeup-capable (per ACPI spec). 281 */ 282#include <linux/mc146818rtc.h> 283 284static struct cmos_rtc_board_info rtc_info; 285 286 287/* PNP devices are registered in a subsys_initcall(); 288 * ACPI specifies the PNP IDs to use. 289 */ 290#include <linux/pnp.h> 291 292static int __init pnp_match(struct device *dev, void *data) 293{ 294 static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", }; 295 struct pnp_dev *pnp = to_pnp_dev(dev); 296 int i; 297 298 for (i = 0; i < ARRAY_SIZE(ids); i++) { 299 if (compare_pnp_id(pnp->id, ids[i]) != 0) 300 return 1; 301 } 302 return 0; 303} 304 305static struct device *__init get_rtc_dev(void) 306{ 307 return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match); 308} 309 310static int __init acpi_rtc_init(void) 311{ 312 struct device *dev = get_rtc_dev(); 313 314 if (dev) { 315 rtc_wake_setup(); 316 rtc_info.wake_on = rtc_wake_on; 317 rtc_info.wake_off = rtc_wake_off; 318 319 if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) { 320 DBG("bogus FADT month_alarm\n"); 321 acpi_gbl_FADT.month_alarm = 0; 322 } 323 324 rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm; 325 rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm; 326 rtc_info.rtc_century = acpi_gbl_FADT.century; 327 328 /* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */ 329 if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE) 330 printk(PREFIX "RTC can wake from S4\n"); 331 332 333 dev->platform_data = &rtc_info; 334 335 /* RTC always wakes from S1/S2/S3, and often S4/STD */ 336 device_init_wakeup(dev, 1); 337 338 put_device(dev); 339 } else 340 DBG("RTC unavailable?\n"); 341 return 0; 342} 343/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */ 344fs_initcall(acpi_rtc_init); 345 346#endif 347