示例#1
0
/* for debugging, print out all the data about the status of devices */
void
wds_print(void)
{
	int	unit;
	int	i;
	struct	wds_req *r;
	struct	wds     *wp;

	for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) {
		wp = (struct wds *) devclass_get_device(wds_devclass, unit);
		if (wp == NULL)
			continue;
		printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n",
		       unit, wp->want_wdsr, inb(wp->addr + WDS_STAT) & 0xff,
		       (inb(wp->addr + WDS_STAT) & WDS_IRQ) ? "ready" : "no",
		       inb(wp->addr + WDS_IRQSTAT) & 0xff);
		for (i = 0; i < MAXSIMUL; i++) {
			r = &wp->dx->req[i];
			if( wp->wdsr_free & (1 << r->id) ) {
				printf("req=%d flg=0x%x ombn=%d ombstat=%d "
				       "mask=0x%x targ=%d lun=%d cmd=0x%x\n",
				       i, r->flags, r->ombn,
				       wp->dx->ombs[r->ombn].stat,
				       r->mask, r->cmd.targ >> 5,
				       r->cmd.targ & 7, r->cmd.scb[0]);
			}
		}
	}
示例#2
0
int
ata_pci_attach(device_t dev)
{
    struct ata_pci_controller *ctlr = device_get_softc(dev);
    u_int32_t cmd;
    int unit;

    /* do chipset specific setups only needed once */
    ctlr->legacy = ata_legacy(dev);
    if (ctlr->legacy || pci_read_config(dev, PCIR_BAR(2), 4) & IOMASK)
	ctlr->channels = 2;
    else
	ctlr->channels = 1;
    ctlr->allocate = ata_pci_allocate;
    ctlr->dev = dev;

    /* if needed try to enable busmastering */
    cmd = pci_read_config(dev, PCIR_COMMAND, 2);
    if (!(cmd & PCIM_CMD_BUSMASTEREN)) {
	pci_write_config(dev, PCIR_COMMAND, cmd | PCIM_CMD_BUSMASTEREN, 2);
	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
    }

    /* if busmastering mode "stuck" use it */
    if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) {
	ctlr->r_type1 = SYS_RES_IOPORT;
	ctlr->r_rid1 = ATA_BMADDR_RID;
	ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, &ctlr->r_rid1,
					      RF_ACTIVE);
	/* Only set a dma init function if the device actually supports it. */
        ctlr->dmainit = ata_pci_dmainit;
    }

    if (ctlr->chipinit(dev))
	return ENXIO;

    /* attach all channels on this controller */
    for (unit = 0; unit < ctlr->channels; unit++) {
	int freeunit = 2;
	if ((unit == 0 || unit == 1) && ctlr->legacy) {
	    device_add_child(dev, "ata", unit);
	    continue;
	}
	/* XXX TGEN devclass_find_free_unit() implementation */
	if (ata_devclass) {
		while (freeunit < devclass_get_maxunit(ata_devclass) &&
		    devclass_get_device(ata_devclass, freeunit) != NULL)
			freeunit++;
	}
	device_add_child(dev, "ata", freeunit);
    }
    bus_generic_attach(dev);
    return 0;
}
示例#3
0
static void
ata_boot_attach(void)
{
    struct ata_channel *ch;
    int ctlr;

    get_mplock();

    /* kick of probe and attach on all channels */
    for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) {
	if ((ch = devclass_get_softc(ata_devclass, ctlr))) {
	    ata_identify(ch->dev);
	}
    }

    rel_mplock();
}
示例#4
0
sc_softc_t
*sc_find_softc(struct video_adapter *adp, struct keyboard *kbd)
{
	sc_softc_t *sc;
	int i;
	int units;

	sc = &main_softc;
	if ((adp == NULL || adp == sc->adp) &&
	    (kbd == NULL || kbd == sc->kbd))
		return (sc);
	units = devclass_get_maxunit(sc_devclass);
	for (i = 0; i < units; ++i) {
	        sc = device_get_softc(devclass_get_device(sc_devclass, i));
		if (sc == NULL)
			continue;
		if ((adp == NULL || adp == sc->adp) &&
		    (kbd == NULL || kbd == sc->kbd))
			return (sc);
	}
	return (NULL);
}
示例#5
0
static device_t
find_masterdev(sc_p scp)
{
	int i, units;
	devclass_t devclass;
	device_t dev;

	devclass = device_get_devclass(scp->dev);
	units = devclass_get_maxunit(devclass);
	dev = NULL;
	for (i = 0 ; i < units ; i++) {
		dev = devclass_get_device(devclass, i);
		if (isa_get_vendorid(dev) == isa_get_vendorid(scp->dev)
		    && isa_get_logicalid(dev) == LOGICALID_PCM
		    && isa_get_serial(dev) == isa_get_serial(scp->dev))
			break;
	}
	if (i == units)
		return (NULL);

	return (dev);
}
/*
 * The battery interface deals with devices and methods but userland
 * expects a logical unit number.  Convert a logical unit to a device_t.
 */
