static int aw_ir_attach(device_t dev) { struct aw_ir_softc *sc; hwreset_t rst_apb; clk_t clk_ir, clk_gate; int err; uint32_t val = 0; clk_ir = clk_gate = NULL; rst_apb = NULL; sc = device_get_softc(dev); sc->dev = dev; if (bus_alloc_resources(dev, aw_ir_spec, sc->res) != 0) { device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); } switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { case A10_IR: sc->fifo_size = 16; break; case A13_IR: sc->fifo_size = 64; break; } /* De-assert reset */ if (hwreset_get_by_ofw_name(dev, 0, "apb", &rst_apb) == 0) { err = hwreset_deassert(rst_apb); if (err != 0) { device_printf(dev, "cannot de-assert reset\n"); goto error; } } /* Reset buffer */ aw_ir_buf_reset(sc); /* Get clocks and enable them */ err = clk_get_by_ofw_name(dev, 0, "apb", &clk_gate); if (err != 0) { device_printf(dev, "Cannot get gate clock\n"); goto error; } err = clk_get_by_ofw_name(dev, 0, "ir", &clk_ir); if (err != 0) { device_printf(dev, "Cannot get IR clock\n"); goto error; } /* Set clock rate */ err = clk_set_freq(clk_ir, AW_IR_BASE_CLK, 0); if (err != 0) { device_printf(dev, "cannot set IR clock rate\n"); goto error; } /* Enable clocks */ err = clk_enable(clk_gate); if (err != 0) { device_printf(dev, "Cannot enable clk gate\n"); goto error; } err = clk_enable(clk_ir); if (err != 0) { device_printf(dev, "Cannot enable IR clock\n"); goto error; } if (bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE, NULL, aw_ir_intr, sc, &sc->intrhand)) { bus_release_resources(dev, aw_ir_spec, sc->res); device_printf(dev, "cannot setup interrupt handler\n"); return (ENXIO); } /* Enable CIR Mode */ WRITE(sc, AW_IR_CTL, AW_IR_CTL_MD); /* * Set clock sample, filter, idle thresholds. * Frequency sample = 3MHz/128 = 23437.5Hz (42.7us) */ val = AW_IR_SAMPLE_128; val |= (AW_IR_RXFILT_VAL | AW_IR_RXIDLE_VAL); val |= (AW_IR_ACTIVE_T | AW_IR_ACTIVE_T_C); WRITE(sc, AW_IR_CIR, val); /* Invert Input Signal */ WRITE(sc, AW_IR_RXCTL, AW_IR_RXCTL_RPPI); /* Clear All RX Interrupt Status */ WRITE(sc, AW_IR_RXSTA, AW_IR_RXSTA_CLEARALL); /* * Enable RX interrupt in case of overflow, packet end * and FIFO available. * RX FIFO Threshold = FIFO size / 2 */ WRITE(sc, AW_IR_RXINT, AW_IR_RXINT_ROI_EN | AW_IR_RXINT_RPEI_EN | AW_IR_RXINT_RAI_EN | AW_IR_RXINT_RAL((sc->fifo_size >> 1) - 1)); /* Enable IR Module */ val = READ(sc, AW_IR_CTL); WRITE(sc, AW_IR_CTL, val | AW_IR_CTL_GEN | AW_IR_CTL_RXEN); sc->sc_evdev = evdev_alloc(); evdev_set_name(sc->sc_evdev, device_get_desc(sc->dev)); evdev_set_phys(sc->sc_evdev, device_get_nameunit(sc->dev)); evdev_set_id(sc->sc_evdev, BUS_HOST, 0, 0, 0); evdev_support_event(sc->sc_evdev, EV_SYN); evdev_support_event(sc->sc_evdev, EV_MSC); evdev_support_msc(sc->sc_evdev, MSC_SCAN); err = evdev_register(sc->sc_evdev); if (err) { device_printf(dev, "failed to register evdev: error=%d\n", err); goto error; } return (0); error: if (clk_gate != NULL) clk_release(clk_gate); if (clk_ir != NULL) clk_release(clk_ir); if (rst_apb != NULL) hwreset_release(rst_apb); evdev_free(sc->sc_evdev); sc->sc_evdev = NULL; /* Avoid double free */ bus_release_resources(dev, aw_ir_spec, sc->res); return (ENXIO); }
/* reset and initialize the device */ static int atkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) { keyboard_t *kbd; atkbd_state_t *state; keymap_t *keymap; accentmap_t *accmap; fkeytab_t *fkeymap; int fkeymap_size; int delay[2]; int *data = (int *)arg; /* data[0]: controller, data[1]: irq */ int error, needfree; #ifdef EVDEV_SUPPORT struct evdev_dev *evdev; char phys_loc[8]; #endif /* XXX */ if (unit == ATKBD_DEFAULT) { *kbdp = kbd = &default_kbd; if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) return 0; state = &default_kbd_state; keymap = &default_keymap; accmap = &default_accentmap; fkeymap = default_fkeytab; fkeymap_size = nitems(default_fkeytab); needfree = 0; } else if (*kbdp == NULL) { *kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT | M_ZERO); state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT | M_ZERO); /* NB: these will always be initialized 'cuz !KBD_IS_PROBED */ keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT); accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT); fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT); fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); needfree = 1; if ((kbd == NULL) || (state == NULL) || (keymap == NULL) || (accmap == NULL) || (fkeymap == NULL)) { error = ENOMEM; goto bad; } } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { return 0; } else { kbd = *kbdp; state = (atkbd_state_t *)kbd->kb_data; bzero(state, sizeof(*state)); keymap = kbd->kb_keymap; accmap = kbd->kb_accentmap; fkeymap = kbd->kb_fkeytab; fkeymap_size = kbd->kb_fkeytab_size; needfree = 0; } if (!KBD_IS_PROBED(kbd)) { state->kbdc = atkbdc_open(data[0]); if (state->kbdc == NULL) { error = ENXIO; goto bad; } kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, 0, 0); bcopy(&key_map, keymap, sizeof(key_map)); bcopy(&accent_map, accmap, sizeof(accent_map)); bcopy(fkey_tab, fkeymap, imin(fkeymap_size * sizeof(fkeymap[0]), sizeof(fkey_tab))); kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); kbd->kb_data = (void *)state; if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */ if (flags & KB_CONF_FAIL_IF_NO_KBD) { error = ENXIO; goto bad; } } else { KBD_FOUND_DEVICE(kbd); } atkbd_clear_state(kbd); state->ks_mode = K_XLATE; /* * FIXME: set the initial value for lock keys in ks_state * according to the BIOS data? */ KBD_PROBE_DONE(kbd); } if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; if (KBD_HAS_DEVICE(kbd) && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) { kbd_unregister(kbd); error = ENXIO; goto bad; } atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); set_typematic(kbd); delay[0] = kbd->kb_delay1; delay[1] = kbd->kb_delay2; atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); #ifdef EVDEV_SUPPORT /* register as evdev provider on first init */ if (state->ks_evdev == NULL) { snprintf(phys_loc, sizeof(phys_loc), "atkbd%d", unit); evdev = evdev_alloc(); evdev_set_name(evdev, "AT keyboard"); evdev_set_phys(evdev, phys_loc); evdev_set_id(evdev, BUS_I8042, PS2_KEYBOARD_VENDOR, PS2_KEYBOARD_PRODUCT, 0); evdev_set_methods(evdev, kbd, &atkbd_evdev_methods); evdev_support_event(evdev, EV_SYN); evdev_support_event(evdev, EV_KEY); evdev_support_event(evdev, EV_LED); evdev_support_event(evdev, EV_REP); evdev_support_all_known_keys(evdev); evdev_support_led(evdev, LED_NUML); evdev_support_led(evdev, LED_CAPSL); evdev_support_led(evdev, LED_SCROLLL); if (evdev_register_mtx(evdev, &Giant)) evdev_free(evdev); else state->ks_evdev = evdev; state->ks_evdev_state = 0; } #endif KBD_INIT_DONE(kbd); } if (!KBD_IS_CONFIGURED(kbd)) { if (kbd_register(kbd) < 0) { error = ENXIO; goto bad; } KBD_CONFIG_DONE(kbd); } return 0; bad: if (needfree) { if (state != NULL) free(state, M_DEVBUF); if (keymap != NULL) free(keymap, M_DEVBUF); if (accmap != NULL) free(accmap, M_DEVBUF); if (fkeymap != NULL) free(fkeymap, M_DEVBUF); if (kbd != NULL) { free(kbd, M_DEVBUF); *kbdp = NULL; /* insure ref doesn't leak to caller */ } } return error; }