cregit-Linux how code gets into the kernel

Release 4.14 drivers/acpi/glue.c

Directory: drivers/acpi
/*
 * Link physical devices with ACPI devices support
 *
 * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>
 * Copyright (c) 2005 Intel Corp.
 *
 * This file is released under the GPLv2.
 */

#include <linux/acpi_iort.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/rwsem.h>
#include <linux/acpi.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>

#include "internal.h"


#define ACPI_GLUE_DEBUG	0
#if ACPI_GLUE_DEBUG

#define DBG(fmt, ...)						\
	printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__)
#else

#define DBG(fmt, ...)						\
do {                                                            \
        if (0)                                                  \
                printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__);   \
} while (0)
#endif
static LIST_HEAD(bus_type_list);
static DECLARE_RWSEM(bus_type_sem);


#define PHYSICAL_NODE_STRING "physical_node"

#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)


int register_acpi_bus_type(struct acpi_bus_type *type) { if (acpi_disabled) return -ENODEV; if (type && type->match && type->find_companion) { down_write(&bus_type_sem); list_add_tail(&type->list, &bus_type_list); up_write(&bus_type_sem); printk(KERN_INFO PREFIX "bus type %s registered\n", type->name); return 0; } return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
David Shaohua Li6795.71%250.00%
Rafael J. Wysocki34.29%250.00%
Total70100.00%4100.00%

EXPORT_SYMBOL_GPL(register_acpi_bus_type);
int unregister_acpi_bus_type(struct acpi_bus_type *type) { if (acpi_disabled) return 0; if (type) { down_write(&bus_type_sem); list_del_init(&type->list); up_write(&bus_type_sem); printk(KERN_INFO PREFIX "bus type %s unregistered\n", type->name); return 0; } return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
David Shaohua Li5696.55%266.67%
Rafael J. Wysocki23.45%133.33%
Total58100.00%3100.00%

EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) { struct acpi_bus_type *tmp, *ret = NULL; down_read(&bus_type_sem); list_for_each_entry(tmp, &bus_type_list, list) { if (tmp->match(dev)) { ret = tmp; break; } } up_read(&bus_type_sem); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
David Shaohua Li5890.62%150.00%
Rafael J. Wysocki69.38%150.00%
Total64100.00%2100.00%

#define FIND_CHILD_MIN_SCORE 1 #define FIND_CHILD_MAX_SCORE 2
static int find_child_checks(struct acpi_device *adev, bool check_children) { bool sta_present = true; unsigned long long sta; acpi_status status; status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); if (status == AE_NOT_FOUND) sta_present = false; else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) return -ENODEV; if (check_children && list_empty(&adev->children)) return -ENODEV; /* * If the device has a _HID returning a valid ACPI/PNP device ID, it is * better to make it look less attractive here, so that the other device * with the same _ADR value (that may not have a valid device ID) can be * matched going forward. [This means a second spec violation in a row, * so whatever we do here is best effort anyway.] */ return sta_present && !adev->pnp.type.platform_id ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki9792.38%675.00%
David Shaohua Li76.67%112.50%
Jeff Wu10.95%112.50%
Total105100.00%8100.00%


struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children) { struct acpi_device *adev, *ret = NULL; int ret_score = 0; if (!parent) return NULL; list_for_each_entry(adev, &parent->children, node) { unsigned long long addr; acpi_status status; int score; status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR, NULL, &addr); if (ACPI_FAILURE(status) || addr != address) continue; if (!ret) { /* This is the first matching object. Save it. */ ret = adev; continue; } /* * There is more than one matching device object with the same * _ADR value. That really is unexpected, so we are kind of * beyond the scope of the spec here. We have to choose which * one to return, though. * * First, check if the previously found object is good enough * and return it if so. Second, do the same for the object that * we've just found. */ if (!ret_score) { ret_score = find_child_checks(ret, check_children); if (ret_score == FIND_CHILD_MAX_SCORE) return ret; } score = find_child_checks(adev, check_children); if (score == FIND_CHILD_MAX_SCORE) { return adev; } else if (score > ret_score) { ret = adev; ret_score = score; } } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki14585.80%571.43%
David Shaohua Li1810.65%114.29%
Jeff Wu63.55%114.29%
Total169100.00%7100.00%

