asc.c revision 1.16 1 /* $NetBSD: asc.c,v 1.16 1997/02/03 17:36:00 scottr Exp $ */
2
3 /*-
4 * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo,
5 * Michael L. Finch, Bradley A. Grantham, and
6 * Lawrence A. Kesteloot
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the Alice Group.
20 * 4. The names of the Alice Group or any of its members may not be used
21 * to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /*
37 * ASC driver code and asc_ringbell() support
38 */
39
40 #include <sys/types.h>
41 #include <sys/cdefs.h>
42 #include <sys/errno.h>
43 #include <sys/time.h>
44 #include <sys/systm.h>
45 #include <sys/param.h>
46 #include <sys/device.h>
47
48 #include <machine/autoconf.h>
49 #include <machine/cpu.h>
50 #include <machine/bus.h>
51
52 #include "ascvar.h"
53 #include "obiovar.h"
54
55 #define MAC68K_ASC_BASE ((caddr_t) 0x50f14000)
56 #define MAC68K_ASC_LEN 0x01000
57
58 /* bell support data */
59 static int asc_configured = 0;
60 static bus_space_tag_t asc_tag = MAC68K_BUS_SPACE_MEM;
61 static bus_space_handle_t asc_handle;
62
63 static int bell_freq = 1880;
64 static int bell_length = 10;
65 static int bell_volume = 100;
66 static int bell_ringing = 0;
67
68 static int ascmatch __P((struct device *, struct cfdata *, void *));
69 static void ascattach __P((struct device *, struct device *, void *));
70
71 struct cfattach asc_ca = {
72 sizeof(struct device), ascmatch, ascattach
73 };
74
75 struct cfdriver asc_cd = {
76 NULL, "asc", DV_DULL, NULL, 0
77 };
78
79 static int
80 ascmatch(parent, cf, aux)
81 struct device *parent;
82 struct cfdata *cf;
83 void *aux;
84 {
85 static int asc_matched = 0;
86 struct obio_attach_args *oa = aux;
87 bus_space_tag_t bst = MAC68K_BUS_SPACE_MEM;
88 bus_space_handle_t bsh;
89 bus_addr_t addr;
90 int rval = 0;
91
92 /* Allow only one instance. */
93 if (asc_matched)
94 return (0);
95 asc_matched = 1;
96
97 addr = (bus_addr_t) (oa->oa_addr ? oa->oa_addr : MAC68K_ASC_BASE);
98
99 if (bus_space_map(bst, addr, MAC68K_ASC_LEN, 0, &bsh))
100 return (0);
101
102 if (bus_probe(bst, bsh, 0, 1))
103 rval = 1;
104 else
105 rval = 0;
106
107 bus_space_unmap(bst, bsh, MAC68K_ASC_LEN);
108
109 return rval;
110 }
111
112 static void
113 ascattach(parent, self, aux)
114 struct device *parent, *self;
115 void *aux;
116 {
117 struct obio_attach_args *oa = aux;
118 bus_addr_t addr;
119
120 addr = (bus_addr_t) (oa->oa_addr ? oa->oa_addr : MAC68K_ASC_BASE);
121 if (bus_space_map(asc_tag, addr, MAC68K_ASC_LEN, 0,
122 &asc_handle)) {
123 printf("%s: can't map memory space\n", self->dv_xname);
124 return;
125 }
126
127 printf(" Apple sound chip\n");
128 asc_configured = 1;
129 }
130
131 int
132 asc_setbellparams(freq, length, volume)
133 int freq;
134 int length;
135 int volume;
136 {
137 if (!asc_configured)
138 return (ENODEV);
139
140 /*
141 * I only perform these checks for sanity. I suppose
142 * someone might want a bell that rings all day, but then
143 * they can make kernel mods themselves.
144 */
145
146 if (freq < 10 || freq > 40000)
147 return (EINVAL);
148 if (length < 0 || length > 3600)
149 return (EINVAL);
150 if (volume < 0 || volume > 100)
151 return (EINVAL);
152
153 bell_freq = freq;
154 bell_length = length;
155 bell_volume = volume;
156
157 return (0);
158 }
159
160
161 int
162 asc_getbellparams(freq, length, volume)
163 int *freq;
164 int *length;
165 int *volume;
166 {
167 if (!asc_configured)
168 return (ENODEV);
169
170 *freq = bell_freq;
171 *length = bell_length;
172 *volume = bell_volume;
173
174 return (0);
175 }
176
177
178 void
179 asc_bellstop(param)
180 int param;
181 {
182 if (!asc_configured)
183 return;
184
185 if (bell_ringing > 1000 || bell_ringing < 0)
186 panic("bell got out of sync?");
187
188 if (--bell_ringing == 0) /* disable ASC */
189 bus_space_write_1(asc_tag, asc_handle, 0x801, 0);
190 }
191
192
193 int
194 asc_ringbell()
195 {
196 int i;
197 unsigned long freq;
198
199 if (!asc_configured)
200 return (ENODEV);
201
202 if (bell_ringing == 0) {
203
204 for (i = 0; i < 0x800; i++)
205 bus_space_write_1(asc_tag, asc_handle, i, 0);
206
207 for (i = 0; i < 256; i++) {
208 bus_space_write_1(asc_tag, asc_handle, i, i / 4);
209 bus_space_write_1(asc_tag, asc_handle, i + 512, i / 4);
210 bus_space_write_1(asc_tag, asc_handle, i + 1024, i / 4);
211 bus_space_write_1(asc_tag, asc_handle, i + 1536, i / 4);
212 } /* up part of wave, four voices ? */
213 for (i = 0; i < 256; i++) {
214 bus_space_write_1(asc_tag, asc_handle, i + 256,
215 0x3f - (i / 4));
216 bus_space_write_1(asc_tag, asc_handle, i + 768,
217 0x3f - (i / 4));
218 bus_space_write_1(asc_tag, asc_handle, i + 1280,
219 0x3f - (i / 4));
220 bus_space_write_1(asc_tag, asc_handle, i + 1792,
221 0x3f - (i / 4));
222 } /* down part of wave, four voices ? */
223
224 /* Fix this. Need to find exact ASC sampling freq */
225 freq = 65536 * bell_freq / 466;
226
227 /* printf("beep: from %d, %02x %02x %02x %02x\n",
228 * cur_beep.freq, (freq >> 24) & 0xff, (freq >> 16) & 0xff,
229 * (freq >> 8) & 0xff, (freq) & 0xff); */
230 for (i = 0; i < 8; i++) {
231 bus_space_write_1(asc_tag, asc_handle, 0x814 + 8 * i,
232 (freq >> 24) & 0xff);
233 bus_space_write_1(asc_tag, asc_handle, 0x815 + 8 * i,
234 (freq >> 16) & 0xff);
235 bus_space_write_1(asc_tag, asc_handle, 0x816 + 8 * i,
236 (freq >> 8) & 0xff);
237 bus_space_write_1(asc_tag, asc_handle, 0x817 + 8 * i,
238 (freq) & 0xff);
239 } /* frequency; should put cur_beep.freq in here
240 * somewhere. */
241
242 bus_space_write_1(asc_tag, asc_handle, 0x807, 3); /* 44 ? */
243 bus_space_write_1(asc_tag, asc_handle, 0x806,
244 255 * bell_volume / 100);
245 bus_space_write_1(asc_tag, asc_handle, 0x805, 0);
246 bus_space_write_1(asc_tag, asc_handle, 0x80f, 0);
247 bus_space_write_1(asc_tag, asc_handle, 0x802, 2); /* sampled */
248 bus_space_write_1(asc_tag, asc_handle, 0x801, 2); /* enable sampled */
249 }
250 bell_ringing++;
251 timeout((void *) asc_bellstop, 0, bell_length);
252
253 return (0);
254 }
255