1 /* $NetBSD: joy_eap.c,v 1.14 2019/05/08 13:40:19 isaki Exp $ */ 2 3 #include <sys/cdefs.h> 4 __KERNEL_RCSID(0, "$NetBSD: joy_eap.c,v 1.14 2019/05/08 13:40:19 isaki 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 /* this cannot fail */ 64 KASSERT(joydev != NULL); 65 66 return joydev; 67 } 68 69 int 70 eap_joy_detach(device_t joydev, struct eap_gameport_args *gpa) 71 { 72 int res; 73 struct joy_softc *sc = device_private(joydev); 74 u_int32_t icsc; 75 76 res = config_detach(joydev, 0); 77 if (res) 78 return res; 79 80 /* disable gameport on eap */ 81 icsc = bus_space_read_4(gpa->gpa_iot, gpa->gpa_ioh, EAP_ICSC); 82 icsc &= ~EAP_JYSTK_EN; 83 bus_space_write_4(gpa->gpa_iot, gpa->gpa_ioh, EAP_ICSC, icsc); 84 85 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 1); 86 return 0; 87 } 88 89 static int 90 joy_eap_match(device_t parent, cfdata_t match, void *aux) 91 { 92 struct joy_eap_aa *eaa = aux; 93 94 if (eaa->aa_aaa.type != AUDIODEV_TYPE_AUX) 95 return 0; 96 return 1; 97 } 98 99 static void 100 joy_eap_attach(device_t parent, device_t self, void *aux) 101 { 102 struct joy_softc *sc = device_private(self); 103 struct eap_softc *esc = device_private(parent); 104 struct joy_eap_aa *eaa = aux; 105 106 aprint_normal("\n"); 107 108 sc->sc_iot = eaa->aa_iot; 109 sc->sc_ioh = eaa->aa_ioh; 110 sc->sc_dev = self; 111 sc->sc_lock = &esc->sc_lock; 112 113 joyattach(sc); 114 } 115 116 static int 117 joy_eap_detach(device_t self, int flags) 118 { 119 120 return joydetach(device_private(self), flags); 121 } 122 123 CFATTACH_DECL_NEW(joy_eap, sizeof (struct joy_softc), 124 joy_eap_match, joy_eap_attach, joy_eap_detach, NULL); 125