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