static int
acpi_cpu_global_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS)
{
    struct	acpi_cpu_softc *sc;
    char	state[8];
    int		val, error, i;

    snprintf(state, sizeof(state), "C%d", cpu_cx_lowest + 1);
    error = sysctl_handle_string(oidp, state, sizeof(state), req);
    if (error != 0 || req->newptr == NULL)
	return (error);
    if (strlen(state) < 2 || toupper(state[0]) != 'C')
	return (EINVAL);
    val = (int) strtol(state + 1, NULL, 10) - 1;
    if (val < 0 || val > cpu_cx_count - 1)
	return (EINVAL);
    cpu_cx_lowest = val;

    /* Update the new lowest useable Cx state for all CPUs. */
    ACPI_SERIAL_BEGIN(cpu);
    for (i = 0; i < cpu_ndevices; i++) {
	sc = device_get_softc(cpu_devices[i]);
	acpi_cpu_set_cx_lowest(sc, val);
    }
    ACPI_SERIAL_END(cpu);

    return (0);
}
Example #2
0
static int
acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp)
{
    struct acpi_cmbat_softc *sc;

    sc = device_get_softc(dev);

    /*
     * Just copy the data.  The only value that should change is the
     * last-full capacity, so we only update when we get a notify that says
     * the info has changed.  Many systems apparently take a long time to
     * process a _BIF call so we avoid it if possible.
     */
    ACPI_SERIAL_BEGIN(cmbat);
    bifp->units = sc->bif.units;
    bifp->dcap = sc->bif.dcap;
    bifp->lfcap = sc->bif.lfcap;
    bifp->btech = sc->bif.btech;
    bifp->dvol = sc->bif.dvol;
    bifp->wcap = sc->bif.wcap;
    bifp->lcap = sc->bif.lcap;
    bifp->gra1 = sc->bif.gra1;
    bifp->gra2 = sc->bif.gra2;
    strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
    strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
    strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
    strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
    ACPI_SERIAL_END(cmbat);

    return (0);
}
Example #3
0
static int
acpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS)
{
	struct acpi_fujitsu_softc	*sc;
	int				method;
	int				arg;
	int				function_num, error = 0;

	sc = (struct acpi_fujitsu_softc *)oidp->oid_arg1;
	function_num = oidp->oid_arg2;
	method = sysctl_table[function_num].method;

	ACPI_SERIAL_BEGIN(fujitsu);

	/* Get the current value */
	arg = acpi_fujitsu_method_get(sc, method);
	error = sysctl_handle_int(oidp, &arg, 0, req);

	if (error != 0 || req->newptr == NULL)
		goto out;

	/* Update the value */
	error = acpi_fujitsu_method_set(sc, method, arg);

out:
	ACPI_SERIAL_END(fujitsu);
	return (error);
}
Example #4
0
static int
acpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS)
{
	struct acpi_panasonic_softc *sc;
	UINT32 arg;
	int function, error;
	hkey_fn_t *handler;

	sc = (struct acpi_panasonic_softc *)oidp->oid_arg1;
	function = oidp->oid_arg2;
	handler = sysctl_table[function].handler;

	/* Get the current value from the appropriate function. */
	ACPI_SERIAL_BEGIN(panasonic);
	error = handler(sc->handle, HKEY_GET, &arg);
	if (error != 0)
		goto out;

	/* Send the current value to the user and return if no new value. */
	error = sysctl_handle_int(oidp, &arg, 0, req);
	if (error != 0 || req->newptr == NULL)
		goto out;

	/* Set the new value via the appropriate function. */
	error = handler(sc->handle, HKEY_SET, &arg);

out:
	ACPI_SERIAL_END(panasonic);
	return (error);
}
Example #5
0
static int
acpi_pci_link_resume(device_t dev)
{
	struct acpi_pci_link_softc *sc;
	ACPI_STATUS status;
	int i, routed;

	/*
	 * If all of our links are routed, then restore the link via _SRS,
	 * otherwise, disable the link via _DIS.
	 */
	ACPI_SERIAL_BEGIN(pci_link);
	sc = device_get_softc(dev);
	routed = 0;
	for (i = 0; i < sc->pl_num_links; i++)
		if (sc->pl_links[i].l_routed)
			routed++;
	if (routed == sc->pl_num_links)
		status = acpi_pci_link_route_irqs(dev);
	else {
		AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL, NULL);
		status = AE_OK;
	}
	ACPI_SERIAL_END(pci_link);
	if (ACPI_FAILURE(status))
		return (ENXIO);
	else
		return (0);
}
static void
acpi_acad_get_status(void *context)
{
    struct acpi_acad_softc *sc;
    device_t	dev;
    ACPI_HANDLE	h;
    int		newstatus;

    dev = context;
    sc = device_get_softc(dev);
    h = acpi_get_handle(dev);
    newstatus = -1;
    acpi_GetInteger(h, "_PSR", &newstatus);

    /* If status is valid and has changed, notify the system. */
    ACPI_SERIAL_BEGIN(acad);
    if (newstatus != -1 && sc->status != newstatus) {
	sc->status = newstatus;
	power_profile_set_state(newstatus ? POWER_PROFILE_PERFORMANCE :
	    POWER_PROFILE_ECONOMY);
	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
	    "%s Line\n", newstatus ? "On" : "Off");
	acpi_UserNotify("ACAD", h, newstatus);
    }
    ACPI_SERIAL_END(acad);
}
Example #7
0
/* XXX There should be a cleaner way to do this locking. */
static void
acpi_cmbat_get_bif_task(void *arg)
{

    ACPI_SERIAL_BEGIN(cmbat);
    acpi_cmbat_get_bif(arg);
    ACPI_SERIAL_END(cmbat);
}
Example #8
0
static void
acpi_cmbat_init_battery(void *arg)
{
    struct acpi_cmbat_softc *sc;
    int		retry, valid;
    device_t	dev;

    dev = (device_t)arg;
    sc = device_get_softc(dev);
    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
		"battery initialization start\n");

    /*
     * Try repeatedly to get valid data from the battery.  Since the
     * embedded controller isn't always ready just after boot, we may have
     * to wait a while.
     */
    for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) {
	/* batteries on DOCK can be ejected w/ DOCK during retrying */
	if (!device_is_attached(dev))
	    return;

	if (!acpi_BatteryIsPresent(dev))
	    continue;

	/*
	 * Only query the battery if this is the first try or the specific
	 * type of info is still invalid.
	 */
	ACPI_SERIAL_BEGIN(cmbat);
	if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) {
	    timespecclear(&sc->bst_lastupdated);
	    acpi_cmbat_get_bst(dev);
	}
	if (retry == 0 || !acpi_battery_bif_valid(&sc->bif))
	    acpi_cmbat_get_bif(dev);

	valid = acpi_battery_bst_valid(&sc->bst) &&
	    acpi_battery_bif_valid(&sc->bif);
	ACPI_SERIAL_END(cmbat);

	if (valid)
	    break;
    }

    if (retry == ACPI_CMBAT_RETRY_MAX) {
	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
		    "battery initialization failed, giving up\n");
    } else {
	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
		    "battery initialization done, tried %d times\n", retry + 1);
    }
}
Example #9
0
int
acpi_battery_register(device_t dev)
{
    int error;

    error = 0;
    ACPI_SERIAL_BEGIN(battery);
    if (!acpi_batteries_initted)
	error = acpi_battery_init();
    ACPI_SERIAL_END(battery);
    return (error);
}
Example #10
0
static void
acpi_panasonic_power_profile(void *arg)
{
	ACPI_HANDLE handle;
	UINT32 brightness;

	handle = (ACPI_HANDLE)arg;

	/* Reset current brightness according to new power state. */
	ACPI_SERIAL_BEGIN(panasonic);
	hkey_lcd_brightness(handle, HKEY_GET, &brightness);
	hkey_lcd_brightness(handle, HKEY_SET, &brightness);
	ACPI_SERIAL_END(panasonic);
}
static int
acpi_dock_attach(device_t dev)
{
	struct acpi_dock_softc *sc;
	ACPI_HANDLE	h;

	sc = device_get_softc(dev);
	h = acpi_get_handle(dev);
	if (sc == NULL || h == NULL)
		return (ENXIO);

	sc->status = ACPI_DOCK_STATUS_UNKNOWN;

	AcpiEvaluateObject(h, "_INI", NULL, NULL);

	ACPI_SERIAL_BEGIN(dock);

	acpi_dock_device_check(dev);

	/* Get the sysctl tree */
	sc->sysctl_ctx = device_get_sysctl_ctx(dev);
	sc->sysctl_tree = device_get_sysctl_tree(dev);

	SYSCTL_ADD_INT(sc->sysctl_ctx,
		SYSCTL_CHILDREN(sc->sysctl_tree),
		OID_AUTO, "_sta", CTLFLAG_RD,
		&sc->_sta, 0, "Dock _STA");
	SYSCTL_ADD_INT(sc->sysctl_ctx,
		SYSCTL_CHILDREN(sc->sysctl_tree),
		OID_AUTO, "_bdn", CTLFLAG_RD,
		&sc->_bdn, 0, "Dock _BDN");
	SYSCTL_ADD_INT(sc->sysctl_ctx,
		SYSCTL_CHILDREN(sc->sysctl_tree),
		OID_AUTO, "_uid", CTLFLAG_RD,
		&sc->_uid, 0, "Dock _UID");
	SYSCTL_ADD_PROC(sc->sysctl_ctx,
		SYSCTL_CHILDREN(sc->sysctl_tree),
		OID_AUTO, "status",
		CTLTYPE_INT|CTLFLAG_RW, dev, 0,
		acpi_dock_status_sysctl, "I",
		"Dock/Undock operation");

	ACPI_SERIAL_END(dock);

	AcpiInstallNotifyHandler(h, ACPI_ALL_NOTIFY,
				 acpi_dock_notify_handler, dev);

	return (0);
}
Example #12
0
static ACPI_STATUS
EcLock(struct acpi_ec_softc *sc)
{
    ACPI_STATUS	status;

    ACPI_SERIAL_BEGIN(ec);
    /* If _GLK is non-zero, acquire the global lock. */
    status = AE_OK;
    if (sc->ec_glk) {
	status = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, &sc->ec_glkhandle);
	if (ACPI_FAILURE(status))
	    ACPI_SERIAL_END(ec);
    }
    return (status);
}
Example #13
0
static void
acpi_fujitsu_notify_status_changed(void *arg)
{
	struct acpi_fujitsu_softc *sc;

	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);

	sc = (struct acpi_fujitsu_softc *)arg;

	/*
	 * Since our notify function is called, we know something has
	 * happened.  So the only reason for acpi_fujitsu_update to fail
	 * is if we can't find what has changed or an error occurs.
	 */
	ACPI_SERIAL_BEGIN(fujitsu);
	acpi_fujitsu_update(sc);
	ACPI_SERIAL_END(fujitsu);
}
Example #14
0
/*
 * PCI power manangement
 */
