📄 acpiphp_glue.c
字号:
list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); if (func->flags & FUNC_HAS_STA) { status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); if (ACPI_SUCCESS(status) && sta) break; } else { pci_bus_read_config_dword(slot->bridge->pci_bus, PCI_DEVFN(slot->device, func->function), PCI_VENDOR_ID, &dvid); if (dvid != 0xffffffff) { sta = ACPI_STA_ALL; break; } } } return (unsigned int)sta;}/** * acpiphp_check_bridge - re-enumerate devices * * Iterate over all slots under this bridge and make sure that if a * card is present they are enabled, and if not they are disabled. */static int acpiphp_check_bridge(struct acpiphp_bridge *bridge){ struct acpiphp_slot *slot; int retval = 0; int enabled, disabled; enabled = disabled = 0; for (slot = bridge->slots; slot; slot = slot->next) { unsigned int status = get_slot_status(slot); if (slot->flags & SLOT_ENABLED) { if (status == ACPI_STA_ALL) continue; retval = acpiphp_disable_slot(slot); if (retval) { err("Error occurred in disabling\n"); goto err_exit; } disabled++; } else { if (status != ACPI_STA_ALL) continue; retval = acpiphp_enable_slot(slot); if (retval) { err("Error occurred in enabling\n"); goto err_exit; } enabled++; } } dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled); err_exit: return retval;}/* * ACPI event handlers *//** * handle_hotplug_event_bridge - handle ACPI event on bridges * * @handle: Notify()'ed acpi_handle * @type: Notify code * @context: pointer to acpiphp_bridge structure * * handles ACPI event notification on {host,p2p} bridges * */static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context){ struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; bridge = (struct acpiphp_bridge *)context; acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); acpiphp_check_bridge(bridge); break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); acpiphp_check_bridge(bridge); break; case ACPI_NOTIFY_DEVICE_WAKE: /* wake event */ dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); break; case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: printk(KERN_ERR "Device %s cannot be configured due" " to a frequency mismatch\n", objname); break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: printk(KERN_ERR "Device %s cannot be configured due" " to a bus mode mismatch\n", objname); break; case ACPI_NOTIFY_POWER_FAULT: printk(KERN_ERR "Device %s has suffered a power fault\n", objname); break; default: warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); break; }}/** * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) * * @handle: Notify()'ed acpi_handle * @type: Notify code * @context: pointer to acpiphp_func structure * * handles ACPI event notification on slots * */static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context){ struct acpiphp_func *func; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); func = (struct acpiphp_func *)context; switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); acpiphp_enable_slot(func->slot); break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check : re-enumerate from parent bus */ dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); acpiphp_check_bridge(func->slot->bridge); break; case ACPI_NOTIFY_DEVICE_WAKE: /* wake event */ dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); break; case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); acpiphp_disable_slot(func->slot); break; default: warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); break; }}static struct acpi_pci_driver acpi_pci_hp_driver = { .add = add_bridge, .remove = remove_bridge,};/** * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures * */int __init acpiphp_glue_init(void){ int num; if (list_empty(&pci_root_buses)) return -1; num = acpi_pci_register_driver(&acpi_pci_hp_driver); if (num <= 0) return -1; return 0;}/** * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures * * This function frees all data allocated in acpiphp_glue_init() */void __exit acpiphp_glue_exit(void){ struct list_head *l1, *l2, *n1, *n2; struct acpiphp_bridge *bridge; struct acpiphp_slot *slot, *next; struct acpiphp_func *func; acpi_status status; list_for_each_safe (l1, n1, &bridge_list) { bridge = (struct acpiphp_bridge *)l1; slot = bridge->slots; while (slot) { next = slot->next; list_for_each_safe (l2, n2, &slot->funcs) { func = list_entry(l2, struct acpiphp_func, sibling); acpiphp_free_resource(&func->io_head); acpiphp_free_resource(&func->mem_head); acpiphp_free_resource(&func->p_mem_head); acpiphp_free_resource(&func->bus_head); status = acpi_remove_notify_handler(func->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_func); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); kfree(func); } kfree(slot); slot = next; } status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); acpiphp_free_resource(&bridge->io_head); acpiphp_free_resource(&bridge->mem_head); acpiphp_free_resource(&bridge->p_mem_head); acpiphp_free_resource(&bridge->bus_head); kfree(bridge); } acpi_pci_unregister_driver(&acpi_pci_hp_driver);}/** * acpiphp_get_num_slots - count number of slots in a system */int __init acpiphp_get_num_slots(void){ struct list_head *node; struct acpiphp_bridge *bridge; int num_slots; num_slots = 0; list_for_each (node, &bridge_list) { bridge = (struct acpiphp_bridge *)node; dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); num_slots += bridge->nr_slots; } dbg("Total %dslots\n", num_slots); return num_slots;}#if 0/** * acpiphp_for_each_slot - call function for each slot * @fn: callback function * @data: context to be passed to callback function * */static int acpiphp_for_each_slot(acpiphp_callback fn, void *data){ struct list_head *node; struct acpiphp_bridge *bridge; struct acpiphp_slot *slot; int retval = 0; list_for_each (node, &bridge_list) { bridge = (struct acpiphp_bridge *)node; for (slot = bridge->slots; slot; slot = slot->next) { retval = fn(slot, data); if (!retval) goto err_exit; } } err_exit: return retval;}#endif/* search matching slot from id */struct acpiphp_slot *get_slot_from_id(int id){ struct list_head *node; struct acpiphp_bridge *bridge; struct acpiphp_slot *slot; list_for_each (node, &bridge_list) { bridge = (struct acpiphp_bridge *)node; for (slot = bridge->slots; slot; slot = slot->next) if (slot->id == id) return slot; } /* should never happen! */ err("%s: no object for id %d\n", __FUNCTION__, id); WARN_ON(1); return NULL;}/** * acpiphp_enable_slot - power on slot */int acpiphp_enable_slot(struct acpiphp_slot *slot){ int retval; down(&slot->crit_sect); /* wake up all functions */ retval = power_on_slot(slot); if (retval) goto err_exit; if (get_slot_status(slot) == ACPI_STA_ALL) /* configure all functions */ retval = enable_device(slot); err_exit: up(&slot->crit_sect); return retval;}/** * acpiphp_disable_slot - power off slot */int acpiphp_disable_slot(struct acpiphp_slot *slot){ int retval = 0; down(&slot->crit_sect); /* unconfigure all functions */ retval = disable_device(slot); if (retval) goto err_exit; /* power off all functions */ retval = power_off_slot(slot); if (retval) goto err_exit; acpiphp_resource_sort_and_combine(&slot->bridge->io_head); acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); dbg("Available resources:\n"); acpiphp_dump_resource(slot->bridge); err_exit: up(&slot->crit_sect); return retval;}/* * slot enabled: 1 * slot disabled: 0 */u8 acpiphp_get_power_status(struct acpiphp_slot *slot){ unsigned int sta; sta = get_slot_status(slot); return (sta & ACPI_STA_ENABLED) ? 1 : 0;}/* * latch closed: 1 * latch open: 0 */u8 acpiphp_get_latch_status(struct acpiphp_slot *slot){ unsigned int sta; sta = get_slot_status(slot); return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;}/* * adapter presence : 1 * absence : 0 */u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot){ unsigned int sta; sta = get_slot_status(slot); return (sta == 0) ? 0 : 1;}/* * pci address (seg/bus/dev) */u32 acpiphp_get_address(struct acpiphp_slot *slot){ u32 address; address = ((slot->bridge->seg) << 16) | ((slot->bridge->bus) << 8) | slot->device; return address;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -