Skip to content
Snippets Groups Projects
Select Git revision
  • 65e9d2faab70d07b9a38ac6ed298f191d24541fc
  • add-vdpu381-and-383-to-rkvdec-v2
  • add-vdpu381-and-383-to-rkvdec
  • prepare-add-vdpu381-and-383-to-rkvdec
  • add-rkvdec2-driver-vdpu383-hevc
  • add-rkvdec2-driver-vdpu383
  • add-rkvdec2-driver-hevc
  • rkvdec-mov-to-structs
  • av1-fix-postproc-leak
  • add-rkvdec2-driver-iommu-422-10bits
  • patch-queue/jamba/trixie
  • hdmi-fix-1080p-rock4d-6.11
  • upstreaming/rk3576-rock4d-spi-v1
  • upstreaming/rk3576-rock4d-support-v5
  • upstreaming/rk3588-hdmi-audio-6
  • upstreaming/rk3576-rock4d-support-v3
  • upstreaming/rk3576-rock4d-support-v1
  • upstreaming/rk3576-rock4d-support
  • add-rkvdec2-driver-iommu
  • upstream/rk3576-rock-4d
  • rk3588-hdmi-audio-2
  • v6.3
  • v6.3-rc1
  • v6.2-rc1
  • v6.0-rc1
  • v5.19-rc3
  • v5.19-rc2
  • v5.19-rc1
  • v5.18
  • v5.18-rc7
  • v5.18-rc6
  • v5.18-rc5
  • v5.18-rc4
  • v5.18-rc3
  • v5.18-rc2
  • v5.18-rc1
  • v5.17
  • v5.17-rc8
  • v5.17-rc7
  • v5.17-rc6
  • v5.17-rc5
41 results

dev.c