static int
acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
{
	ACPI_HANDLE h;
	ACPI_STATUS status;
	int old_state, error;

	error = 0;
	if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
		return (EINVAL);

	/*
	 * We set the state using PCI Power Management outside of setting
	 * the ACPI state.  This means that when powering down a device, we
	 * first shut it down using PCI, and then using ACPI, which lets ACPI
	 * try to power down any Power Resources that are now no longer used.
	 * When powering up a device, we let ACPI set the state first so that
	 * it can enable any needed Power Resources before changing the PCI
	 * power state.
	 */
	ACPI_SERIAL_BEGIN(pci_powerstate);
	old_state = pci_get_powerstate(child);
	if (old_state < state && pci_do_power_suspend) {
		error = pci_set_powerstate_method(dev, child, state);
		if (error)
			goto out;
	}
	h = acpi_get_handle(child);
	status = acpi_pwr_switch_consumer(h, state);
	if (ACPI_SUCCESS(status)) {
		if (bootverbose)
			device_printf(dev, "set ACPI power state D%d on %s\n",
			    state, acpi_name(h));
	} else if (status != AE_NOT_FOUND)
		device_printf(dev,
		    "failed to set ACPI power state D%d on %s: %s\n",
		    state, acpi_name(h), AcpiFormatException(status));
	if (old_state > state && pci_do_power_resume)
		error = pci_set_powerstate_method(dev, child, state);

out:
	ACPI_SERIAL_END(pci_powerstate);
	return (error);
}
static int
acpi_dock_status_sysctl(SYSCTL_HANDLER_ARGS)
{
	struct acpi_dock_softc *sc;
	device_t	dev;
	int		status, err;

	err = 0;
	dev = (device_t)arg1;

	sc = device_get_softc(dev);
	status = sc->status;

	ACPI_SERIAL_BEGIN(dock);
	err = sysctl_handle_int(oidp, &status, 0, req);
	if (err != 0 || req->newptr == NULL)
		goto out;

	if (status != ACPI_DOCK_STATUS_UNDOCKED &&
	    status != ACPI_DOCK_STATUS_DOCKED) {
		err = EINVAL;
		goto out;
	}

	if (status == sc->status)
		goto out;

	switch (status) {
	case ACPI_DOCK_STATUS_UNDOCKED:
		acpi_dock_removal(dev);
		break;
	case ACPI_DOCK_STATUS_DOCKED:
		acpi_dock_device_check(dev);
		break;
	default:
		err = EINVAL;
		break;
	}
out:
	ACPI_SERIAL_END(dock);
	return (err);
}
Example #16
0
int
acpi_pci_link_route_interrupt(device_t dev, int index)
{
	struct link *link;

	if (acpi_disabled("pci_link"))
		return (PCI_INVALID_IRQ);

	ACPI_SERIAL_BEGIN(pci_link);
	link = acpi_pci_link_lookup(dev, index);
	if (link == NULL)
		panic("%s: apparently invalid index %d", __func__, index);

	/*
	 * If this link device is already routed to an interrupt, just return
	 * the interrupt it is routed to.
	 */
	if (link->l_routed) {
		KASSERT(PCI_INTERRUPT_VALID(link->l_irq),
		    ("%s: link is routed but has an invalid IRQ", __func__));
		ACPI_SERIAL_END(pci_link);
		return (link->l_irq);
	}

	/* Choose an IRQ if we need one. */
	if (!PCI_INTERRUPT_VALID(link->l_irq)) {
		link->l_irq = acpi_pci_link_choose_irq(dev, link);

		/*
		 * Try to route the interrupt we picked.  If it fails, then
		 * assume the interrupt is not routed.
		 */
		if (PCI_INTERRUPT_VALID(link->l_irq)) {
			acpi_pci_link_route_irqs(dev);
			if (!link->l_routed)
				link->l_irq = PCI_INVALID_IRQ;
		}
	}
	ACPI_SERIAL_END(pci_link);

	return (link->l_irq);
}
Example #17
0
static int
acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp)
{
    struct acpi_cmbat_softc *sc;

    sc = device_get_softc(dev);

    ACPI_SERIAL_BEGIN(cmbat);
    if (acpi_BatteryIsPresent(dev)) {
	acpi_cmbat_get_bst(dev);
	bstp->state = sc->bst.state;
	bstp->rate = sc->bst.rate;
	bstp->cap = sc->bst.cap;
	bstp->volt = sc->bst.volt;
    } else
	bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
    ACPI_SERIAL_END(cmbat);

    return (0);
}
Example #18
0
static void
acpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify, void *context)
{
	struct acpi_panasonic_softc *sc;
	UINT32 key = 0;

	sc = (struct acpi_panasonic_softc *)context;

	switch (notify) {
	case 0x80:
		ACPI_SERIAL_BEGIN(panasonic);
		if (acpi_panasonic_hkey_event(sc, h, &key) == 0) {
			acpi_panasonic_hkey_action(sc, h, key);
			acpi_UserNotify("Panasonic", h, (uint8_t)key);
		}
		ACPI_SERIAL_END(panasonic);
		break;
	default:
		device_printf(sc->dev, "unknown notify: %#x\n", notify);
		break;
	}
}
Example #19
0
static void
acpi_lid_notify_status_changed(void *arg)
{
    struct acpi_lid_softc	*sc;
    struct acpi_softc		*acpi_sc;
    ACPI_STATUS			status;

    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);

    sc = (struct acpi_lid_softc *)arg;
    ACPI_SERIAL_BEGIN(lid);

    /*
     * Evaluate _LID and check the return value, update lid status.
     *	Zero:		The lid is closed
     *	Non-zero:	The lid is open
     */
    status = acpi_GetInteger(sc->lid_handle, "_LID", &sc->lid_status);
    if (ACPI_FAILURE(status))
        goto out;

    acpi_sc = acpi_device_get_parent_softc(sc->lid_dev);
    if (acpi_sc == NULL)
        goto out;

    ACPI_VPRINT(sc->lid_dev, acpi_sc, "Lid %s\n",
                sc->lid_status ? "opened" : "closed");

    acpi_UserNotify("Lid", sc->lid_handle, sc->lid_status);

    if (sc->lid_status == 0)
        EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_sx);
    else
        EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_sx);