static device_t
acpi_battery_find_dev(u_int logical_unit)
{
    int found_unit, i, maxunit;
    device_t dev;
    devclass_t batt_dc;

    dev = NULL;
    found_unit = 0;
    batt_dc = devclass_find("battery");
    maxunit = devclass_get_maxunit(batt_dc);
    for (i = 0; i < maxunit; i++) {
	dev = devclass_get_device(batt_dc, i);
	if (dev == NULL)
	    continue;
	if (logical_unit == found_unit)
	    break;
	found_unit++;
	dev = NULL;
    }

    return (dev);
}
static void
ata_boot_attach(void)
{
    struct ata_channel *ch;
    int ctlr;

    mtx_lock(&Giant);       /* newbus suckage it needs Giant */

    /* kick of probe and attach on all channels */
    for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) {
	if ((ch = devclass_get_softc(ata_devclass, ctlr))) {
	    ata_identify(ch->dev);
	}
    }

    /* release the hook that got us here, we are only needed once during boot */
    if (ata_delayed_attach) {
	config_intrhook_disestablish(ata_delayed_attach);
	free(ata_delayed_attach, M_TEMP);
	ata_delayed_attach = NULL;
    }

    mtx_unlock(&Giant);     /* newbus suckage dealt with, release Giant */
}
示例#8
0
int
sc_max_unit(void)
{

	return (devclass_get_maxunit(sc_devclass));
}
示例#9
0
static void 
ata_boot_attach(void)
{
    struct ata_channel *ch;
    int ctlr, s;

    if (ata_delayed_attach) {
	config_intrhook_disestablish(ata_delayed_attach);
	free(ata_delayed_attach, M_TEMP);
	ata_delayed_attach = NULL;
    }
    s = splbio();

    /*
     * run through all ata devices and look for real ATA & ATAPI devices
     * using the hints we found in the early probe, this avoids some of
     * the delays probing of non-exsistent devices can cause.
     */
    for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
	if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
	    continue;
	if (ch->devices & ATA_ATA_SLAVE)
	    if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY))
		ch->devices &= ~ATA_ATA_SLAVE;
	if (ch->devices & ATA_ATAPI_SLAVE)
	    if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY))
		ch->devices &= ~ATA_ATAPI_SLAVE;
	if (ch->devices & ATA_ATA_MASTER)
	    if (ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY))
		ch->devices &= ~ATA_ATA_MASTER;
	if (ch->devices & ATA_ATAPI_MASTER)
	    if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY))
		ch->devices &= ~ATA_ATAPI_MASTER;
    }

#if NATADISK > 0
    /* now we know whats there, do the real attach, first the ATA disks */
    for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
	if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
	    continue;
	if (ch->devices & ATA_ATA_MASTER)
	    ad_attach(&ch->device[MASTER], 0);
	if (ch->devices & ATA_ATA_SLAVE)
	    ad_attach(&ch->device[SLAVE], 0);
    }
    ata_raid_attach();
#endif
#if DEV_ATAPIALL
    /* then the atapi devices */
    for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
	if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
	    continue;
	if (ch->devices & ATA_ATAPI_MASTER)
	    atapi_attach(&ch->device[MASTER], 0);
	if (ch->devices & ATA_ATAPI_SLAVE)
	    atapi_attach(&ch->device[SLAVE], 0);
