Line data Source code
1 : /* $OpenBSD: pcppi.c,v 1.13 2016/01/08 15:54:13 jcs Exp $ */
2 : /* $NetBSD: pcppi.c,v 1.1 1998/04/15 20:26:18 drochner Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1996 Carnegie-Mellon University.
6 : * All rights reserved.
7 : *
8 : * Author: Chris G. Demetriou
9 : *
10 : * Permission to use, copy, modify and distribute this software and
11 : * its documentation is hereby granted, provided that both the copyright
12 : * notice and this permission notice appear in all copies of the
13 : * software, derivative works or modified versions, and any portions
14 : * thereof, and that both notices appear in supporting documentation.
15 : *
16 : * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 : * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18 : * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 : *
20 : * Carnegie Mellon requests users of this software to return to
21 : *
22 : * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 : * School of Computer Science
24 : * Carnegie Mellon University
25 : * Pittsburgh PA 15213-3890
26 : *
27 : * any improvements or extensions that they make and grant Carnegie the
28 : * rights to redistribute these changes.
29 : */
30 :
31 : #include <sys/param.h>
32 : #include <sys/systm.h>
33 : #include <sys/kernel.h>
34 : #include <sys/device.h>
35 : #include <sys/errno.h>
36 : #include <sys/timeout.h>
37 :
38 : #include <machine/bus.h>
39 :
40 : #include <dev/isa/isareg.h>
41 : #include <dev/isa/isavar.h>
42 : #include <dev/isa/pcppireg.h>
43 : #include <dev/isa/pcppivar.h>
44 :
45 : #include <dev/ic/i8253reg.h>
46 :
47 : #include "pckbd.h"
48 : #include "hidkbd.h"
49 : #if NPCKBD > 0 || NHIDKBD > 0
50 : #include <dev/ic/pckbcvar.h>
51 : #include <dev/pckbc/pckbdvar.h>
52 : #include <dev/hid/hidkbdvar.h>
53 : void pcppi_kbd_bell(void *, u_int, u_int, u_int, int);
54 : #endif
55 :
56 : struct pcppi_softc {
57 : struct device sc_dv;
58 :
59 : bus_space_tag_t sc_iot;
60 : bus_space_handle_t sc_ppi_ioh, sc_pit1_ioh;
61 :
62 : struct timeout sc_bell_timeout;
63 :
64 : int sc_bellactive, sc_bellpitch;
65 : int sc_slp;
66 : int sc_timeout;
67 : };
68 :
69 : int pcppi_match(struct device *, void *, void *);
70 : void pcppi_attach(struct device *, struct device *, void *);
71 :
72 : struct cfattach pcppi_ca = {
73 : sizeof(struct pcppi_softc), pcppi_match, pcppi_attach,
74 : };
75 :
76 : struct cfdriver pcppi_cd = {
77 : NULL, "pcppi", DV_DULL
78 : };
79 :
80 : static void pcppi_bell_stop(void *);
81 :
82 : #define PCPPIPRI (PZERO - 1)
83 :
84 : int
85 0 : pcppi_match(parent, match, aux)
86 : struct device *parent;
87 : void *match;
88 : void *aux;
89 : {
90 0 : struct isa_attach_args *ia = aux;
91 0 : bus_space_handle_t ppi_ioh, pit1_ioh;
92 : int have_pit1, have_ppi, rv;
93 : u_int8_t v, nv;
94 :
95 : /* If values are hardwired to something that they can't be, punt. */
96 0 : if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_PPI) ||
97 0 : ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 ||
98 0 : ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK)
99 0 : return (0);
100 :
101 : rv = 0;
102 : have_pit1 = have_ppi = 0;
103 :
104 0 : if (bus_space_map(ia->ia_iot, IO_TIMER1, 4, 0, &pit1_ioh))
105 : goto lose;
106 : have_pit1 = 1;
107 0 : if (bus_space_map(ia->ia_iot, IO_PPI, 1, 0, &ppi_ioh))
108 : goto lose;
109 : have_ppi = 1;
110 :
111 : /*
112 : * Check for existence of PPI. Realistically, this is either going to
113 : * be here or nothing is going to be here.
114 : *
115 : * We don't want to have any chance of changing speaker output (which
116 : * this test might, if it crashes in the middle, or something;
117 : * normally it's be to quick to produce anthing audible), but
118 : * many "combo chip" mock-PPI's don't seem to support the top bit
119 : * of Port B as a settable bit. The bottom bit has to be settable,
120 : * since the speaker driver hardware still uses it.
121 : */
122 0 : v = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */
123 0 : bus_space_write_1(ia->ia_iot, ppi_ioh, 0, v ^ 0x01); /* XXX */
124 0 : nv = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */
125 0 : if (((nv ^ v) & 0x01) == 0x01)
126 0 : rv = 1;
127 0 : bus_space_write_1(ia->ia_iot, ppi_ioh, 0, v); /* XXX */
128 0 : nv = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */
129 0 : if (((nv ^ v) & 0x01) != 0x00) {
130 : rv = 0;
131 0 : goto lose;
132 : }
133 :
134 : /*
135 : * We assume that the programmable interval timer is there.
136 : */
137 :
138 : lose:
139 0 : if (have_pit1)
140 0 : bus_space_unmap(ia->ia_iot, pit1_ioh, 4);
141 0 : if (have_ppi)
142 0 : bus_space_unmap(ia->ia_iot, ppi_ioh, 1);
143 0 : if (rv) {
144 0 : ia->ia_iobase = IO_PPI;
145 0 : ia->ia_iosize = 0x1;
146 0 : ia->ia_msize = 0x0;
147 0 : }
148 0 : return (rv);
149 0 : }
150 :
151 : void
152 0 : pcppi_attach(parent, self, aux)
153 : struct device *parent, *self;
154 : void *aux;
155 : {
156 0 : struct pcppi_softc *sc = (struct pcppi_softc *)self;
157 0 : struct isa_attach_args *ia = aux;
158 : bus_space_tag_t iot;
159 0 : struct pcppi_attach_args pa;
160 :
161 0 : timeout_set(&sc->sc_bell_timeout, pcppi_bell_stop, sc);
162 :
163 0 : sc->sc_iot = iot = ia->ia_iot;
164 :
165 0 : if (bus_space_map(iot, IO_TIMER1, 4, 0, &sc->sc_pit1_ioh) ||
166 0 : bus_space_map(iot, IO_PPI, 1, 0, &sc->sc_ppi_ioh))
167 0 : panic("pcppi_attach: couldn't map");
168 :
169 0 : printf("\n");
170 :
171 0 : sc->sc_bellactive = sc->sc_bellpitch = sc->sc_slp = 0;
172 :
173 : /* Provide a beeper for the keyboard, if there isn't one already. */
174 : #if NPCKBD > 0
175 0 : pckbd_hookup_bell(pcppi_kbd_bell, sc);
176 : #endif
177 : #if NHIDKBD > 0
178 0 : hidkbd_hookup_bell(pcppi_kbd_bell, sc);
179 : #endif
180 :
181 0 : pa.pa_cookie = sc;
182 0 : while (config_found(self, &pa, 0))
183 : ;
184 0 : }
185 :
186 : void
187 0 : pcppi_bell(self, pitch, period, slp)
188 : pcppi_tag_t self;
189 : int pitch, period;
190 : int slp;
191 : {
192 0 : struct pcppi_softc *sc = self;
193 : int s1, s2;
194 :
195 0 : s1 = spltty(); /* ??? */
196 0 : if (sc->sc_bellactive) {
197 0 : if (sc->sc_timeout) {
198 0 : sc->sc_timeout = 0;
199 0 : timeout_del(&sc->sc_bell_timeout);
200 0 : }
201 0 : if (sc->sc_slp)
202 0 : wakeup(pcppi_bell_stop);
203 : }
204 0 : if (pitch == 0 || period == 0) {
205 0 : pcppi_bell_stop(sc);
206 0 : sc->sc_bellpitch = 0;
207 0 : splx(s1);
208 0 : return;
209 : }
210 0 : if (!sc->sc_bellactive || sc->sc_bellpitch != pitch) {
211 0 : s2 = splhigh();
212 0 : bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_MODE,
213 : TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
214 0 : bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_CNTR2,
215 : TIMER_DIV(pitch) % 256);
216 0 : bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_CNTR2,
217 : TIMER_DIV(pitch) / 256);
218 0 : splx(s2);
219 : /* enable speaker */
220 0 : bus_space_write_1(sc->sc_iot, sc->sc_ppi_ioh, 0,
221 : bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0)
222 : | PIT_SPKR);
223 0 : }
224 0 : sc->sc_bellpitch = pitch;
225 :
226 0 : sc->sc_bellactive = 1;
227 :
228 0 : if (slp & PCPPI_BELL_POLL) {
229 0 : delay((period * 1000000) / hz);
230 0 : pcppi_bell_stop(sc);
231 0 : } else {
232 0 : sc->sc_timeout = 1;
233 0 : timeout_add(&sc->sc_bell_timeout, period);
234 0 : if (slp & PCPPI_BELL_SLEEP) {
235 0 : sc->sc_slp = 1;
236 0 : tsleep(pcppi_bell_stop, PCPPIPRI | PCATCH, "bell", 0);
237 0 : sc->sc_slp = 0;
238 0 : }
239 : }
240 0 : splx(s1);
241 0 : }
242 :
243 : static void
244 0 : pcppi_bell_stop(arg)
245 : void *arg;
246 : {
247 0 : struct pcppi_softc *sc = arg;
248 : int s;
249 :
250 0 : s = spltty(); /* ??? */
251 0 : sc->sc_timeout = 0;
252 :
253 : /* disable bell */
254 0 : bus_space_write_1(sc->sc_iot, sc->sc_ppi_ioh, 0,
255 : bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0)
256 : & ~PIT_SPKR);
257 0 : sc->sc_bellactive = 0;
258 0 : if (sc->sc_slp)
259 0 : wakeup(pcppi_bell_stop);
260 0 : splx(s);
261 0 : }
262 :
263 : #if NPCKBD > 0 || NHIDKBD > 0
264 : void
265 0 : pcppi_kbd_bell(arg, pitch, period, volume, poll)
266 : void *arg;
267 : u_int pitch, period, volume;
268 : int poll;
269 : {
270 : /*
271 : * Comes in as ms, goes out as ticks; volume ignored.
272 : */
273 0 : pcppi_bell(arg, volume ? pitch : 0, (period * hz) / 1000,
274 0 : poll ? PCPPI_BELL_POLL : 0);
275 0 : }
276 : #endif /* NPCKBD > 0 || NHIDKBD > 0 */
|