out:
    ACPI_SERIAL_END(lid);
    return_VOID;
}
Example #20
0
static int
acpi_fujitsu_resume(device_t dev)
{
	struct acpi_fujitsu_softc   *sc;
	ACPI_STATUS		    status;

	sc = device_get_softc(dev);

	/*
	 * The pointer needs to be re-enabled for
	 * some revisions of the P series (2120).
	 */
	ACPI_SERIAL_BEGIN(fujitsu);

	if(sc->gmou.exists) {
		status = acpi_SetInteger(sc->handle, "SMOU", 1);
		if (ACPI_FAILURE(status))
			device_printf(sc->dev, "Couldn't enable pointer\n");
	}
	ACPI_SERIAL_END(fujitsu);

	return (0);
}
Example #21
0
static int
acpi_fujitsu_attach(device_t dev)
{
	struct acpi_fujitsu_softc *sc;

	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);

	sc = device_get_softc(dev);
	sc->dev = dev;
	sc->handle = acpi_get_handle(dev);

	/* Install notification handler */
	AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
	    acpi_fujitsu_notify_handler, sc);

	/* Snag our default values for the hotkeys / hotkey states. */
	ACPI_SERIAL_BEGIN(fujitsu);
	if (!acpi_fujitsu_init(sc))
		device_printf(dev, "Couldn't initialize hotkey states!\n");
	ACPI_SERIAL_END(fujitsu);

	return (0);
}
static int
acpi_cpu_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS)
{
    struct	 acpi_cpu_softc *sc;
    char	 state[8];
    int		 val, error;

    sc = (struct acpi_cpu_softc *) arg1;
    snprintf(state, sizeof(state), "C%d", sc->cpu_cx_lowest + 1);
    error = sysctl_handle_string(oidp, state, sizeof(state), req);
    if (error != 0 || req->newptr == NULL)
	return (error);
    if (strlen(state) < 2 || toupper(state[0]) != 'C')
	return (EINVAL);
    val = (int) strtol(state + 1, NULL, 10) - 1;
    if (val < 0 || val > sc->cpu_cx_count - 1)
	return (EINVAL);

    ACPI_SERIAL_BEGIN(cpu);
    acpi_cpu_set_cx_lowest(sc, val);
    ACPI_SERIAL_END(cpu);

    return (0);
}
static void
acpi_dock_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
{
	device_t	dev;

	dev = (device_t) context;
	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
		    "got notification %#x\n", notify);

	ACPI_SERIAL_BEGIN(dock);
	switch (notify) {
	case ACPI_NOTIFY_BUS_CHECK:
	case ACPI_NOTIFY_DEVICE_CHECK:
		acpi_dock_device_check(dev);
		break;
	case ACPI_NOTIFY_EJECT_REQUEST:
		acpi_dock_removal(dev);
		break;
	default:
		device_printf(dev, "unknown notify %#x\n", notify);
		break;
	}
	ACPI_SERIAL_END(dock);
}
/*
 * Re-evaluate the _CST object when we are notified that it changed.
 *
 * XXX Re-evaluation disabled until locking is done.
 */
static void
acpi_cpu_notify(ACPI_HANDLE h, UINT32 notify, void *context)
{
    struct acpi_cpu_softc *sc = (struct acpi_cpu_softc *)context;
    struct acpi_cpu_softc *isc;
    int i;
    
    if (notify != ACPI_NOTIFY_CX_STATES)
	return;

    /* Update the list of Cx states. */
    acpi_cpu_cx_cst(sc);
    acpi_cpu_cx_list(sc);

    /* Update the new lowest useable Cx state for all CPUs. */
    ACPI_SERIAL_BEGIN(cpu);
    cpu_cx_count = 0;
    for (i = 0; i < cpu_ndevices; i++) {
	isc = device_get_softc(cpu_devices[i]);
	if (isc->cpu_cx_count > cpu_cx_count)
	    cpu_cx_count = isc->cpu_cx_count;
    }
    ACPI_SERIAL_END(cpu);
}
Example #25
0
/*
 * Route an interrupt for a child of the bridge.
 */
int
acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
    ACPI_BUFFER *prtbuf)
{
    ACPI_PCI_ROUTING_TABLE *prt;
    struct prt_lookup_request pr;
    ACPI_HANDLE lnkdev;
    int interrupt;

    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);

    interrupt = PCI_INVALID_IRQ;

    /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */
    pin--;

    ACPI_SERIAL_BEGIN(pcib);

    /* Search for a matching entry in the routing table. */
    pr.pr_entry = NULL;
    pr.pr_pin = pin;
    pr.pr_slot = pci_get_slot(dev);
    prt_walk_table(prtbuf, prt_lookup_device, &pr);
    if (pr.pr_entry == NULL) {
	device_printf(pcib, "no PRT entry for %d.%d.INT%c\n", pci_get_bus(dev),
	    pci_get_slot(dev), 'A' + pin);
	goto out;
    }
    prt = pr.pr_entry;

    if (bootverbose) {
	device_printf(pcib, "matched entry for %d.%d.INT%c",
	    pci_get_bus(dev), pci_get_slot(dev), 'A' + pin);
	if (prt->Source != NULL && prt->Source[0] != '\0')
		printf(" (src %s:%u)", prt->Source, prt->SourceIndex);
	printf("\n");
    }

    /*
     * If source is empty/NULL, the source index is a global IRQ number
     * and it's hard-wired so we're done.
     *
     * XXX: If the source index is non-zero, ignore the source device and
     * assume that this is a hard-wired entry.
     */
    if (prt->Source == NULL || prt->Source[0] == '\0' ||
	prt->SourceIndex != 0) {
	if (bootverbose)
	    device_printf(pcib, "slot %d INT%c hardwired to IRQ %d\n",
		pci_get_slot(dev), 'A' + pin, prt->SourceIndex);
	if (prt->SourceIndex) {
	    interrupt = prt->SourceIndex;
	    BUS_CONFIG_INTR(dev, interrupt, INTR_TRIGGER_LEVEL,
		INTR_POLARITY_LOW);
	} else
	    device_printf(pcib, "error: invalid hard-wired IRQ of 0\n");
	goto out;
    }

    /*
     * We have to find the source device (PCI interrupt link device).
     */
    if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) {
	device_printf(pcib, "couldn't find PCI interrupt link device %s\n",
	    prt->Source);
	goto out;
    }
    interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev),
	prt->SourceIndex);

    if (bootverbose && PCI_INTERRUPT_VALID(interrupt))
	device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n",
	    pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(lnkdev));