#if NATAPICAM > 0
	atapi_cam_attach_bus(ch);
#endif
    }
#endif
    splx(s);
}
示例#10
0
static int
atausb_attach(device_t dev)
{
    struct atausb_softc *sc = device_get_softc(dev);
    struct usb_attach_arg *uaa = device_get_ivars(dev);
    usb_interface_descriptor_t *id;
    usb_endpoint_descriptor_t *ed;
    usbd_device_handle udev;
    usb_device_request_t request;
    char devinfo[1024], *proto, *subclass;
    u_int8_t maxlun;
    int err, i;

    sc->dev = dev;
    usbd_devinfo(uaa->device, 0, devinfo);
    device_set_desc_copy(dev, devinfo);
    sc->bulkin = sc->bulkout = sc->bulkirq = -1;
    sc->bulkin_pipe = sc->bulkout_pipe= sc->bulkirq_pipe = NULL;
    sc->iface = uaa->iface;
    sc->ifaceno = uaa->ifaceno;
    sc->maxlun = 0;
    sc->timeout = 5000;
    sc->locked_ch = NULL;
    sc->restart_ch = NULL;
    spin_init(&sc->locked_mtx); 

    id = usbd_get_interface_descriptor(sc->iface);
    switch (id->bInterfaceProtocol) {
    case UIPROTO_MASS_BBB:
    case UIPROTO_MASS_BBB_OLD:
	    proto = "Bulk-Only";
	    break;
    case UIPROTO_MASS_CBI:
	    proto = "CBI";
	    break;
    case UIPROTO_MASS_CBI_I:
	    proto = "CBI with CCI";
	    break;
    default:
	    proto = "Unknown";
    }
    switch (id->bInterfaceSubClass) {
    case UISUBCLASS_RBC:
	    subclass = "RBC";
	    break;
    case UISUBCLASS_QIC157:
    case UISUBCLASS_SFF8020I:
    case UISUBCLASS_SFF8070I:
	    subclass = "ATAPI";
	    break;
    case UISUBCLASS_SCSI:
	    subclass = "SCSI";
	    break;
    case UISUBCLASS_UFI:
	    subclass = "UFI";
	    break;
    default:
	    subclass = "Unknown";
    }
    device_printf(dev, "using %s over %s\n", subclass, proto);
    if (strcmp(proto, "Bulk-Only") ||
	(strcmp(subclass, "ATAPI") && strcmp(subclass, "SCSI")))
	return ENXIO;

    for (i = 0 ; i < id->bNumEndpoints ; i++) {
	if (!(ed = usbd_interface2endpoint_descriptor(sc->iface, i))) {
	    device_printf(sc->dev, "could not read endpoint descriptor\n");
	    return ENXIO;
	}
	if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
	    (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
	    sc->bulkin = ed->bEndpointAddress;
	}
	if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
	           (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
	    sc->bulkout = ed->bEndpointAddress;
	}
	if (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I &&
	           UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
	           (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
	    sc->bulkirq = ed->bEndpointAddress;
	}
    }

    /* check whether we found at least the endpoints we need */
    if (!sc->bulkin || !sc->bulkout) {
	device_printf(sc->dev, "needed endpoints not found (%d,%d)\n",
		      sc->bulkin, sc->bulkout);
	atausb_detach(dev);
	return ENXIO;
    }

    /* open the pipes */
    if (usbd_open_pipe(sc->iface, sc->bulkout,
		       USBD_EXCLUSIVE_USE, &sc->bulkout_pipe)) {
	device_printf(sc->dev, "cannot open bulkout pipe (%d)\n", sc->bulkout);
	atausb_detach(dev);
	return ENXIO;
    }
    if (usbd_open_pipe(sc->iface, sc->bulkin,
		       USBD_EXCLUSIVE_USE, &sc->bulkin_pipe)) {
	device_printf(sc->dev, "cannot open bulkin pipe (%d)\n", sc->bulkin);
	atausb_detach(dev);
	return ENXIO;
    }
    if (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I) {
	if (usbd_open_pipe(sc->iface, sc->bulkirq,
			   USBD_EXCLUSIVE_USE, &sc->bulkirq_pipe)) {
	    device_printf(sc->dev, "cannot open bulkirq pipe (%d)\n",
	    		  sc->bulkirq);
	    atausb_detach(dev);
	    return ENXIO;
	}
    }
    sc->state = ATAUSB_S_ATTACH;

    /* alloc needed number of transfer handles */
    for (i = 0; i < ATAUSB_T_MAX; i++) {
	sc->transfer[i] = usbd_alloc_xfer(uaa->device);
	if (!sc->transfer[i]) {
	    device_printf(sc->dev, "out of memory\n");
	    atausb_detach(dev);
	    return ENXIO;
	}
    }

    /* driver is ready to process requests here */
    sc->state = ATAUSB_S_IDLE;

    /* get number of devices so we can add matching channels */
    usbd_interface2device_handle(sc->iface, &udev);
    request.bmRequestType = UT_READ_CLASS_INTERFACE;
    request.bRequest = 0xfe; /* GET_MAX_LUN; */
    USETW(request.wValue, 0);
    USETW(request.wIndex, sc->ifaceno);
    USETW(request.wLength, sizeof(maxlun));
    switch ((err = usbd_do_request(udev, &request, &maxlun))) {
    case USBD_NORMAL_COMPLETION:
	if (bootverbose)
	    device_printf(sc->dev, "maxlun=%d\n", maxlun);
	sc->maxlun = maxlun;
	break;
    default:
	if (bootverbose)
	    device_printf(sc->dev, "get maxlun not supported %s\n",
	usbd_errstr(err));
    }

    /* ata channels are children to this USB control device */
    for (i = 0; i <= sc->maxlun; i++) {
	/* XXX TGEN devclass_find_free_unit() implementation */
	int freeunit = 2;
	while (freeunit < devclass_get_maxunit(ata_devclass) &&
	       devclass_get_device(ata_devclass, freeunit) != NULL)
	    freeunit++;
	if (!device_add_child(sc->dev, "ata", freeunit)) {
	    device_printf(sc->dev, "failed to attach ata child device\n");
	    atausb_detach(dev);
	    return ENXIO;
	}
    }
    bus_generic_attach(sc->dev);
    return 0;
}
/*
 * device related interfaces
 */
static int
ata_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
	  int32_t flag, struct thread *td)
{
    device_t device, *children;
    struct ata_ioc_devices *devices = (struct ata_ioc_devices *)data;
    int *value = (int *)data;
    int i, nchildren, error = ENOTTY;

    switch (cmd) {
    case IOCATAGMAXCHANNEL:
	/* In case we have channel 0..n this will return n+1. */
	*value = devclass_get_maxunit(ata_devclass);
	error = 0;
	break;

    case IOCATAREINIT:
	if (*value >= devclass_get_maxunit(ata_devclass) ||
	    !(device = devclass_get_device(ata_devclass, *value)))
	    return ENXIO;
	error = ata_reinit(device);
	break;

    case IOCATAATTACH:
	if (*value >= devclass_get_maxunit(ata_devclass) ||
	    !(device = devclass_get_device(ata_devclass, *value)))
	    return ENXIO;
	/* XXX SOS should enable channel HW on controller */
	error = ata_attach(device);
	break;

    case IOCATADETACH:
	if (*value >= devclass_get_maxunit(ata_devclass) ||
	    !(device = devclass_get_device(ata_devclass, *value)))
	    return ENXIO;
	error = ata_detach(device);
	/* XXX SOS should disable channel HW on controller */
	break;

    case IOCATADEVICES:
	if (devices->channel >= devclass_get_maxunit(ata_devclass) ||
	    !(device = devclass_get_device(ata_devclass, devices->channel)))
	    return ENXIO;
	bzero(devices->name[0], 32);
	bzero(&devices->params[0], sizeof(struct ata_params));
	bzero(devices->name[1], 32);
	bzero(&devices->params[1], sizeof(struct ata_params));
	if (!device_get_children(device, &children, &nchildren)) {
	    for (i = 0; i < nchildren; i++) {
		if (children[i] && device_is_attached(children[i])) {
		    struct ata_device *atadev = device_get_softc(children[i]);

		    if (atadev->unit == ATA_MASTER) {
			strncpy(devices->name[0],
				device_get_nameunit(children[i]), 32);
			bcopy(&atadev->param, &devices->params[0],
			      sizeof(struct ata_params));
		    }
		    if (atadev->unit == ATA_SLAVE) {
			strncpy(devices->name[1],
				device_get_nameunit(children[i]), 32);
			bcopy(&atadev->param, &devices->params[1],
			      sizeof(struct ata_params));
		    }
		}
	    }
	    free(children, M_TEMP);
	    error = 0;
	}
	else
	    error = ENODEV;
	break;

    default:
	if (ata_raid_ioctl_func)
	    error = ata_raid_ioctl_func(cmd, data);
    }
    return error;
}
/* Get info about one or all batteries. */
int
acpi_battery_get_battinfo(device_t dev, struct acpi_battinfo *battinfo)
{
    int	batt_stat, devcount, dev_idx, error, i;
    int total_cap, total_min, valid_rate, valid_units;
    devclass_t batt_dc;
    device_t batt_dev;
    struct acpi_bst *bst;
    struct acpi_bif *bif;
    struct acpi_battinfo *bi;

    /*
     * Get the battery devclass and max unit for battery devices.  If there
     * are none or error, return immediately.
     */
    batt_dc = devclass_find("battery");
    if (batt_dc == NULL)
	return (ENXIO);
    devcount = devclass_get_maxunit(batt_dc);
    if (devcount == 0)
	return (ENXIO);

    /*
     * Allocate storage for all _BST data, their derived battinfo data,
     * and the current battery's _BIF data.
     */
    bst = kmalloc(devcount * sizeof(*bst), M_TEMP, M_WAITOK | M_ZERO);
    bi = kmalloc(devcount * sizeof(*bi), M_TEMP, M_WAITOK | M_ZERO);
    bif = kmalloc(sizeof(*bif), M_TEMP, M_WAITOK | M_ZERO);

    /*
     * Pass 1:  for each battery that is present and valid, get its status,
     * calculate percent capacity remaining, and sum all the current
     * discharge rates.
     */
    dev_idx = -1;
    batt_stat = valid_rate = valid_units = 0;
    for (i = 0; i < devcount; i++) {
	/* Default info for every battery is "not present". */
	acpi_reset_battinfo(&bi[i]);

	/*
	 * Find the device.  Since devcount is in terms of max units, this
	 * may be a sparse array so skip devices that aren't present.
	 */
	batt_dev = devclass_get_device(batt_dc, i);
	if (batt_dev == NULL)
	    continue;

	/* If examining a specific battery and this is it, record its index. */
	if (dev != NULL && dev == batt_dev)
	    dev_idx = i;

	/*
	 * Be sure we can get various info from the battery.  Note that
	 * acpi_BatteryIsPresent() is not enough because smart batteries only
	 * return that the device is present.
	 */
	if (!acpi_BatteryIsPresent(batt_dev) ||
	    ACPI_BATT_GET_STATUS(batt_dev, &bst[i]) != 0 ||
	    ACPI_BATT_GET_INFO(batt_dev, bif) != 0)
	    continue;

	/* If a battery is not installed, we sometimes get strange values. */
	if (!acpi_battery_bst_valid(&bst[i]) ||
	    !acpi_battery_bif_valid(bif))
	    continue;

	/*
	 * Record current state.  If both charging and discharging are set,
	 * ignore the charging flag.
	 */
	valid_units++;
	if ((bst[i].state & ACPI_BATT_STAT_DISCHARG) != 0)
	    bst[i].state &= ~ACPI_BATT_STAT_CHARGING;
	batt_stat |= bst[i].state;
	bi[i].state = bst[i].state;

	/*
	 * If the battery info is in terms of mA, convert to mW by
	 * multiplying by the design voltage.  If the design voltage
	 * is 0 (due to some error reading the battery), skip this
	 * conversion.
	 */
	if (bif->units == ACPI_BIF_UNITS_MA && bif->dvol != 0 && dev == NULL) {
	    bst[i].rate = (bst[i].rate * bif->dvol) / 1000;
	    bst[i].cap = (bst[i].cap * bif->dvol) / 1000;
	    bif->lfcap = (bif->lfcap * bif->dvol) / 1000;
	}

	/*
	 * The calculation above may set bif->lfcap to zero. This was
	 * seen on a laptop with a broken battery. The result of the
	 * division was rounded to zero.
	 */
	if (!acpi_battery_bif_valid(bif))
	    continue;

	/* Calculate percent capacity remaining. */
	bi[i].cap = (100 * bst[i].cap) / bif->lfcap;

	/*
	 * Some laptops report the "design-capacity" instead of the
	 * "real-capacity" when the battery is fully charged.  That breaks
	 * the above arithmetic as it needs to be 100% maximum.
	 */
	if (bi[i].cap > 100)
	    bi[i].cap = 100;

	/*
	 * On systems with more than one battery, they may get used
	 * sequentially, thus bst.rate may only signify the one currently
	 * in use.  For the remaining batteries, bst.rate will be zero,
	 * which makes it impossible to calculate the total remaining time.
	 * Therefore, we sum the bst.rate for batteries in the discharging
	 * state and use the sum to calculate the total remaining time.
	 */
	if (bst[i].rate != ACPI_BATT_UNKNOWN &&
	    (bst[i].state & ACPI_BATT_STAT_DISCHARG) != 0)
	    valid_rate += bst[i].rate;

	/*
	 * Some DSDTs report a negative 16-bit value for the rate and/or
	 * report 0 as 65536.
	 */
	if (acpi_quirks & ACPI_Q_BATT_RATE_ABS &&
	    bif->units == ACPI_BIF_UNITS_MA &&
	    bst[i].rate != ACPI_BATT_UNKNOWN &&
	    (int16_t)bst[i].rate < 0)
		bst[i].rate = abs((int16_t)bst[i].rate);
    }

    /* If the caller asked for a device but we didn't find it, error. */
    if (dev != NULL && dev_idx == -1) {
	error = ENXIO;
	goto out;
    }

    /* Pass 2:  calculate capacity and remaining time for all batteries. */
    total_cap = total_min = 0;
    for (i = 0; i < devcount; i++) {
	/*
	 * If any batteries are discharging, use the sum of the bst.rate
	 * values.  Otherwise, we are on AC power, and there is infinite
	 * time remaining for this battery until we go offline.
	 */
	if (valid_rate > 0)
	    bi[i].min = (60 * bst[i].cap) / valid_rate;
	else
	    bi[i].min = 0;
	total_min += bi[i].min;

	/* If this battery is not present, don't use its capacity. */
	if (bi[i].cap != -1)
	    total_cap += bi[i].cap;
    }

    /*
     * Return total battery percent and time remaining.  If there are
     * no valid batteries, report values as unknown.
     */
    if (valid_units > 0) {
	if (dev == NULL) {
	    battinfo->cap = total_cap / valid_units;
	    battinfo->min = total_min;
	    battinfo->state = batt_stat;
	    battinfo->rate = valid_rate;
	} else {
	    battinfo->cap = bi[dev_idx].cap;
	    battinfo->min = bi[dev_idx].min;
	    battinfo->state = bi[dev_idx].state;
	    battinfo->rate = bst[dev_idx].rate;
	}

	/*
	 * If the queried battery has no discharge rate or is charging,
	 * report that we don't know the remaining time.
	 */
	if (valid_rate == 0 || (battinfo->state & ACPI_BATT_STAT_CHARGING))
	    battinfo->min = -1;
    } else
	acpi_reset_battinfo(battinfo);

    error = 0;

out:
    if (bi)
	kfree(bi, M_TEMP);
    if (bif)
	kfree(bif, M_TEMP);
    if (bst)
	kfree(bst, M_TEMP);
    return (error);
}