1*b525169dSotto /* $OpenBSD: kb3310.c,v 1.8 2010/03/02 09:58:19 otto Exp $ */ 2e1f5be9aSotto /* 3e1f5be9aSotto * Copyright (c) 2010 Otto Moerbeek <otto@drijf.net> 4e1f5be9aSotto * 5e1f5be9aSotto * Permission to use, copy, modify, and distribute this software for any 6e1f5be9aSotto * purpose with or without fee is hereby granted, provided that the above 7e1f5be9aSotto * copyright notice and this permission notice appear in all copies. 8e1f5be9aSotto * 9e1f5be9aSotto * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10e1f5be9aSotto * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11e1f5be9aSotto * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12e1f5be9aSotto * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13e1f5be9aSotto * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14e1f5be9aSotto * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15e1f5be9aSotto * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16e1f5be9aSotto */ 17e1f5be9aSotto 18e1f5be9aSotto #include <sys/param.h> 19e1f5be9aSotto #include <sys/kernel.h> 20e1f5be9aSotto #include <sys/systm.h> 21e1f5be9aSotto #include <sys/device.h> 22e1f5be9aSotto #include <sys/sensors.h> 2399b7edb0Smiod #include <sys/timeout.h> 24e1f5be9aSotto 2513bfa4beSotto #include <machine/apmvar.h> 26e1f5be9aSotto #include <machine/bus.h> 27e1f5be9aSotto #include <dev/isa/isavar.h> 28e1f5be9aSotto 2913bfa4beSotto #include "apm.h" 3099b7edb0Smiod #include "pckbd.h" 3199b7edb0Smiod #include "ukbd.h" 3299b7edb0Smiod 3399b7edb0Smiod #if NPCKBD > 0 || NUKBD > 0 3499b7edb0Smiod #include <dev/ic/pckbcvar.h> 3599b7edb0Smiod #include <dev/pckbc/pckbdvar.h> 3699b7edb0Smiod #include <dev/usb/ukbdvar.h> 3799b7edb0Smiod #endif 3813bfa4beSotto 39e1f5be9aSotto struct cfdriver ykbec_cd = { 40e1f5be9aSotto NULL, "ykbec", DV_DULL, 41e1f5be9aSotto }; 42e1f5be9aSotto 43e1f5be9aSotto #define IO_YKBEC 0x381 44e1f5be9aSotto #define IO_YKBECSIZE 0x3 45e1f5be9aSotto 4613bfa4beSotto static const struct { 4713bfa4beSotto const char *desc; 4813bfa4beSotto int type; 4913bfa4beSotto } ykbec_table[] = { 5013bfa4beSotto #define YKBEC_FAN 0 5113bfa4beSotto { NULL, SENSOR_FANRPM }, 5213bfa4beSotto #define YKBEC_ITEMP 1 5313bfa4beSotto { "Internal temperature", SENSOR_TEMP }, 5413bfa4beSotto #define YKBEC_DCAP 2 5513bfa4beSotto { "Battery design capacity", SENSOR_AMPHOUR }, 5613bfa4beSotto #define YKBEC_FCAP 3 5713bfa4beSotto { "Battery full charge capacity", SENSOR_AMPHOUR }, 5813bfa4beSotto #define YKBEC_DVOLT 4 5913bfa4beSotto { "Battery design voltage", SENSOR_VOLTS_DC }, 6013bfa4beSotto #define YKBEC_BCURRENT 5 6113bfa4beSotto { "Battery current", SENSOR_AMPS }, 6213bfa4beSotto #define YKBEC_BVOLT 6 6313bfa4beSotto { "Battery voltage", SENSOR_VOLTS_DC }, 6413bfa4beSotto #define YKBEC_BTEMP 7 6513bfa4beSotto { "Battery temperature", SENSOR_TEMP }, 6613bfa4beSotto #define YKBEC_CAP 8 6713bfa4beSotto { "Battery capacity", SENSOR_PERCENT }, 6813bfa4beSotto #define YKBEC_CHARGING 9 6913bfa4beSotto { "Battery charging", SENSOR_INDICATOR }, 7013bfa4beSotto #define YKBEC_AC 10 7113bfa4beSotto { "AC-Power", SENSOR_INDICATOR } 7213bfa4beSotto #define YKBEC_NSENSORS 11 7313bfa4beSotto }; 74e1f5be9aSotto 75e1f5be9aSotto struct ykbec_softc { 76e1f5be9aSotto struct device sc_dev; 77e1f5be9aSotto bus_space_tag_t sc_iot; 78e1f5be9aSotto bus_space_handle_t sc_ioh; 7913bfa4beSotto struct ksensor sc_sensor[YKBEC_NSENSORS]; 80e1f5be9aSotto struct ksensordev sc_sensordev; 8199b7edb0Smiod #if NPCKBD > 0 || NUKBD > 0 8299b7edb0Smiod struct timeout sc_bell_tmo; 8399b7edb0Smiod #endif 84e1f5be9aSotto }; 85e1f5be9aSotto 86e1f5be9aSotto int ykbec_match(struct device *, void *, void *); 87e1f5be9aSotto void ykbec_attach(struct device *, struct device *, void *); 88e1f5be9aSotto 89e1f5be9aSotto const struct cfattach ykbec_ca = { 90e1f5be9aSotto sizeof(struct ykbec_softc), ykbec_match, ykbec_attach 91e1f5be9aSotto }; 92e1f5be9aSotto 9399b7edb0Smiod int ykbec_apminfo(struct apm_power_info *); 9499b7edb0Smiod void ykbec_bell(void *, u_int, u_int, u_int, int); 9599b7edb0Smiod void ykbec_bell_stop(void *); 96e1f5be9aSotto u_int ykbec_read(struct ykbec_softc *, u_int); 97e1f5be9aSotto u_int ykbec_read16(struct ykbec_softc *, u_int); 9899b7edb0Smiod void ykbec_refresh(void *arg); 9999b7edb0Smiod void ykbec_write(struct ykbec_softc *, u_int, u_int); 100e1f5be9aSotto 10113bfa4beSotto #if NAPM > 0 10213bfa4beSotto struct apm_power_info ykbec_apmdata; 10313bfa4beSotto const char *ykbec_batstate[] = { 10413bfa4beSotto "high", 10513bfa4beSotto "low", 10613bfa4beSotto "critical", 10713bfa4beSotto "charging", 10813bfa4beSotto "unknown" 10913bfa4beSotto }; 11013bfa4beSotto #define BATTERY_STRING(x) ((x) < nitems(ykbec_batstate) ? \ 11113bfa4beSotto ykbec_batstate[x] : ykbec_batstate[4]) 11213bfa4beSotto #endif 11313bfa4beSotto 114e1f5be9aSotto int 115e1f5be9aSotto ykbec_match(struct device *parent, void *match, void *aux) 116e1f5be9aSotto { 117e1f5be9aSotto struct isa_attach_args *ia = aux; 118e1f5be9aSotto bus_space_handle_t ioh; 119e1f5be9aSotto 120e1f5be9aSotto if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_YKBEC) || 121e1f5be9aSotto /* (ia->ia_iosize != 0 && ia->ia_iosize != IO_YKBECSIZE) || XXX isa.c */ 122e1f5be9aSotto ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 || 123e1f5be9aSotto ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK) 124e1f5be9aSotto return (0); 125e1f5be9aSotto 126e1f5be9aSotto if (bus_space_map(ia->ia_iot, IO_YKBEC, IO_YKBECSIZE, 0, &ioh)) 127e1f5be9aSotto return (0); 128e1f5be9aSotto 129e1f5be9aSotto bus_space_unmap(ia->ia_iot, ioh, IO_YKBECSIZE); 130e1f5be9aSotto 131e1f5be9aSotto ia->ia_iobase = IO_YKBEC; 132e1f5be9aSotto ia->ia_iosize = IO_YKBECSIZE; 133e1f5be9aSotto 134e1f5be9aSotto return (1); 135e1f5be9aSotto } 136e1f5be9aSotto 137e1f5be9aSotto void 138e1f5be9aSotto ykbec_attach( struct device *parent, struct device *self, void *aux) 139e1f5be9aSotto { 140e1f5be9aSotto struct isa_attach_args *ia = aux; 141e1f5be9aSotto struct ykbec_softc *sc = (struct ykbec_softc *)self; 14213bfa4beSotto int i; 143e1f5be9aSotto 144e1f5be9aSotto sc->sc_iot = ia->ia_iot; 145e1f5be9aSotto if (bus_space_map(sc->sc_iot, ia->ia_iobase, ia->ia_iosize, 0, 146e1f5be9aSotto &sc->sc_ioh)) { 147e1f5be9aSotto printf(": couldn't map I/O space"); 148e1f5be9aSotto return; 149e1f5be9aSotto } 150e1f5be9aSotto 151e1f5be9aSotto /* Initialize sensor data. */ 152e1f5be9aSotto strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 153e1f5be9aSotto sizeof(sc->sc_sensordev.xname)); 154e1f5be9aSotto if (sensor_task_register(sc, ykbec_refresh, 5) == NULL) { 155e1f5be9aSotto printf(", unable to register update task\n"); 156e1f5be9aSotto return; 157e1f5be9aSotto } 158e1f5be9aSotto 15999b7edb0Smiod printf("\n"); 16099b7edb0Smiod 16113bfa4beSotto for (i = 0; i < YKBEC_NSENSORS; i++) { 16213bfa4beSotto sc->sc_sensor[i].type = ykbec_table[i].type; 16313bfa4beSotto if (ykbec_table[i].desc) 16413bfa4beSotto strlcpy(sc->sc_sensor[i].desc, ykbec_table[i].desc, 16513bfa4beSotto sizeof(sc->sc_sensor[i].desc)); 16613bfa4beSotto sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 16713bfa4beSotto } 16815562d19Sotto 169e1f5be9aSotto sensordev_install(&sc->sc_sensordev); 170e1f5be9aSotto 17113bfa4beSotto #if NAPM > 0 17299b7edb0Smiod /* make sure we have the apm state initialized before apm attaches */ 17399b7edb0Smiod ykbec_refresh(sc); 17413bfa4beSotto apm_setinfohook(ykbec_apminfo); 17513bfa4beSotto #endif 17699b7edb0Smiod #if NPCKBD > 0 || NUKBD > 0 17799b7edb0Smiod timeout_set(&sc->sc_bell_tmo, ykbec_bell_stop, sc); 17899b7edb0Smiod #if NPCKBD > 0 17999b7edb0Smiod pckbd_hookup_bell(ykbec_bell, sc); 18099b7edb0Smiod #endif 18199b7edb0Smiod #if NUKBD > 0 18299b7edb0Smiod ukbd_hookup_bell(ykbec_bell, sc); 18399b7edb0Smiod #endif 18499b7edb0Smiod #endif 185e1f5be9aSotto } 186e1f5be9aSotto 187e1f5be9aSotto void 188e1f5be9aSotto ykbec_write(struct ykbec_softc *mcsc, u_int reg, u_int datum) 189e1f5be9aSotto { 190e1f5be9aSotto struct ykbec_softc *sc = (struct ykbec_softc *)mcsc; 191e1f5be9aSotto bus_space_tag_t iot = sc->sc_iot; 192e1f5be9aSotto bus_space_handle_t ioh = sc->sc_ioh; 193e1f5be9aSotto 194e1f5be9aSotto bus_space_write_1(iot, ioh, 0, (reg >> 8) & 0xff); 195e1f5be9aSotto bus_space_write_1(iot, ioh, 1, (reg >> 0) & 0xff); 196e1f5be9aSotto bus_space_write_1(iot, ioh, 2, datum); 197e1f5be9aSotto } 198e1f5be9aSotto 199e1f5be9aSotto u_int 200e1f5be9aSotto ykbec_read(struct ykbec_softc *mcsc, u_int reg) 201e1f5be9aSotto { 202e1f5be9aSotto struct ykbec_softc *sc = (struct ykbec_softc *)mcsc; 203e1f5be9aSotto bus_space_tag_t iot = sc->sc_iot; 204e1f5be9aSotto bus_space_handle_t ioh = sc->sc_ioh; 205e1f5be9aSotto 206e1f5be9aSotto bus_space_write_1(iot, ioh, 0, (reg >> 8) & 0xff); 207e1f5be9aSotto bus_space_write_1(iot, ioh, 1, (reg >> 0) & 0xff); 208e1f5be9aSotto return bus_space_read_1(iot, ioh, 2); 209e1f5be9aSotto } 210e1f5be9aSotto 211e1f5be9aSotto u_int 212e1f5be9aSotto ykbec_read16(struct ykbec_softc *mcsc, u_int reg) 213e1f5be9aSotto { 214e1f5be9aSotto u_int val; 215e1f5be9aSotto 216e1f5be9aSotto val = ykbec_read(mcsc, reg); 217e1f5be9aSotto return (val << 8) | ykbec_read(mcsc, reg + 1); 218e1f5be9aSotto } 219e1f5be9aSotto 220e1f5be9aSotto #define KB3310_FAN_SPEED_DIVIDER 480000 221e1f5be9aSotto 222e1f5be9aSotto #define ECTEMP_CURRENT_REG 0xf458 223e1f5be9aSotto #define REG_FAN_SPEED_HIGH 0xfe22 224e1f5be9aSotto #define REG_FAN_SPEED_LOW 0xfe23 225e1f5be9aSotto 226e1f5be9aSotto #define REG_DESIGN_CAP_HIGH 0xf77d 227e1f5be9aSotto #define REG_DESIGN_CAP_LOW 0xf77e 228e1f5be9aSotto #define REG_FULLCHG_CAP_HIGH 0xf780 229e1f5be9aSotto #define REG_FULLCHG_CAP_LOW 0xf781 230e1f5be9aSotto 231e1f5be9aSotto #define REG_DESIGN_VOL_HIGH 0xf782 232e1f5be9aSotto #define REG_DESIGN_VOL_LOW 0xf783 233e1f5be9aSotto #define REG_CURRENT_HIGH 0xf784 234e1f5be9aSotto #define REG_CURRENT_LOW 0xf785 235e1f5be9aSotto #define REG_VOLTAGE_HIGH 0xf786 236e1f5be9aSotto #define REG_VOLTAGE_LOW 0xf787 237e1f5be9aSotto #define REG_TEMPERATURE_HIGH 0xf788 238e1f5be9aSotto #define REG_TEMPERATURE_LOW 0xf789 239e1f5be9aSotto #define REG_RELATIVE_CAT_HIGH 0xf492 240e1f5be9aSotto #define REG_RELATIVE_CAT_LOW 0xf493 241e1f5be9aSotto #define REG_BAT_VENDOR 0xf4c4 242e1f5be9aSotto #define REG_BAT_CELL_COUNT 0xf4c6 24315562d19Sotto 244e1f5be9aSotto #define REG_BAT_CHARGE 0xf4a2 24515562d19Sotto #define BAT_CHARGE_AC 0x00 24615562d19Sotto #define BAT_CHARGE_DISCHARGE 0x01 24715562d19Sotto #define BAT_CHARGE_CHARGE 0x02 24815562d19Sotto 249e1f5be9aSotto #define REG_POWER_FLAG 0xf440 25015562d19Sotto #define POWER_FLAG_ADAPTER_IN (1<<0) 25115562d19Sotto #define POWER_FLAG_POWER_ON (1<<1) 25215562d19Sotto #define POWER_FLAG_ENTER_SUS (1<<2) 253e1f5be9aSotto 254e1f5be9aSotto #define REG_BAT_STATUS 0xf4b0 255e1f5be9aSotto #define BAT_STATUS_BAT_EXISTS (1<<0) 256e1f5be9aSotto #define BAT_STATUS_BAT_FULL (1<<1) 257e1f5be9aSotto #define BAT_STATUS_BAT_DESTROY (1<<2) 258e1f5be9aSotto #define BAT_STATUS_BAT_LOW (1<<5) 259e1f5be9aSotto 260e1f5be9aSotto #define REG_CHARGE_STATUS 0xf4b1 261e1f5be9aSotto #define CHARGE_STATUS_PRECHARGE (1<<1) 262e1f5be9aSotto #define CHARGE_STATUS_OVERHEAT (1<<2) 263e1f5be9aSotto 264e1f5be9aSotto #define REG_BAT_STATE 0xf482 265e1f5be9aSotto #define BAT_STATE_DISCHARGING (1<<0) 266e1f5be9aSotto #define BAT_STATE_CHARGING (1<<1) 267e1f5be9aSotto 26899b7edb0Smiod #define REG_BEEP_CONTROL 0xf4d0 26999b7edb0Smiod #define BEEP_ENABLE (1<<0) 27099b7edb0Smiod 271e1f5be9aSotto void 272e1f5be9aSotto ykbec_refresh(void *arg) 273e1f5be9aSotto { 274e1f5be9aSotto struct ykbec_softc *sc = (struct ykbec_softc *)arg; 27515562d19Sotto u_int val, bat_charge, bat_status, charge_status, bat_state, power_flag; 27613bfa4beSotto u_int cap_pct, fullcap; 277e1f5be9aSotto int current; 27813bfa4beSotto #if NAPM > 0 27913bfa4beSotto struct apm_power_info old; 28013bfa4beSotto #endif 281e1f5be9aSotto 2825175924aSotto val = ykbec_read16(sc, REG_FAN_SPEED_HIGH) & 0xfffff; 28313bfa4beSotto if (val != 0) { 284e1f5be9aSotto val = KB3310_FAN_SPEED_DIVIDER / val; 28513bfa4beSotto sc->sc_sensor[YKBEC_FAN].value = val; 286*b525169dSotto CLR(sc->sc_sensor[YKBEC_FAN].flags, SENSOR_FINVALID); 28713bfa4beSotto } else 288*b525169dSotto SET(sc->sc_sensor[YKBEC_FAN].flags, SENSOR_FINVALID); 289e1f5be9aSotto 290e1f5be9aSotto val = ykbec_read(sc, ECTEMP_CURRENT_REG); 29113bfa4beSotto sc->sc_sensor[YKBEC_ITEMP].value = val * 1000000 + 273150000; 292e1f5be9aSotto 29313bfa4beSotto sc->sc_sensor[YKBEC_DCAP].value = ykbec_read16(sc, REG_DESIGN_CAP_HIGH) 29413bfa4beSotto * 1000; 29513bfa4beSotto fullcap = ykbec_read16(sc, REG_FULLCHG_CAP_HIGH); 29613bfa4beSotto sc->sc_sensor[YKBEC_FCAP].value = fullcap * 1000; 29713bfa4beSotto sc->sc_sensor[YKBEC_DVOLT].value = ykbec_read16(sc, REG_DESIGN_VOL_HIGH) 29813bfa4beSotto * 1000; 2995175924aSotto 300e1f5be9aSotto current = ykbec_read16(sc, REG_CURRENT_HIGH); 3015175924aSotto /* sign extend short -> int, int -> int64 will be done next statement */ 3025175924aSotto current |= -(current & 0x8000); 30313bfa4beSotto sc->sc_sensor[YKBEC_BCURRENT].value = -1000 * current; 3045175924aSotto 30513bfa4beSotto sc->sc_sensor[YKBEC_BVOLT].value = ykbec_read16(sc, REG_VOLTAGE_HIGH) * 30613bfa4beSotto 1000; 307e1f5be9aSotto 308e1f5be9aSotto val = ykbec_read16(sc, REG_TEMPERATURE_HIGH); 30913bfa4beSotto sc->sc_sensor[YKBEC_BTEMP].value = val * 1000000 + 273150000; 310e1f5be9aSotto 31113bfa4beSotto cap_pct = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH); 31213bfa4beSotto sc->sc_sensor[YKBEC_CAP].value = cap_pct * 1000; 313e1f5be9aSotto 31415562d19Sotto bat_charge = ykbec_read(sc, REG_BAT_CHARGE); 31515562d19Sotto bat_status = ykbec_read(sc, REG_BAT_STATUS); 31615562d19Sotto charge_status = ykbec_read(sc, REG_CHARGE_STATUS); 31715562d19Sotto bat_state = ykbec_read(sc, REG_BAT_STATE); 31815562d19Sotto power_flag = ykbec_read(sc, REG_POWER_FLAG); 319e1f5be9aSotto 320*b525169dSotto sc->sc_sensor[YKBEC_CHARGING].value = !!ISSET(bat_state, 321*b525169dSotto BAT_STATE_CHARGING); 322*b525169dSotto sc->sc_sensor[YKBEC_AC].value = !!ISSET(power_flag, 323*b525169dSotto POWER_FLAG_ADAPTER_IN); 324*b525169dSotto 325*b525169dSotto sc->sc_sensor[YKBEC_CAP].status = ISSET(bat_status, BAT_STATUS_BAT_LOW) ? 326*b525169dSotto SENSOR_S_CRIT : SENSOR_S_OK; 32713bfa4beSotto 32813bfa4beSotto #if NAPM > 0 32913bfa4beSotto bcopy(&ykbec_apmdata, &old, sizeof(old)); 33013bfa4beSotto ykbec_apmdata.battery_life = cap_pct; 331*b525169dSotto ykbec_apmdata.ac_state = ISSET(power_flag, POWER_FLAG_ADAPTER_IN) ? 33213bfa4beSotto APM_AC_ON : APM_AC_OFF; 333*b525169dSotto if (!ISSET(bat_status, BAT_STATUS_BAT_EXISTS)) { 33413bfa4beSotto ykbec_apmdata.battery_state = APM_BATTERY_ABSENT; 33513bfa4beSotto ykbec_apmdata.minutes_left = 0; 33613bfa4beSotto ykbec_apmdata.battery_life = 0; 33713bfa4beSotto } else { 338*b525169dSotto if (ISSET(bat_state, BAT_STATE_CHARGING)) 33913bfa4beSotto ykbec_apmdata.battery_state = APM_BATT_CHARGING; 340*b525169dSotto else if (ISSET(bat_status, BAT_STATUS_BAT_LOW)) 341*b525169dSotto ykbec_apmdata.battery_state = APM_BATT_CRITICAL; 342c50a8308Sotto /* XXX arbitrary */ 343c50a8308Sotto else if (cap_pct > 60) 34413bfa4beSotto ykbec_apmdata.battery_state = APM_BATT_HIGH; 34513bfa4beSotto else 34613bfa4beSotto ykbec_apmdata.battery_state = APM_BATT_LOW; 34713bfa4beSotto 348c50a8308Sotto /* if charging, current is positive */ 349*b525169dSotto if (ISSET(bat_state, BAT_STATE_CHARGING)) 350c50a8308Sotto current = 0; 351c50a8308Sotto else 35213bfa4beSotto current = -current; 353c50a8308Sotto /* XXX Yeeloong draw is about 1A */ 35413bfa4beSotto if (current <= 0) 35513bfa4beSotto current = 1000; 356c50a8308Sotto /* XXX at 5?%, the Yeeloong shuts down */ 35713bfa4beSotto if (cap_pct <= 5) 35813bfa4beSotto cap_pct = 0; 35913bfa4beSotto else 36013bfa4beSotto cap_pct -= 5; 36113bfa4beSotto fullcap = cap_pct * 60 * fullcap / 100; 36213bfa4beSotto ykbec_apmdata.minutes_left = fullcap / current; 36313bfa4beSotto 36413bfa4beSotto } 36513bfa4beSotto if (old.ac_state != ykbec_apmdata.ac_state) 36613bfa4beSotto apm_record_event(APM_POWER_CHANGE, "AC power", 36713bfa4beSotto ykbec_apmdata.ac_state ? "restored" : "lost"); 36813bfa4beSotto if (old.battery_state != ykbec_apmdata.battery_state) 36913bfa4beSotto apm_record_event(APM_POWER_CHANGE, "battery", 37013bfa4beSotto BATTERY_STRING(ykbec_apmdata.battery_state)); 37113bfa4beSotto #endif 37213bfa4beSotto } 37313bfa4beSotto 37413bfa4beSotto 37513bfa4beSotto #if NAPM > 0 37613bfa4beSotto int 37713bfa4beSotto ykbec_apminfo(struct apm_power_info *info) 37813bfa4beSotto { 37913bfa4beSotto bcopy(&ykbec_apmdata, info, sizeof(struct apm_power_info)); 38013bfa4beSotto return 0; 38113bfa4beSotto } 38299b7edb0Smiod #endif 38313bfa4beSotto 38499b7edb0Smiod #if NPCKBD > 0 || NUKBD > 0 38599b7edb0Smiod void 38699b7edb0Smiod ykbec_bell(void *arg, u_int pitch, u_int period, u_int volume, int poll) 38799b7edb0Smiod { 38899b7edb0Smiod struct ykbec_softc *sc = (struct ykbec_softc *)arg; 38999b7edb0Smiod int bctrl; 39099b7edb0Smiod int s; 39199b7edb0Smiod 39299b7edb0Smiod s = spltty(); 39399b7edb0Smiod bctrl = ykbec_read(sc, REG_BEEP_CONTROL); 39499b7edb0Smiod if (volume == 0 || timeout_pending(&sc->sc_bell_tmo)) { 39599b7edb0Smiod timeout_del(&sc->sc_bell_tmo); 39699b7edb0Smiod /* inline ykbec_bell_stop(arg); */ 39799b7edb0Smiod ykbec_write(sc, REG_BEEP_CONTROL, bctrl & ~BEEP_ENABLE); 39899b7edb0Smiod } 39999b7edb0Smiod 40099b7edb0Smiod if (volume != 0) { 40199b7edb0Smiod ykbec_write(sc, REG_BEEP_CONTROL, bctrl | BEEP_ENABLE); 40299b7edb0Smiod if (poll) { 40399b7edb0Smiod delay(period * 1000); 40499b7edb0Smiod ykbec_write(sc, REG_BEEP_CONTROL, bctrl & ~BEEP_ENABLE); 40599b7edb0Smiod } else { 40699b7edb0Smiod timeout_add_msec(&sc->sc_bell_tmo, period); 40799b7edb0Smiod } 40899b7edb0Smiod } 40999b7edb0Smiod splx(s); 41099b7edb0Smiod } 41199b7edb0Smiod 41299b7edb0Smiod void 41399b7edb0Smiod ykbec_bell_stop(void *arg) 41499b7edb0Smiod { 41599b7edb0Smiod struct ykbec_softc *sc = (struct ykbec_softc *)arg; 41699b7edb0Smiod int s; 41799b7edb0Smiod 41899b7edb0Smiod s = spltty(); 41999b7edb0Smiod ykbec_write(sc, REG_BEEP_CONTROL, 42099b7edb0Smiod ykbec_read(sc, REG_BEEP_CONTROL) & ~BEEP_ENABLE); 42199b7edb0Smiod splx(s); 42299b7edb0Smiod } 42313bfa4beSotto #endif 424