out:
    ACPI_SERIAL_END(pcib);

    return_VALUE(interrupt);
}
Example #26
0
static int
acpi_smbat_get_bst(device_t dev, struct acpi_bst *bst)
{
	struct acpi_smbat_softc *sc;
	int error;
	uint32_t cap_units, factor;
	int16_t val;
	uint8_t	addr;

	ACPI_SERIAL_BEGIN(smbat);

	addr = SMBATT_ADDRESS;
	error = ENXIO;
	sc = device_get_softc(dev);

	if (!acpi_smbat_info_expired(&sc->bst_lastupdated)) {
		error = 0;
		goto out;
	}

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val))
		goto out;
	if (val & SMBATT_BM_CAPACITY_MODE) {
		factor = 10;
		cap_units = ACPI_BIF_UNITS_MW;
	} else {
		factor = 1;
		cap_units = ACPI_BIF_UNITS_MA;
	}

	/* get battery status */
	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_STATUS, &val))
		goto out;

	sc->bst.state = 0;
	if (val & SMBATT_BS_DISCHARGING)
		sc->bst.state |= ACPI_BATT_STAT_DISCHARG;

	if (val & SMBATT_BS_REMAINING_CAPACITY_ALARM)
		sc->bst.state |= ACPI_BATT_STAT_CRITICAL;

	/*
	 * If the rate is negative, it is discharging.  Otherwise,
	 * it is charging.
	 */
	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_CURRENT, &val))
		goto out;

	if (val > 0) {
		sc->bst.rate = val * factor;
		sc->bst.state &= ~SMBATT_BS_DISCHARGING;
		sc->bst.state |= ACPI_BATT_STAT_CHARGING;
	} else if (val < 0)
		sc->bst.rate = (-val) * factor;
	else
		sc->bst.rate = 0;

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_REMAINING_CAPACITY, &val))
		goto out;
	sc->bst.cap = val * factor;

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_VOLTAGE, &val))
		goto out;
	sc->bst.volt = val;

	acpi_smbat_info_updated(&sc->bst_lastupdated);
	error = 0;