Blame
  • Forked from hardware-enablement / Rockchip upstream enablement efforts / linux
    Source project has a limited visibility.
    glue.c 7.45 KiB
    /*
     * 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/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 "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"
    
    int register_acpi_bus_type(struct acpi_bus_type *type)
    {
    	if (acpi_disabled)
    		return -ENODEV;
    	if (type && type->bus && type->find_device) {
    		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->bus->name);
    		return 0;
    	}
    	return -ENODEV;
    }
    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 "ACPI bus type %s unregistered\n",
    		       type->bus->name);
    		return 0;
    	}
    	return -ENODEV;
    }
    EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
    
    static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
    {
    	struct acpi_bus_type *tmp, *ret = NULL;
    
    	down_read(&bus_type_sem);
    	list_for_each_entry(tmp, &bus_type_list, list) {
    		if (tmp->bus == type) {
    			ret = tmp;
    			break;
    		}
    	}
    	up_read(&bus_type_sem);
    	return ret;
    }
    
    static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
    {
    	struct acpi_bus_type *tmp;
    	int ret = -ENODEV;
    
    	down_read(&bus_type_sem);
    	list_for_each_entry(tmp, &bus_type_list, list) {
    		if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) {
    			ret = 0;
    			break;
    		}
    	}
    	up_read(&bus_type_sem);
    	return ret;
    }
    
    /* Get device's handler per its address under its parent */
    struct acpi_find_child {
    	acpi_handle handle;
    	u64 address;
    };
    
    static acpi_status
    do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
    {
    	acpi_status status;
    	struct acpi_device_info *info;
    	struct acpi_find_child *find = context;
    
    	status = acpi_get_object_info(handle, &info);
    	if (ACPI_SUCCESS(status)) {
    		if ((info->address == find->address)
    			&& (info->valid & ACPI_VALID_ADR))
    			find->handle = handle;
    		kfree(info);
    	}
    	return AE_OK;
    }
    
    acpi_handle acpi_get_child(acpi_handle parent, u64 address)
    {
    	struct acpi_find_child find = { NULL, address };
    
    	if (!parent)
    		return NULL;
    	acpi_walk_namespace(ACPI_TYPE_DEVICE, parent,
    			    1, do_acpi_find_child, NULL, &find, NULL);
    	return find.handle;
    }
    
    EXPORT_SYMBOL(acpi_get_child);
    
    static int acpi_bind_one(struct device *dev, acpi_handle handle)
    {
    	struct acpi_device *acpi_dev;
    	acpi_status status;
    	struct acpi_device_physical_node *physical_node, *pn;
    	char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
    	int retval = -EINVAL;
    
    	if (ACPI_HANDLE(dev)) {
    		if (handle) {
    			dev_warn(dev, "ACPI handle is already set\n");
    			return -EINVAL;
    		} else {
    			handle = ACPI_HANDLE(dev);
    		}
    	}
    	if (!handle)
    		return -EINVAL;
    
    	get_device(dev);
    	status = acpi_bus_get_device(handle, &acpi_dev);
    	if (ACPI_FAILURE(status))
    		goto err;
    
    	physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
    	if (!physical_node) {
    		retval = -ENOMEM;
    		goto err;
    	}
    
    	mutex_lock(&acpi_dev->physical_node_lock);
    
    	/* Sanity check. */
    	list_for_each_entry(pn, &acpi_dev->physical_node_list, node)
    		if (pn->dev == dev) {
    			dev_warn(dev, "Already associated with ACPI node\n");
    			goto err_free;
    		}
    
    	/* allocate physical node id according to physical_node_id_bitmap */
    	physical_node->node_id =
    		find_first_zero_bit(acpi_dev->physical_node_id_bitmap,
    		ACPI_MAX_PHYSICAL_NODE);
    	if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
    		retval = -ENOSPC;
    		goto err_free;
    	}
    
    	set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap);
    	physical_node->dev = dev;
    	list_add_tail(&physical_node->node, &acpi_dev->physical_node_list);
    	acpi_dev->physical_node_count++;
    
    	mutex_unlock(&acpi_dev->physical_node_lock);
    
    	if (!ACPI_HANDLE(dev))
    		ACPI_HANDLE_SET(dev, acpi_dev->handle);
    
    	if (!physical_node->node_id)
    		strcpy(physical_node_name, PHYSICAL_NODE_STRING);
    	else
    		sprintf(physical_node_name,
    			"physical_node%d", physical_node->node_id);
    	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
    			physical_node_name);
    	retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
    		"firmware_node");
    
    	if (acpi_dev->wakeup.flags.valid)
    		device_set_wakeup_capable(dev, true);
    
    	return 0;
    
     err:
    	ACPI_HANDLE_SET(dev, NULL);
    	put_device(dev);
    	return retval;
    
     err_free:
    	mutex_unlock(&acpi_dev->physical_node_lock);
    	kfree(physical_node);
    	goto err;
    }
    
    static int acpi_unbind_one(struct device *dev)
    {
    	struct acpi_device_physical_node *entry;
    	struct acpi_device *acpi_dev;
    	acpi_status status;
    	struct list_head *node, *next;
    
    	if (!ACPI_HANDLE(dev))
    		return 0;
    
    	status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev);
    	if (ACPI_FAILURE(status))
    		goto err;
    
    	mutex_lock(&acpi_dev->physical_node_lock);
    	list_for_each_safe(node, next, &acpi_dev->physical_node_list) {
    		char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
    
    		entry = list_entry(node, struct acpi_device_physical_node,
    			node);
    		if (entry->dev != dev)
    			continue;
    
    		list_del(node);
    		clear_bit(entry->node_id, acpi_dev->physical_node_id_bitmap);
    
    		acpi_dev->physical_node_count--;
    
    		if (!entry->node_id)
    			strcpy(physical_node_name, PHYSICAL_NODE_STRING);
    		else
    			sprintf(physical_node_name,
    				"physical_node%d", entry->node_id);
    
    		sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name);
    		sysfs_remove_link(&dev->kobj, "firmware_node");
    		ACPI_HANDLE_SET(dev, NULL);
    		/* acpi_bind_one increase refcnt by one */
    		put_device(dev);
    		kfree(entry);
    	}
    	mutex_unlock(&acpi_dev->physical_node_lock);
    
    	return 0;
    
    err:
    	dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
    	return -EINVAL;
    }
    
    static int acpi_platform_notify(struct device *dev)
    {
    	struct acpi_bus_type *type;
    	acpi_handle handle;
    	int ret = -EINVAL;
    
    	ret = acpi_bind_one(dev, NULL);
    	if (!ret)
    		goto out;
    
    	if (!dev->bus || !dev->parent) {
    		/* bridge devices genernally haven't bus or parent */
    		ret = acpi_find_bridge_device(dev, &handle);
    		goto end;
    	}
    	type = acpi_get_bus_type(dev->bus);
    	if (!type) {
    		DBG("No ACPI bus support for %s\n", dev_name(dev));
    		ret = -EINVAL;
    		goto end;
    	}
    	if ((ret = type->find_device(dev, &handle)) != 0)
    		DBG("Can't get handler for %s\n", dev_name(dev));
     end:
    	if (!ret)
    		acpi_bind_one(dev, handle);
    
     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;
    }
    
    static int acpi_platform_notify_remove(struct device *dev)
    {
    	acpi_unbind_one(dev);
    	return 0;
    }
    
    int __init init_acpi_device_notify(void)
    {
    	if (platform_notify || platform_notify_remove) {
    		printk(KERN_ERR PREFIX "Can't use platform_notify\n");
    		return 0;
    	}
    	platform_notify = acpi_platform_notify;
    	platform_notify_remove = acpi_platform_notify_remove;
    	return 0;
    }