1 /* $NetBSD: joy_eap.c,v 1.17 2021/08/07 16:19:14 thorpej Exp $ */ 2 3 #include <sys/cdefs.h> 4 __KERNEL_RCSID(0, "$NetBSD: joy_eap.c,v 1.17 2021/08/07 16:19:14 thorpej Exp $"); 5 6 #include <sys/param.h> 7 #include <sys/systm.h> 8 #include <sys/kernel.h> 9 #include <sys/device.h> 10 #include <sys/audioio.h> 11 #include <sys/bus.h> 12 13 #include <dev/audio/audio_if.h> 14 15 #include <dev/pci/eapreg.h> 16 #include <dev/pci/eapvar.h> 17 18 #include <dev/ic/joyvar.h> 19 20 struct joy_eap_aa { 21 struct audio_attach_args aa_aaa; 22 bus_space_tag_t aa_iot; 23 bus_space_handle_t aa_ioh; 24 }; 25 26 device_t 27 eap_joy_attach(device_t eapdev, struct eap_gameport_args *gpa) 28 { 29 int i; 30 bus_space_handle_t ioh; 31 u_int32_t icsc; 32 struct joy_eap_aa aa; 33 device_t joydev; 34 35 /* 36 * There are 4 possible locations. Just try to map one of them. 37 * XXX This is questionable for 2 reasons: 38 * - We don't know whether these addresses are usable on our 39 * PCI bus (might be a secondary one). 40 * - PCI probing is early. ISA devices might conflict. 41 */ 42 for (i = 0; i < 4; i++) { 43 if (bus_space_map(gpa->gpa_iot, 0x200 + i * 8, 1, 44 0, &ioh) == 0) 45 break; 46 } 47 if (i == 4) 48 return 0; 49 50 printf("%s: enabling gameport at legacy io port 0x%x\n", 51 device_xname(eapdev), 0x200 + i * 8); 52 53 /* enable gameport on eap */ 54 icsc = bus_space_read_4(gpa->gpa_iot, gpa->gpa_ioh, EAP_ICSC); 55 icsc &= ~E1371_JOY_ASELBITS; 56 icsc |= EAP_JYSTK_EN | E1371_JOY_ASEL(i); 57 bus_space_write_4(gpa->gpa_iot, gpa->gpa_ioh, EAP_ICSC, icsc); 58 59 aa.aa_aaa.type = AUDIODEV_TYPE_AUX; 60 aa.aa_iot = gpa->gpa_iot; 61 aa.aa_ioh = ioh; 62 joydev = config_found(eapdev, &aa, 0, 63 CFARGS(.iattr = "eap")); 64 /* this cannot fail */ 65 KASSERT(joydev != NULL); 66 67 return joydev; 68 } 69 70 int 71 eap_joy_detach(device_t joydev, struct eap_gameport_args *gpa) 72 { 73 int res; 74 struct joy_softc *sc = device_private(joydev); 75 u_int32_t icsc; 76 77 res = config_detach(joydev, 0); 78 if (res) 79 return res; 80 81 /* disable gameport on eap */ 82 icsc = bus_space_read_4(gpa->gpa_iot, gpa->gpa_ioh, EAP_ICSC); 83 icsc &= ~EAP_JYSTK_EN; 84 bus_space_write_4(gpa->gpa_iot, gpa->gpa_ioh, EAP_ICSC, icsc); 85 86 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 1); 87 return 0; 88 } 89 90 static int 91 joy_eap_match(device_t parent, cfdata_t match, void *aux) 92 { 93 struct joy_eap_aa *eaa = aux; 94 95 if (eaa->aa_aaa.type != AUDIODEV_TYPE_AUX) 96 return 0; 97 return 1; 98 } 99 100 static void 101 joy_eap_attach(device_t parent, device_t self, void *aux) 102 { 103 struct joy_softc *sc = device_private(self); 104 struct eap_softc *esc = device_private(parent); 105 struct joy_eap_aa *eaa = aux; 106 107 aprint_normal("\n"); 108 109 sc->sc_iot = eaa->aa_iot; 110 sc->sc_ioh = eaa->aa_ioh; 111 sc->sc_dev = self; 112 sc->sc_lock = &esc->sc_lock; 113 114 joyattach(sc); 115 } 116 117 static int 118 joy_eap_detach(device_t self, int flags) 119 { 120 121 return joydetach(device_private(self), flags); 122 } 123 124 CFATTACH_DECL_NEW(joy_eap, sizeof (struct joy_softc), 125 joy_eap_match, joy_eap_attach, joy_eap_detach, NULL); 126