out:
	if (error == 0)
		memcpy(bst, &sc->bst, sizeof(sc->bst));
	ACPI_SERIAL_END(smbat);
	return (error);
}
Example #27
0
static int
aibs_sysctl(SYSCTL_HANDLER_ARGS)
{
	struct aibs_softc	*sc = arg1;
	enum aibs_type		st = arg2;
	int			i = oidp->oid_number;
	ACPI_STATUS		rs;
	ACPI_OBJECT		p, *bp;
	ACPI_OBJECT_LIST	mp;
	ACPI_BUFFER		b;
	char			*name;
	struct aibs_sensor	*as;
	ACPI_INTEGER		v, l, h;
	int			so[3];

	switch (st) {
	case AIBS_VOLT:
		name = "RVLT";
		as = sc->sc_asens_volt;
		break;
	case AIBS_TEMP:
		name = "RTMP";
		as = sc->sc_asens_temp;
		break;
	case AIBS_FAN:
		name = "RFAN";
		as = sc->sc_asens_fan;
		break;
	default:
		return ENOENT;
	}
	if (as == NULL)
		return ENOENT;
	l = as[i].l;
	h = as[i].h;
	p.Type = ACPI_TYPE_INTEGER;
	p.Integer.Value = as[i].i;
	mp.Count = 1;
	mp.Pointer = &p;
	b.Length = ACPI_ALLOCATE_BUFFER;
	ACPI_SERIAL_BEGIN(aibs);
	rs = AcpiEvaluateObjectTyped(sc->sc_ah, name, &mp, &b,
	    ACPI_TYPE_INTEGER);
	if (ACPI_FAILURE(rs)) {
		ddevice_printf(sc->sc_dev,
		    "%s: %i: evaluation failed\n",
		    name, i);
		ACPI_SERIAL_END(aibs);
		return EIO;
	}
	bp = b.Pointer;
	v = bp->Integer.Value;
	AcpiOsFree(b.Pointer);
	ACPI_SERIAL_END(aibs);

	switch (st) {
	case AIBS_VOLT:
		break;
	case AIBS_TEMP:
		v += 2731;
		l += 2731;
		h += 2731;
		break;
	case AIBS_FAN:
		break;
	}
	so[0] = v;
	so[1] = l;
	so[2] = h;
	return sysctl_handle_opaque(oidp, &so, sizeof(so), req);
}
Example #28
0
static int
acpi_smbat_get_bif(device_t dev, struct acpi_bif *bif)
{
	struct acpi_smbat_softc *sc;
	int error;
	uint32_t factor;
	uint16_t val;
	uint8_t addr;

	ACPI_SERIAL_BEGIN(smbat);

	addr = SMBATT_ADDRESS;
	error = ENXIO;
	sc = device_get_softc(dev);

	if (!acpi_smbat_info_expired(&sc->bif_lastupdated)) {
		error = 0;
		goto out;
	}

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val))
		goto out;
	if (val & SMBATT_BM_CAPACITY_MODE) {
		factor = 10;
		sc->bif.units = ACPI_BIF_UNITS_MW;
	} else {
		factor = 1;
		sc->bif.units = ACPI_BIF_UNITS_MA;
	}

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_CAPACITY, &val))
		goto out;
	sc->bif.dcap = val * factor;

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_FULL_CHARGE_CAPACITY, &val))
		goto out;
	sc->bif.lfcap = val * factor;
	sc->bif.btech = 1;		/* secondary (rechargeable) */

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_VOLTAGE, &val))
		goto out;
	sc->bif.dvol = val;

	sc->bif.wcap = sc->bif.dcap / 10;
	sc->bif.lcap = sc->bif.dcap / 10;

	sc->bif.gra1 = factor;	/* not supported */
	sc->bif.gra2 = factor;	/* not supported */

	if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_NAME,
	    sc->bif.model, sizeof(sc->bif.model)))
		goto out;

	if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_SERIAL_NUMBER, &val))
		goto out;
	snprintf(sc->bif.serial, sizeof(sc->bif.serial), "0x%04x", val);

	if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_CHEMISTRY,
	    sc->bif.type, sizeof(sc->bif.type)))
		goto out;

	if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_MANUFACTURER_DATA,
	    sc->bif.oeminfo, sizeof(sc->bif.oeminfo)))
		goto out;

	/* XXX check if device was replugged during read? */

	acpi_smbat_info_updated(&sc->bif_lastupdated);
	error = 0;