EXPORT_SYMBOL_GPL(acpi_find_child_device);
static void acpi_physnode_link_name(char *buf, unsigned int node_id) { if (node_id > 0) snprintf(buf, PHYSICAL_NODE_NAME_SIZE, PHYSICAL_NODE_STRING "%u", node_id); else strcpy(buf, PHYSICAL_NODE_STRING); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki40100.00%1100.00%
Total40100.00%1100.00%


int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) { struct acpi_device_physical_node *physical_node, *pn; char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; struct list_head *physnode_list; unsigned int node_id; int retval = -EINVAL; if (has_acpi_companion(dev)) { if (acpi_dev) { dev_warn(dev, "ACPI companion already set\n"); return -EINVAL; } else { acpi_dev = ACPI_COMPANION(dev); } } if (!acpi_dev) return -EINVAL; get_device(&acpi_dev->dev); get_device(dev); physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL); if (!physical_node) { retval = -ENOMEM; goto err; } mutex_lock(&acpi_dev->physical_node_lock); /* * Keep the list sorted by node_id so that the IDs of removed nodes can * be recycled easily. */ physnode_list = &acpi_dev->physical_node_list; node_id = 0; list_for_each_entry(pn, &acpi_dev->physical_node_list, node) { /* Sanity check. */ if (pn->dev == dev) { mutex_unlock(&acpi_dev->physical_node_lock); dev_warn(dev, "Already associated with ACPI node\n"); kfree(physical_node); if (ACPI_COMPANION(dev) != acpi_dev) goto err; put_device(dev); put_device(&acpi_dev->dev); return 0; } if (pn->node_id == node_id) { physnode_list = &pn->node; node_id++; } } physical_node->node_id = node_id; physical_node->dev = dev; list_add(&physical_node->node, physnode_list); acpi_dev->physical_node_count++; if (!has_acpi_companion(dev)) ACPI_COMPANION_SET(dev, acpi_dev); acpi_physnode_link_name(physical_node_name, node_id); retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, physical_node_name); if (retval) dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n", physical_node_name, retval); retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, "firmware_node"); if (retval) dev_err(dev, "Failed to create link firmware_node (%d)\n", retval); mutex_unlock(&acpi_dev->physical_node_lock); if (acpi_dev->wakeup.flags.valid) device_set_wakeup_capable(dev, true); return 0; err: ACPI_COMPANION_SET(dev, NULL); put_device(dev); put_device(&acpi_dev->dev); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki23557.32%1376.47%
Lan Tianyu10525.61%15.88%
David Shaohua Li379.02%15.88%
David Brownell307.32%15.88%
Greg Kroah-Hartman30.73%15.88%
Total410100.00%17100.00%

EXPORT_SYMBOL_GPL(acpi_bind_one);
int acpi_unbind_one(struct device *dev) { struct acpi_device *acpi_dev = ACPI_COMPANION(dev); struct acpi_device_physical_node *entry; if (!acpi_dev) return 0; mutex_lock(&acpi_dev->physical_node_lock); list_for_each_entry(entry, &acpi_dev->physical_node_list, node) if (entry->dev == dev) { char physnode_name[PHYSICAL_NODE_NAME_SIZE]; list_del(&entry->node); acpi_dev->physical_node_count--; acpi_physnode_link_name(physnode_name, entry->node_id); sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name); sysfs_remove_link(&dev->kobj, "firmware_node"); ACPI_COMPANION_SET(dev, NULL); /* Drop references taken by acpi_bind_one(). */ put_device(dev); put_device(&acpi_dev->dev); kfree(entry); break; } mutex_unlock(&acpi_dev->physical_node_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Lan Tianyu5537.41%111.11%
Rafael J. Wysocki4329.25%666.67%
David Shaohua Li3020.41%111.11%
David Brownell1912.93%111.11%
Total147100.00%9100.00%

EXPORT_SYMBOL_GPL(acpi_unbind_one);
static int acpi_platform_notify(struct device *dev) { struct acpi_bus_type *type = acpi_get_bus_type(dev); struct acpi_device *adev; int ret; ret = acpi_bind_one(dev, NULL); if (ret && type) { struct acpi_device *adev; adev = type->find_companion(dev); if (!adev) { DBG("Unable to get handle for %s\n", dev_name(dev)); ret = -ENODEV; goto out; } ret = acpi_bind_one(dev, adev); if (ret) goto out; } adev = ACPI_COMPANION(dev); if (!adev) goto out; if (dev->bus == &platform_bus_type) acpi_configure_pmsi_domain(dev); if (type && type->setup) type->setup(dev); else if (adev->handler && adev->handler->bind) adev->handler->bind(dev); out: #if ACPI_GLUE_DEBUG if (!ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer); DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer); kfree(buffer.pointer); } else DBG("Device %s -> No ACPI support\n", dev_name(dev)); #endif return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki11145.68%650.00%
David Shaohua Li10543.21%216.67%
Hanjun Guo145.76%18.33%
Kay Sievers93.70%18.33%
Yinghai Lu31.23%18.33%
Len Brown10.41%18.33%
Total243100.00%12100.00%


static int acpi_platform_notify_remove(struct device *dev) { struct acpi_device *adev = ACPI_COMPANION(dev); struct acpi_bus_type *type; if (!adev) return 0; type = acpi_get_bus_type(dev); if (type && type->cleanup) type->cleanup(dev); else if (adev->handler && adev->handler->unbind) adev->handler->unbind(dev); acpi_unbind_one(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki6777.91%266.67%
David Shaohua Li1922.09%133.33%
Total86100.00%3100.00%


void __init init_acpi_device_notify(void) { if (platform_notify || platform_notify_remove) { printk(KERN_ERR PREFIX "Can't use platform_notify\n"); return; } platform_notify = acpi_platform_notify; platform_notify_remove = acpi_platform_notify_remove; }

Contributors

PersonTokensPropCommitsCommitProp
David Shaohua Li2993.55%150.00%
Rami Rosen26.45%150.00%
Total31100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki77650.36%2961.70%
David Shaohua Li47730.95%24.26%
Lan Tianyu16410.64%12.13%
David Brownell493.18%12.13%
Hanjun Guo201.30%12.13%
Kay Sievers90.58%12.13%
Matthew Garrett80.52%12.13%
Joe Perches80.52%12.13%
Jeff Wu70.45%12.13%
Len Brown40.26%24.26%
Suravee Suthikulpanit30.19%12.13%
Yinghai Lu30.19%12.13%
Greg Kroah-Hartman30.19%12.13%
Tejun Heo30.19%12.13%
Paul Gortmaker30.19%12.13%
Rami Rosen20.13%12.13%
Jeff Garzik20.13%12.13%
Total1541100.00%47100.00%
Directory: drivers/acpi
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.