out:
	if (error == 0)
		memcpy(bif, &sc->bif, sizeof(sc->bif));
	ACPI_SERIAL_END(smbat);
	return (error);
}
Example #29
0
void
acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
    int pin)
{
	struct link *link;
	uint8_t bios_irq;
	uintptr_t bus;

	/*
	 * Look up the PCI bus for the specified PCI bridge device.  Note
	 * that the PCI bridge device might not have any children yet.
	 * However, looking up its bus number doesn't require a valid child
	 * device, so we just pass NULL.
	 */
	if (BUS_READ_IVAR(pcib, NULL, PCIB_IVAR_BUS, &bus) != 0) {
		device_printf(pcib, "Unable to read PCI bus number");
		panic("PCI bridge without a bus number");
	}
		
	/* Bump the reference count. */
	ACPI_SERIAL_BEGIN(pci_link);
	link = acpi_pci_link_lookup(dev, index);
	if (link == NULL) {
		device_printf(dev, "apparently invalid index %d\n", index);
		ACPI_SERIAL_END(pci_link);
		return;
	}
	link->l_references++;
	if (link->l_routed)
		pci_link_interrupt_weights[link->l_irq]++;

	/*
	 * The BIOS only routes interrupts via ISA IRQs using the ATPICs
	 * (8259As).  Thus, if this link is routed via an ISA IRQ, go
	 * look to see if the BIOS routed an IRQ for this link at the
	 * indicated (bus, slot, pin).  If so, we prefer that IRQ for
	 * this link and add that IRQ to our list of known-good IRQs.
	 * This provides a good work-around for link devices whose _CRS
	 * method is either broken or bogus.  We only use the value
	 * returned by _CRS if we can't find a valid IRQ via this method
	 * in fact.
	 *
	 * If this link is not routed via an ISA IRQ (because we are using
	 * APIC for example), then don't bother looking up the BIOS IRQ
	 * as if we find one it won't be valid anyway.
	 */
	if (!link->l_isa_irq) {
		ACPI_SERIAL_END(pci_link);
		return;
	}

	/* Try to find a BIOS IRQ setting from any matching devices. */
	bios_irq = acpi_pci_link_search_irq(bus, slot, pin);
	if (!PCI_INTERRUPT_VALID(bios_irq)) {
		ACPI_SERIAL_END(pci_link);
		return;
	}

	/* Validate the BIOS IRQ. */
	if (!link_valid_irq(link, bios_irq)) {
		device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n",
		    bios_irq, (int)bus, slot, pin + 'A');
	} else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) {
		link->l_bios_irq = bios_irq;
		if (bios_irq < NUM_ISA_INTERRUPTS)
			pci_link_bios_isa_irqs |= (1 << bios_irq);
		if (bios_irq != link->l_initial_irq &&
		    PCI_INTERRUPT_VALID(link->l_initial_irq))
			device_printf(dev,
			    "BIOS IRQ %u does not match initial IRQ %u\n",
			    bios_irq, link->l_initial_irq);
	} else if (bios_irq != link->l_bios_irq)
		device_printf(dev,
	    "BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n",
		    bios_irq, (int)bus, slot, pin + 'A',
		    link->l_bios_irq);
	ACPI_SERIAL_END(pci_link);
}
Example #30
0
static int
acpi_pci_link_attach(device_t dev)
{
	struct acpi_pci_link_softc *sc;
	struct link_count_request creq;
	struct link_res_request rreq;
	ACPI_STATUS status;
	int i;

	sc = device_get_softc(dev);
	sc->pl_dev = dev;
	ACPI_SERIAL_BEGIN(pci_link);

	/*
	 * Count the number of current resources so we know how big of
	 * a link array to allocate.  On some systems, _CRS is broken,
	 * so for those systems try to derive the count from _PRS instead.
	 */
	creq.in_dpf = DPF_OUTSIDE;
	creq.count = 0;
	status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
	    acpi_count_irq_resources, &creq);
	sc->pl_crs_bad = ACPI_FAILURE(status);
	if (sc->pl_crs_bad) {
		creq.in_dpf = DPF_OUTSIDE;
		creq.count = 0;
		status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
		    acpi_count_irq_resources, &creq);
		if (ACPI_FAILURE(status)) {
			device_printf(dev,
			    "Unable to parse _CRS or _PRS: %s\n",
			    AcpiFormatException(status));
			ACPI_SERIAL_END(pci_link);
			return (ENXIO);
		}
	}
	sc->pl_num_links = creq.count;
	if (creq.count == 0) {
		ACPI_SERIAL_END(pci_link);
		return (0);
	}
	sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links,
	    M_PCI_LINK, M_WAITOK | M_ZERO);

	/* Initialize the child links. */
	for (i = 0; i < sc->pl_num_links; i++) {
		sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
		sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ;
		sc->pl_links[i].l_sc = sc;
		sc->pl_links[i].l_isa_irq = FALSE;
		sc->pl_links[i].l_res_index = -1;
	}

	/* Try to read the current settings from _CRS if it is valid. */
	if (!sc->pl_crs_bad) {
		rreq.in_dpf = DPF_OUTSIDE;
		rreq.link_index = 0;
		rreq.res_index = 0;
		rreq.sc = sc;
		status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
		    link_add_crs, &rreq);
		if (ACPI_FAILURE(status)) {
			device_printf(dev, "Unable to parse _CRS: %s\n",
			    AcpiFormatException(status));
			goto fail;
		}
	}

	/*
	 * Try to read the possible settings from _PRS.  Note that if the
	 * _CRS is toast, we depend on having a working _PRS.  However, if
	 * _CRS works, then it is ok for _PRS to be missing.
	 */
	rreq.in_dpf = DPF_OUTSIDE;
	rreq.link_index = 0;
	rreq.res_index = 0;
	rreq.sc = sc;
	status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
	    link_add_prs, &rreq);
	if (ACPI_FAILURE(status) &&
	    (status != AE_NOT_FOUND || sc->pl_crs_bad)) {
		device_printf(dev, "Unable to parse _PRS: %s\n",
		    AcpiFormatException(status));
		goto fail;
	}
	if (bootverbose)
		acpi_pci_link_dump(sc, 1, "Initial Probe");

	/* Verify initial IRQs if we have _PRS. */
	if (status != AE_NOT_FOUND)
		for (i = 0; i < sc->pl_num_links; i++)
			if (!link_valid_irq(&sc->pl_links[i],
			    sc->pl_links[i].l_irq))
				sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
	if (bootverbose)
		acpi_pci_link_dump(sc, 0, "Validation");

	/* Save initial IRQs. */
	for (i = 0; i < sc->pl_num_links; i++)
		sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq;

	/*
	 * Try to disable this link.  If successful, set the current IRQ to
	 * zero and flags to indicate this link is not routed.  If we can't
	 * run _DIS (i.e., the method doesn't exist), assume the initial
	 * IRQ was routed by the BIOS.
	 */
	if (ACPI_SUCCESS(AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL,
	    NULL)))
		for (i = 0; i < sc->pl_num_links; i++)
			sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
	else
		for (i = 0; i < sc->pl_num_links; i++)
			if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq))
				sc->pl_links[i].l_routed = TRUE;
	if (bootverbose)
		acpi_pci_link_dump(sc, 0, "After Disable");
	ACPI_SERIAL_END(pci_link);
	return (0);
fail:
	ACPI_SERIAL_END(pci_link);
	for (i = 0; i < sc->pl_num_links; i++)
		if (sc->pl_links[i].l_irqs != NULL)
			free(sc->pl_links[i].l_irqs, M_PCI_LINK);
	free(sc->pl_links, M_PCI_LINK);
	return (ENXIO);
}