1 1.18 nat /* $NetBSD: ascaudio.c,v 1.18 2025/06/05 02:44:56 nat Exp $ */ 2 1.1 nat 3 1.1 nat /*- 4 1.17 nat * Copyright (c) 2017, 2023, 2025 Nathanial Sloss <nathanialsloss (at) yahoo.com.au> 5 1.1 nat * All rights reserved. 6 1.1 nat * 7 1.1 nat * Redistribution and use in source and binary forms, with or without 8 1.1 nat * modification, are permitted provided that the following conditions 9 1.1 nat * are met: 10 1.1 nat * 1. Redistributions of source code must retain the above copyright 11 1.1 nat * notice, this list of conditions and the following disclaimer. 12 1.1 nat * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 nat * notice, this list of conditions and the following disclaimer in the 14 1.1 nat * documentation and/or other materials provided with the distribution. 15 1.1 nat * 16 1.1 nat * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 nat * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 nat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 nat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 nat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 nat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 nat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 nat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 nat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 nat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 nat * POSSIBILITY OF SUCH DAMAGE. 27 1.1 nat */ 28 1.1 nat 29 1.1 nat /* Based on pad(4) and asc(4) */ 30 1.1 nat 31 1.1 nat #include <sys/cdefs.h> 32 1.18 nat __KERNEL_RCSID(0, "$NetBSD: ascaudio.c,v 1.18 2025/06/05 02:44:56 nat Exp $"); 33 1.1 nat 34 1.1 nat #include <sys/types.h> 35 1.1 nat #include <sys/param.h> 36 1.1 nat #include <sys/conf.h> 37 1.1 nat #include <sys/buf.h> 38 1.1 nat #include <sys/kauth.h> 39 1.1 nat #include <sys/kmem.h> 40 1.1 nat #include <sys/kernel.h> 41 1.1 nat #include <sys/device.h> 42 1.1 nat #include <sys/proc.h> 43 1.1 nat #include <sys/audioio.h> 44 1.1 nat #include <sys/module.h> 45 1.1 nat #include <sys/atomic.h> 46 1.1 nat 47 1.1 nat #include <uvm/uvm_extern.h> 48 1.1 nat 49 1.1 nat #include <dev/audio/audio_if.h> 50 1.1 nat #include <dev/audio/audiovar.h> 51 1.1 nat 52 1.1 nat #include <machine/autoconf.h> 53 1.1 nat #include <machine/cpu.h> 54 1.1 nat #include <machine/bus.h> 55 1.1 nat #include <machine/viareg.h> 56 1.1 nat 57 1.7 nat #include <mac68k/dev/pm_direct.h> 58 1.1 nat #include <mac68k/obio/ascaudiovar.h> 59 1.1 nat #include <mac68k/obio/ascreg.h> 60 1.1 nat #include <mac68k/obio/obiovar.h> 61 1.1 nat 62 1.1 nat #define MAC68K_ASCAUDIO_BASE 0x50f14000 63 1.1 nat #define MAC68K_IIFX_ASCAUDIO_BASE 0x50f10000 64 1.3 nat #define MAC68K_ASCAUDIO_LEN 0x2000 65 1.1 nat 66 1.1 nat #define BUFSIZE 32768 67 1.1 nat #define PLAYBLKSIZE 8192 68 1.15 nat #define RECBLKSIZE 1024 69 1.1 nat 70 1.3 nat #define ASC_VIA_CLR_INTR() via_reg(VIA2, vIFR) = V2IF_ASC 71 1.3 nat 72 1.1 nat static int ascaudiomatch(device_t, cfdata_t, void *); 73 1.1 nat static void ascaudioattach(device_t, device_t, void *); 74 1.1 nat 75 1.1 nat CFATTACH_DECL_NEW(ascaudio, sizeof(struct ascaudio_softc), 76 1.1 nat ascaudiomatch, ascaudioattach, NULL, NULL); 77 1.1 nat 78 1.1 nat extern struct cfdriver ascaudio_cd; 79 1.1 nat 80 1.1 nat dev_type_open(ascaudioopen); 81 1.1 nat dev_type_close(ascaudioclose); 82 1.1 nat dev_type_read(ascaudioread); 83 1.1 nat dev_type_write(ascaudiowrite); 84 1.1 nat dev_type_ioctl(ascaudioioctl); 85 1.1 nat 86 1.1 nat const struct cdevsw ascaudio_cdevsw = { 87 1.1 nat .d_open = ascaudioopen, 88 1.1 nat .d_close = ascaudioclose, 89 1.1 nat .d_read = ascaudioread, 90 1.1 nat .d_write = ascaudiowrite, 91 1.1 nat .d_ioctl = ascaudioioctl, 92 1.1 nat .d_stop = nostop, 93 1.1 nat .d_tty = notty, 94 1.1 nat .d_poll = nopoll, 95 1.1 nat .d_mmap = nommap, 96 1.1 nat .d_kqfilter = nokqfilter, 97 1.1 nat .d_discard = nodiscard, 98 1.1 nat .d_flag = 0 99 1.1 nat }; 100 1.1 nat 101 1.1 nat static int ascaudio_query_format(void *, struct audio_format_query *); 102 1.1 nat static int ascaudio_set_format(void *, int, 103 1.1 nat const audio_params_t *, const audio_params_t *, 104 1.1 nat audio_filter_reg_t *, audio_filter_reg_t *); 105 1.1 nat static int ascaudio_start_output(void *, void *, int, 106 1.1 nat void (*)(void *), void *); 107 1.1 nat static int ascaudio_start_input(void *, void *, int, 108 1.1 nat void (*)(void *), void *); 109 1.16 nat static int ascaudio_halt_input(void *); 110 1.16 nat static int ascaudio_halt_output(void *); 111 1.1 nat static int ascaudio_set_port(void *, mixer_ctrl_t *); 112 1.1 nat static int ascaudio_get_port(void *, mixer_ctrl_t *); 113 1.1 nat static int ascaudio_getdev(void *, struct audio_device *); 114 1.1 nat static int ascaudio_query_devinfo(void *, mixer_devinfo_t *); 115 1.1 nat static int ascaudio_get_props(void *); 116 1.1 nat static int 117 1.1 nat ascaudio_round_blocksize(void *, int, int, const audio_params_t *); 118 1.1 nat static void ascaudio_get_locks(void *, kmutex_t **, kmutex_t **); 119 1.1 nat static void ascaudio_intr(void *); 120 1.1 nat static int ascaudio_intr_est(void *); 121 1.1 nat static void ascaudio_intr_enable(void); 122 1.1 nat static void ascaudio_done_output(void *); 123 1.1 nat static void ascaudio_done_input(void *); 124 1.7 nat static void configure_dfac(uint8_t); 125 1.1 nat 126 1.1 nat static const struct audio_hw_if ascaudio_hw_if = { 127 1.1 nat .query_format = ascaudio_query_format, 128 1.1 nat .set_format = ascaudio_set_format, 129 1.1 nat .start_output = ascaudio_start_output, 130 1.1 nat .start_input = ascaudio_start_input, 131 1.16 nat .halt_output = ascaudio_halt_output, 132 1.16 nat .halt_input = ascaudio_halt_input, 133 1.1 nat .set_port = ascaudio_set_port, 134 1.1 nat .get_port = ascaudio_get_port, 135 1.1 nat .getdev = ascaudio_getdev, 136 1.1 nat .query_devinfo = ascaudio_query_devinfo, 137 1.1 nat .get_props = ascaudio_get_props, 138 1.1 nat .round_blocksize = ascaudio_round_blocksize, 139 1.1 nat .get_locks = ascaudio_get_locks, 140 1.1 nat }; 141 1.1 nat 142 1.1 nat enum { 143 1.1 nat ASC_OUTPUT_CLASS, 144 1.1 nat ASC_INPUT_CLASS, 145 1.1 nat ASC_OUTPUT_MASTER_VOLUME, 146 1.1 nat ASC_INPUT_DAC_VOLUME, 147 1.1 nat ASC_ENUM_LAST, 148 1.1 nat }; 149 1.1 nat 150 1.1 nat static int 151 1.1 nat ascaudiomatch(device_t parent, cfdata_t cf, void *aux) 152 1.1 nat { 153 1.1 nat struct obio_attach_args *oa = (struct obio_attach_args *)aux; 154 1.1 nat bus_addr_t addr; 155 1.1 nat bus_space_handle_t bsh; 156 1.1 nat int rval = 0; 157 1.1 nat 158 1.1 nat if (oa->oa_addr != (-1)) 159 1.1 nat addr = (bus_addr_t)oa->oa_addr; 160 1.1 nat else if (current_mac_model->machineid == MACH_MACTV) 161 1.1 nat return 0; 162 1.1 nat else if (current_mac_model->machineid == MACH_MACIIFX) 163 1.1 nat addr = (bus_addr_t)MAC68K_IIFX_ASCAUDIO_BASE; 164 1.1 nat else 165 1.1 nat addr = (bus_addr_t)MAC68K_ASCAUDIO_BASE; 166 1.1 nat 167 1.1 nat if (bus_space_map(oa->oa_tag, addr, MAC68K_ASCAUDIO_LEN, 0, &bsh)) 168 1.1 nat return (0); 169 1.1 nat 170 1.1 nat if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0, 1)) { 171 1.1 nat rval = 1; 172 1.1 nat } else 173 1.1 nat rval = 0; 174 1.1 nat 175 1.1 nat bus_space_unmap(oa->oa_tag, bsh, MAC68K_ASCAUDIO_LEN); 176 1.1 nat 177 1.1 nat return rval; 178 1.1 nat } 179 1.1 nat 180 1.1 nat static void 181 1.1 nat ascaudioattach(device_t parent, device_t self, void *aux) 182 1.1 nat { 183 1.1 nat struct ascaudio_softc *sc = device_private(self); 184 1.1 nat struct obio_attach_args *oa = (struct obio_attach_args *)aux; 185 1.1 nat bus_addr_t addr; 186 1.1 nat uint8_t tmp; 187 1.1 nat 188 1.1 nat sc->sc_dev = self; 189 1.1 nat sc->sc_tag = oa->oa_tag; 190 1.1 nat 191 1.1 nat if (oa->oa_addr != (-1)) 192 1.1 nat addr = (bus_addr_t)oa->oa_addr; 193 1.1 nat else if (current_mac_model->machineid == MACH_MACIIFX) 194 1.1 nat addr = (bus_addr_t)MAC68K_IIFX_ASCAUDIO_BASE; 195 1.1 nat else 196 1.1 nat addr = (bus_addr_t)MAC68K_ASCAUDIO_BASE; 197 1.1 nat if (bus_space_map(sc->sc_tag, addr, MAC68K_ASCAUDIO_LEN, 0, 198 1.1 nat &sc->sc_handle)) { 199 1.1 nat printf(": can't map memory space\n"); 200 1.1 nat return; 201 1.1 nat } 202 1.1 nat 203 1.4 riastrad /* Pull in the options flags. */ 204 1.1 nat sc->sc_options = ((device_cfdata(self)->cf_flags) & 205 1.1 nat ASCAUDIO_OPTIONS_MASK); 206 1.1 nat 207 1.1 nat sc->sc_playbuf = kmem_alloc(BUFSIZE, KM_SLEEP); 208 1.1 nat sc->sc_recbuf = kmem_alloc(BUFSIZE, KM_SLEEP); 209 1.1 nat sc->sc_rptr = sc->sc_recbuf; 210 1.1 nat sc->sc_getptr = sc->sc_recbuf; 211 1.1 nat sc->sc_wptr = sc->sc_playbuf; 212 1.1 nat sc->sc_putptr = sc->sc_playbuf; 213 1.1 nat 214 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 215 1.1 nat 216 1.1 nat sc->sc_ver = bus_space_read_1(oa->oa_tag, sc->sc_handle, 0x800); 217 1.1 nat 218 1.1 nat if (sc->sc_options & HIGHQUALITY) { 219 1.1 nat tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCRATE); 220 1.1 nat switch (tmp) { 221 1.1 nat case 2: 222 1.1 nat sc->sc_rate = 22050; 223 1.1 nat break; 224 1.1 nat case 3: 225 1.1 nat sc->sc_rate = 44100; 226 1.1 nat break; 227 1.1 nat default: 228 1.1 nat sc->sc_rate = 22254; 229 1.1 nat break; 230 1.1 nat } 231 1.1 nat 232 1.1 nat tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCTRL); 233 1.1 nat if (tmp & STEREO) 234 1.1 nat sc->sc_speakers = 2; 235 1.1 nat else 236 1.1 nat sc->sc_speakers = 1; 237 1.1 nat 238 1.1 nat } else { 239 1.1 nat __USE(tmp); 240 1.1 nat sc->sc_rate = 22254; 241 1.1 nat sc->sc_speakers = 1; 242 1.1 nat } 243 1.1 nat 244 1.1 nat if (sc->sc_options & LOWQUALITY) { 245 1.1 nat sc->sc_slowcpu = true; 246 1.1 nat if (sc->sc_slowcpu) 247 1.1 nat sc->sc_rate /= 2; 248 1.1 nat } 249 1.1 nat 250 1.3 nat if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) 251 1.3 nat printf(": Enhanced Apple Sound Chip"); 252 1.3 nat else 253 1.3 nat printf(": Apple Sound Chip"); 254 1.2 nat 255 1.1 nat if (oa->oa_addr != (-1)) 256 1.1 nat printf(" at %x", oa->oa_addr); 257 1.1 nat printf("\n"); 258 1.1 nat 259 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 260 1.1 nat 261 1.1 nat if (mac68k_machine.aux_interrupts) { 262 1.1 nat intr_establish(ascaudio_intr_est, sc, ASCIRQ); 263 1.1 nat } else { 264 1.1 nat via2_register_irq(VIA2_ASC, ascaudio_intr, sc); 265 1.1 nat } 266 1.1 nat ascaudio_intr_enable(); 267 1.1 nat 268 1.1 nat mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 269 1.3 nat mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); 270 1.1 nat callout_init(&sc->sc_pcallout, CALLOUT_MPSAFE); 271 1.1 nat callout_setfunc(&sc->sc_pcallout, ascaudio_done_output, sc); 272 1.1 nat callout_init(&sc->sc_rcallout, CALLOUT_MPSAFE); 273 1.1 nat callout_setfunc(&sc->sc_rcallout, ascaudio_done_input, sc); 274 1.1 nat 275 1.3 nat sc->sc_vol = 180; 276 1.6 nat sc->sc_recvol = 255; 277 1.1 nat 278 1.1 nat sc->sc_audiodev = audio_attach_mi(&ascaudio_hw_if, sc, sc->sc_dev); 279 1.1 nat 280 1.1 nat if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 281 1.1 nat aprint_error_dev(sc->sc_dev, 282 1.1 nat "couldn't establish power handler\n"); 283 1.1 nat 284 1.3 nat if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2) 285 1.1 nat return; 286 1.1 nat 287 1.1 nat if (sc->sc_options & HIGHQUALITY) 288 1.1 nat tmp = CDQUALITY; 289 1.1 nat else 290 1.1 nat tmp = MACDEFAULTS; 291 1.1 nat 292 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOCTRLA, tmp); 293 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOCTRLB, tmp); 294 1.4 riastrad 295 1.1 nat } 296 1.1 nat 297 1.1 nat int 298 1.1 nat ascaudioopen(dev_t dev, int flag, int mode, struct lwp *l) 299 1.1 nat { 300 1.1 nat struct ascaudio_softc *sc; 301 1.1 nat 302 1.1 nat sc = device_lookup_private(&ascaudio_cd, ASCAUDIOUNIT(dev)); 303 1.1 nat if (sc == NULL) 304 1.1 nat return (ENXIO); 305 1.1 nat if (sc->sc_open) 306 1.1 nat return (EBUSY); 307 1.1 nat sc->sc_open = 1; 308 1.1 nat 309 1.1 nat return (0); 310 1.1 nat } 311 1.1 nat 312 1.1 nat int 313 1.1 nat ascaudioclose(dev_t dev, int flag, int mode, struct lwp *l) 314 1.1 nat { 315 1.1 nat struct ascaudio_softc *sc; 316 1.1 nat 317 1.1 nat sc = device_lookup_private(&ascaudio_cd, ASCAUDIOUNIT(dev)); 318 1.1 nat sc->sc_open = 0; 319 1.1 nat 320 1.1 nat return (0); 321 1.1 nat } 322 1.1 nat 323 1.1 nat int 324 1.1 nat ascaudioread(dev_t dev, struct uio *uio, int ioflag) 325 1.1 nat { 326 1.1 nat return (ENXIO); 327 1.1 nat } 328 1.1 nat 329 1.1 nat int 330 1.1 nat ascaudiowrite(dev_t dev, struct uio *uio, int ioflag) 331 1.1 nat { 332 1.1 nat return (ENXIO); 333 1.1 nat } 334 1.1 nat 335 1.1 nat int 336 1.1 nat ascaudioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 337 1.1 nat { 338 1.1 nat int error; 339 1.1 nat #ifdef notyet 340 1.1 nat struct ascaudio_softc *sc; 341 1.1 nat int unit = ASCAUDIOUNIT(dev); 342 1.1 nat 343 1.1 nat sc = device_lookup_private(&ascaudio_cd, unit); 344 1.1 nat #endif 345 1.1 nat error = 0; 346 1.1 nat 347 1.1 nat switch (cmd) { 348 1.1 nat default: 349 1.1 nat error = EINVAL; 350 1.1 nat break; 351 1.1 nat } 352 1.1 nat return (error); 353 1.1 nat } 354 1.1 nat 355 1.11 nat #define ASCAUDIO_NFORMATS 3 356 1.1 nat static int 357 1.1 nat ascaudio_query_format(void *opaque, struct audio_format_query *ae) 358 1.1 nat { 359 1.1 nat struct ascaudio_softc *sc = opaque; 360 1.1 nat 361 1.1 nat const struct audio_format asc_formats[ASCAUDIO_NFORMATS] = { 362 1.1 nat { .mode = AUMODE_PLAY, 363 1.3 nat .encoding = AUDIO_ENCODING_SLINEAR_BE, 364 1.1 nat .validbits = 8, 365 1.1 nat .precision = 8, 366 1.1 nat .channels = sc->sc_speakers, 367 1.1 nat .channel_mask = sc->sc_speakers == 2 ? AUFMT_STEREO : 368 1.1 nat AUFMT_MONAURAL, 369 1.1 nat .frequency_type = 1, 370 1.1 nat .frequency = { sc->sc_rate }, }, 371 1.1 nat { .mode = AUMODE_RECORD, 372 1.3 nat .encoding = AUDIO_ENCODING_SLINEAR_BE, 373 1.1 nat .validbits = 8, 374 1.1 nat .precision = 8, 375 1.1 nat .channels = 1, 376 1.1 nat .channel_mask = AUFMT_MONAURAL, 377 1.1 nat .frequency_type = 1, 378 1.11 nat .frequency = { 11025 }, }, 379 1.11 nat { .mode = AUMODE_RECORD, 380 1.11 nat .encoding = AUDIO_ENCODING_SLINEAR_BE, 381 1.11 nat .validbits = 8, 382 1.11 nat .precision = 8, 383 1.11 nat .channels = 1, 384 1.11 nat .channel_mask = AUFMT_MONAURAL, 385 1.11 nat .frequency_type = 1, 386 1.11 nat .frequency = { 22050 }, } 387 1.1 nat }; 388 1.4 riastrad 389 1.1 nat return audio_query_format(asc_formats, ASCAUDIO_NFORMATS, ae); 390 1.1 nat } 391 1.1 nat 392 1.1 nat static int 393 1.1 nat ascaudio_set_format(void *opaque, int setmode, 394 1.1 nat const audio_params_t *play, const audio_params_t *rec, 395 1.1 nat audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 396 1.1 nat { 397 1.1 nat struct ascaudio_softc *sc = opaque; 398 1.1 nat 399 1.1 nat KASSERT(mutex_owned(&sc->sc_lock)); 400 1.1 nat 401 1.11 nat sc->sc_recfreq = rec->sample_rate; 402 1.11 nat 403 1.1 nat return 0; 404 1.1 nat } 405 1.1 nat 406 1.1 nat static int 407 1.1 nat ascaudio_start_output(void *opaque, void *block, int blksize, 408 1.1 nat void (*intr)(void *), void *intrarg) 409 1.1 nat { 410 1.1 nat struct ascaudio_softc *sc; 411 1.1 nat uint8_t *loc, tmp; 412 1.1 nat int total; 413 1.1 nat 414 1.1 nat sc = (struct ascaudio_softc *)opaque; 415 1.1 nat if (!sc) 416 1.1 nat return (ENODEV); 417 1.1 nat 418 1.1 nat sc->sc_pintr = intr; 419 1.1 nat sc->sc_pintrarg = intrarg; 420 1.1 nat 421 1.1 nat loc = block; 422 1.1 nat if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) != 423 1.1 nat MODEFIFO) { 424 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 425 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); 426 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 427 1.16 nat NONCOMP); 428 1.1 nat 429 1.1 nat } 430 1.1 nat 431 1.3 nat /* set the volume. */ 432 1.3 nat if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 433 1.3 nat /* DO NOT CHANGE THESE VALUES UNLESS TESTED. 434 1.3 nat CAN BE VERY LOUD!!!! */ 435 1.3 nat tmp = sc->sc_vol >> 5; 436 1.3 nat KASSERT(tmp <= MACOS_HIGH_VOL); 437 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp); 438 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp); 439 1.17 nat if (sc->sc_rintr == NULL) { 440 1.17 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, 441 1.17 nat A_LEFT_VOL, tmp); 442 1.17 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, 443 1.17 nat A_RIGHT_VOL, tmp); 444 1.17 nat } 445 1.3 nat } 446 1.3 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, sc->sc_vol); 447 1.1 nat 448 1.1 nat total = blksize; 449 1.3 nat if (sc->sc_putptr + blksize >= sc->sc_playbuf + BUFSIZE) 450 1.1 nat total = sc->sc_playbuf + BUFSIZE - sc->sc_putptr; 451 1.1 nat 452 1.3 nat if (total) { 453 1.3 nat memcpy(sc->sc_putptr, loc, total); 454 1.3 nat sc->sc_putptr += total; 455 1.3 nat loc += total; 456 1.3 nat } 457 1.1 nat 458 1.1 nat total = blksize - total; 459 1.1 nat if (total) { 460 1.1 nat sc->sc_putptr = sc->sc_playbuf; 461 1.1 nat memcpy(sc->sc_playbuf, loc, total); 462 1.1 nat sc->sc_putptr += total; 463 1.1 nat } 464 1.1 nat 465 1.1 nat sc->sc_avail += blksize; 466 1.1 nat if (sc->sc_avail > BUFSIZE) 467 1.1 nat sc->sc_avail = BUFSIZE; 468 1.1 nat 469 1.1 nat /* start fifo playback */ 470 1.16 nat if ((sc->sc_rintr == NULL) && bus_space_read_1(sc->sc_tag, 471 1.16 nat sc->sc_handle, ASCMODE) != MODEFIFO) 472 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); 473 1.16 nat 474 1.16 nat if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 475 1.16 nat /* enable interrupts channel b */ 476 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); 477 1.16 nat } 478 1.1 nat 479 1.1 nat return 0; 480 1.1 nat } 481 1.1 nat 482 1.1 nat static int 483 1.1 nat ascaudio_start_input(void *opaque, void *block, int blksize, 484 1.1 nat void (*intr)(void *), void *intrarg) 485 1.1 nat { 486 1.1 nat struct ascaudio_softc *sc; 487 1.1 nat uint8_t tmp; 488 1.1 nat int total; 489 1.1 nat 490 1.1 nat sc = (struct ascaudio_softc *)opaque; 491 1.1 nat if (!sc) 492 1.1 nat return (ENODEV); 493 1.1 nat 494 1.1 nat uint8_t *loc; 495 1.1 nat loc = block; 496 1.1 nat 497 1.1 nat sc->sc_rintr = intr; 498 1.1 nat sc->sc_rintrarg = intrarg; 499 1.1 nat 500 1.1 nat if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) != 501 1.1 nat MODEFIFO) { 502 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 503 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); 504 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 505 1.16 nat NONCOMP); 506 1.16 nat memset(loc, 0x80, blksize); 507 1.16 nat } 508 1.3 nat 509 1.16 nat if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 510 1.16 nat /* 511 1.16 nat * Set up dfac for microphone. 512 1.16 nat * DO NOT SET BITS 5-7 due to loud feedback squeal. 513 1.16 nat */ 514 1.16 nat configure_dfac(DFAC_GAIN_HIGH); 515 1.16 nat } 516 1.3 nat 517 1.16 nat tmp = RECORDA; 518 1.16 nat if (sc->sc_recfreq == 22050) 519 1.16 nat tmp |= REC22KHZ; 520 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); 521 1.3 nat 522 1.16 nat if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 523 1.16 nat /* enable interrupts channel a */ 524 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); 525 1.16 nat } 526 1.1 nat 527 1.16 nat /* start fifo playback */ 528 1.16 nat if ((sc->sc_pintr == NULL) && bus_space_read_1(sc->sc_tag, 529 1.16 nat sc->sc_handle, ASCMODE) != MODEFIFO) { 530 1.13 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); 531 1.13 nat 532 1.1 nat return 0; 533 1.1 nat } 534 1.1 nat 535 1.3 nat /* set the volume. */ 536 1.3 nat if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 537 1.3 nat /* DO NOT CHANGE THESE VALUES UNLESS TESTED. 538 1.3 nat CAN BE VERY LOUD!!!! */ 539 1.6 nat tmp = sc->sc_recvol >> 5; 540 1.3 nat KASSERT(tmp <= MACOS_HIGH_VOL); 541 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp); 542 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp); 543 1.17 nat if (sc->sc_pintr == NULL) { 544 1.17 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, 545 1.17 nat B_LEFT_VOL, tmp); 546 1.17 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, 547 1.17 nat B_RIGHT_VOL, tmp); 548 1.17 nat } 549 1.17 nat } 550 1.17 nat if (sc->sc_pintr == NULL) { 551 1.17 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, 552 1.17 nat sc->sc_recvol); 553 1.3 nat } 554 1.1 nat 555 1.1 nat total = blksize; 556 1.3 nat if (sc->sc_getptr + blksize >= sc->sc_recbuf + BUFSIZE) 557 1.1 nat total = sc->sc_recbuf + BUFSIZE - sc->sc_getptr; 558 1.1 nat 559 1.3 nat if (total) { 560 1.3 nat memcpy(loc, sc->sc_getptr, total); 561 1.3 nat sc->sc_getptr += total; 562 1.3 nat loc += total; 563 1.3 nat } 564 1.1 nat 565 1.1 nat total = blksize - total; 566 1.1 nat if (total) { 567 1.3 nat sc->sc_getptr = sc->sc_recbuf; 568 1.1 nat memcpy(loc, sc->sc_getptr, total); 569 1.1 nat sc->sc_getptr += total; 570 1.1 nat } 571 1.1 nat 572 1.1 nat sc->sc_recavail -= blksize; 573 1.1 nat 574 1.1 nat return 0; 575 1.1 nat } 576 1.1 nat 577 1.1 nat static int 578 1.16 nat ascaudio_halt_input(void *opaque) 579 1.1 nat { 580 1.1 nat ascaudio_softc_t *sc; 581 1.1 nat 582 1.1 nat sc = (ascaudio_softc_t *)opaque; 583 1.1 nat 584 1.1 nat KASSERT(mutex_owned(&sc->sc_lock)); 585 1.1 nat 586 1.3 nat callout_halt(&sc->sc_rcallout, &sc->sc_intr_lock); 587 1.3 nat 588 1.1 nat sc->sc_rintr = NULL; 589 1.1 nat sc->sc_rintrarg = NULL; 590 1.16 nat sc->sc_recavail = 0; 591 1.1 nat 592 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, 0); 593 1.1 nat 594 1.16 nat if (sc->sc_pintr == NULL) { 595 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 596 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 597 1.16 nat CLEARFIFO); 598 1.16 nat } 599 1.1 nat 600 1.1 nat sc->sc_rptr = sc->sc_recbuf; 601 1.1 nat sc->sc_getptr = sc->sc_recbuf; 602 1.1 nat 603 1.3 nat if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2) 604 1.1 nat return 0; 605 1.1 nat 606 1.7 nat configure_dfac(DFAC_DISABLE); 607 1.7 nat 608 1.1 nat /* disable half interrupts channel a */ 609 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEHALFIRQ); 610 1.16 nat 611 1.16 nat return 0; 612 1.16 nat } 613 1.16 nat 614 1.16 nat static int 615 1.16 nat ascaudio_halt_output(void *opaque) 616 1.16 nat { 617 1.16 nat ascaudio_softc_t *sc; 618 1.16 nat 619 1.16 nat sc = (ascaudio_softc_t *)opaque; 620 1.16 nat 621 1.16 nat KASSERT(mutex_owned(&sc->sc_lock)); 622 1.16 nat 623 1.16 nat callout_halt(&sc->sc_pcallout, &sc->sc_intr_lock); 624 1.16 nat 625 1.16 nat sc->sc_pintr = NULL; 626 1.16 nat sc->sc_pintrarg = NULL; 627 1.16 nat sc->sc_avail = 0; 628 1.16 nat 629 1.16 nat if (sc->sc_rintr == NULL) { 630 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 631 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 632 1.16 nat CLEARFIFO); 633 1.16 nat } 634 1.16 nat 635 1.16 nat sc->sc_wptr = sc->sc_playbuf; 636 1.16 nat sc->sc_putptr = sc->sc_playbuf; 637 1.16 nat 638 1.16 nat if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2) 639 1.16 nat return 0; 640 1.16 nat 641 1.1 nat /* disable half interrupts channel b */ 642 1.1 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, DISABLEHALFIRQ); 643 1.1 nat 644 1.1 nat return 0; 645 1.1 nat } 646 1.1 nat 647 1.1 nat static int 648 1.1 nat ascaudio_getdev(void *opaque, struct audio_device *ret) 649 1.1 nat { 650 1.1 nat strlcpy(ret->name, "Apple ASC Audio", sizeof(ret->name)); 651 1.1 nat strlcpy(ret->version, osrelease, sizeof(ret->version)); 652 1.1 nat strlcpy(ret->config, "ascaudio", sizeof(ret->config)); 653 1.1 nat 654 1.1 nat return 0; 655 1.1 nat } 656 1.1 nat 657 1.1 nat static int 658 1.1 nat ascaudio_set_port(void *opaque, mixer_ctrl_t *mc) 659 1.1 nat { 660 1.1 nat struct ascaudio_softc *sc = opaque; 661 1.1 nat 662 1.1 nat KASSERT(mutex_owned(&sc->sc_lock)); 663 1.1 nat 664 1.1 nat switch (mc->dev) { 665 1.1 nat case ASC_OUTPUT_MASTER_VOLUME: 666 1.6 nat if (mc->un.value.num_channels != 1) 667 1.6 nat return EINVAL; 668 1.6 nat sc->sc_vol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 669 1.6 nat return 0; 670 1.1 nat case ASC_INPUT_DAC_VOLUME: 671 1.1 nat if (mc->un.value.num_channels != 1) 672 1.1 nat return EINVAL; 673 1.6 nat sc->sc_recvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 674 1.1 nat return 0; 675 1.1 nat } 676 1.1 nat 677 1.1 nat return ENXIO; 678 1.1 nat } 679 1.1 nat 680 1.1 nat static int 681 1.1 nat ascaudio_get_port(void *opaque, mixer_ctrl_t *mc) 682 1.1 nat { 683 1.1 nat struct ascaudio_softc *sc = opaque; 684 1.1 nat 685 1.1 nat KASSERT(mutex_owned(&sc->sc_lock)); 686 1.1 nat 687 1.1 nat switch (mc->dev) { 688 1.1 nat case ASC_OUTPUT_MASTER_VOLUME: 689 1.6 nat if (mc->un.value.num_channels != 1) 690 1.6 nat return EINVAL; 691 1.6 nat mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vol; 692 1.6 nat return 0; 693 1.1 nat case ASC_INPUT_DAC_VOLUME: 694 1.1 nat if (mc->un.value.num_channels != 1) 695 1.1 nat return EINVAL; 696 1.6 nat mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_recvol; 697 1.1 nat return 0; 698 1.1 nat } 699 1.1 nat 700 1.1 nat return ENXIO; 701 1.1 nat } 702 1.1 nat 703 1.1 nat static int 704 1.1 nat ascaudio_query_devinfo(void *opaque, mixer_devinfo_t *di) 705 1.1 nat { 706 1.1 nat ascaudio_softc_t *sc __diagused; 707 1.1 nat 708 1.1 nat sc = (ascaudio_softc_t *)opaque; 709 1.1 nat 710 1.1 nat KASSERT(mutex_owned(&sc->sc_lock)); 711 1.1 nat 712 1.1 nat switch (di->index) { 713 1.1 nat case ASC_OUTPUT_CLASS: 714 1.1 nat di->mixer_class = ASC_OUTPUT_CLASS; 715 1.1 nat strcpy(di->label.name, AudioCoutputs); 716 1.1 nat di->type = AUDIO_MIXER_CLASS; 717 1.1 nat di->next = di->prev = AUDIO_MIXER_LAST; 718 1.1 nat return 0; 719 1.1 nat case ASC_INPUT_CLASS: 720 1.1 nat di->mixer_class = ASC_INPUT_CLASS; 721 1.1 nat strcpy(di->label.name, AudioCinputs); 722 1.1 nat di->type = AUDIO_MIXER_CLASS; 723 1.1 nat di->next = di->prev = AUDIO_MIXER_LAST; 724 1.1 nat return 0; 725 1.1 nat case ASC_OUTPUT_MASTER_VOLUME: 726 1.1 nat di->mixer_class = ASC_OUTPUT_CLASS; 727 1.1 nat strcpy(di->label.name, AudioNmaster); 728 1.1 nat di->type = AUDIO_MIXER_VALUE; 729 1.1 nat di->next = di->prev = AUDIO_MIXER_LAST; 730 1.1 nat di->un.v.num_channels = 1; 731 1.1 nat strcpy(di->un.v.units.name, AudioNvolume); 732 1.1 nat return 0; 733 1.1 nat case ASC_INPUT_DAC_VOLUME: 734 1.1 nat di->mixer_class = ASC_INPUT_CLASS; 735 1.1 nat strcpy(di->label.name, AudioNdac); 736 1.1 nat di->type = AUDIO_MIXER_VALUE; 737 1.1 nat di->next = di->prev = AUDIO_MIXER_LAST; 738 1.1 nat di->un.v.num_channels = 1; 739 1.1 nat strcpy(di->un.v.units.name, AudioNvolume); 740 1.1 nat return 0; 741 1.1 nat } 742 1.1 nat 743 1.1 nat return ENXIO; 744 1.1 nat } 745 1.1 nat 746 1.1 nat static int 747 1.1 nat ascaudio_get_props(void *opaque) 748 1.1 nat { 749 1.1 nat 750 1.1 nat return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 751 1.16 nat AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 752 1.1 nat } 753 1.1 nat 754 1.1 nat static int 755 1.1 nat ascaudio_round_blocksize(void *opaque, int blksize, int mode, 756 1.1 nat const audio_params_t *p) 757 1.1 nat { 758 1.1 nat ascaudio_softc_t *sc __diagused; 759 1.1 nat 760 1.1 nat sc = (ascaudio_softc_t *)opaque; 761 1.1 nat KASSERT(mutex_owned(&sc->sc_lock)); 762 1.1 nat 763 1.1 nat if (mode == AUMODE_PLAY) 764 1.1 nat return PLAYBLKSIZE; 765 1.1 nat else 766 1.1 nat return RECBLKSIZE; 767 1.1 nat } 768 1.1 nat 769 1.1 nat static void 770 1.1 nat ascaudio_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread) 771 1.1 nat { 772 1.1 nat ascaudio_softc_t *sc; 773 1.1 nat 774 1.1 nat sc = (ascaudio_softc_t *)opaque; 775 1.1 nat 776 1.1 nat *intr = &sc->sc_intr_lock; 777 1.1 nat *thread = &sc->sc_lock; 778 1.1 nat } 779 1.1 nat 780 1.1 nat static int 781 1.1 nat ascaudio_intr_est(void *arg) 782 1.1 nat { 783 1.1 nat ascaudio_intr(arg); 784 1.1 nat 785 1.1 nat return 0; 786 1.1 nat } 787 1.1 nat 788 1.1 nat static void 789 1.1 nat ascaudio_intr(void *arg) 790 1.1 nat { 791 1.1 nat struct ascaudio_softc *sc = arg; 792 1.16 nat uint8_t status; 793 1.10 nat int8_t val; 794 1.3 nat int loc_a, loc_b, total, count, i; 795 1.1 nat 796 1.1 nat if (!sc) 797 1.1 nat return; 798 1.1 nat 799 1.1 nat if (!sc->sc_pintr && !sc->sc_rintr) 800 1.1 nat return; 801 1.1 nat 802 1.1 nat mutex_enter(&sc->sc_intr_lock); 803 1.3 nat 804 1.16 nat status = bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFOSTATUS); 805 1.16 nat 806 1.16 nat if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 807 1.18 nat if (sc->sc_pintr) { 808 1.18 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, 809 1.18 nat IRQB, DISABLEHALFIRQ); 810 1.18 nat } 811 1.16 nat if (sc->sc_rintr) { 812 1.3 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, 813 1.3 nat IRQA, DISABLEHALFIRQ); 814 1.16 nat } 815 1.16 nat } 816 1.3 nat 817 1.18 nat if (sc->sc_ver == EASC_VER2 && (status & A_HALF)) 818 1.18 nat count = 0x200; 819 1.18 nat else if (sc->sc_ver != EASC_VER2 && !(status & A_HALF)) 820 1.16 nat count = 0x200; 821 1.16 nat else 822 1.16 nat count = 0; 823 1.16 nat 824 1.16 nat if (count && sc->sc_rintr) { 825 1.3 nat total = count; 826 1.3 nat if (sc->sc_rptr + count >= sc->sc_recbuf + BUFSIZE) 827 1.3 nat count = sc->sc_recbuf + BUFSIZE - sc->sc_rptr; 828 1.3 nat while (total) { 829 1.3 nat if (sc->sc_ver == EASC_VER2) { 830 1.3 nat loc_a = FIFO_A_ALT; 831 1.3 nat loc_b = FIFO_B_ALT; 832 1.3 nat } else { 833 1.3 nat loc_a = FIFO_A; 834 1.3 nat loc_b = 0; 835 1.3 nat } 836 1.3 nat for (i = 0; i < count; i++) { 837 1.3 nat val = bus_space_read_1(sc->sc_tag, 838 1.3 nat sc->sc_handle, loc_a); 839 1.3 nat val ^= 0x80; 840 1.10 nat val = val * sc->sc_recvol / 64; 841 1.3 nat *sc->sc_rptr++ = val; 842 1.18 nat if (loc_b) { 843 1.3 nat (void)bus_space_read_1 844 1.3 nat (sc->sc_tag, sc->sc_handle, loc_b); 845 1.1 nat } 846 1.1 nat } 847 1.3 nat if (sc->sc_rptr >= sc->sc_recbuf + BUFSIZE) 848 1.3 nat sc->sc_rptr = sc->sc_recbuf; 849 1.3 nat total -= count; 850 1.3 nat sc->sc_recavail += count; 851 1.3 nat count = total; 852 1.3 nat } 853 1.1 nat 854 1.3 nat if (sc->sc_recavail > BUFSIZE) 855 1.3 nat sc->sc_recavail = BUFSIZE; 856 1.16 nat } 857 1.16 nat 858 1.16 nat if (sc->sc_pintr == NULL) 859 1.16 nat goto more; 860 1.3 nat 861 1.16 nat if (status & B_HALF) 862 1.16 nat count = 0x200; 863 1.16 nat else 864 1.16 nat count = 0; 865 1.1 nat 866 1.3 nat if (sc->sc_slowcpu) 867 1.3 nat count /= 2; 868 1.3 nat 869 1.16 nat if (count && sc->sc_avail < count) { 870 1.3 nat if (sc->sc_avail) { 871 1.3 nat count = sc->sc_avail; 872 1.3 nat goto fill_fifo; 873 1.3 nat } 874 1.3 nat if (sc->sc_pintr) { 875 1.3 nat for (i = 0; i < 0x200; i++) { 876 1.18 nat if (sc->sc_rintr == NULL || 877 1.18 nat sc->sc_ver == EASC_VER2) { 878 1.16 nat bus_space_write_1(sc->sc_tag, 879 1.16 nat sc->sc_handle, FIFO_A, 0x80); 880 1.16 nat } 881 1.3 nat bus_space_write_1(sc->sc_tag, 882 1.3 nat sc->sc_handle, FIFO_B, 0x80); 883 1.3 nat } 884 1.3 nat } else { 885 1.3 nat if (sc->sc_slowcpu) 886 1.3 nat count *= 2; 887 1.3 nat for (i = 0; i < count; i++) { 888 1.3 nat bus_space_write_1(sc->sc_tag, 889 1.3 nat sc->sc_handle, FIFO_B, 0x80); 890 1.3 nat } 891 1.3 nat } 892 1.3 nat goto more; 893 1.3 nat } 894 1.1 nat 895 1.3 nat fill_fifo: 896 1.3 nat total = count; 897 1.3 nat if (sc->sc_wptr + count >= sc->sc_playbuf + BUFSIZE) 898 1.3 nat count = sc->sc_playbuf + BUFSIZE - sc->sc_wptr; 899 1.3 nat 900 1.3 nat while (total) { 901 1.3 nat if (sc->sc_slowcpu) { 902 1.3 nat for (i = 0; i < count; i++) { 903 1.3 nat val = *sc->sc_wptr++; 904 1.3 nat val ^= 0x80; 905 1.18 nat if (sc->sc_rintr == NULL || 906 1.18 nat sc->sc_ver == EASC_VER2) { 907 1.16 nat bus_space_write_1(sc->sc_tag, 908 1.16 nat sc->sc_handle, FIFO_A, val); 909 1.16 nat bus_space_write_1(sc->sc_tag, 910 1.16 nat sc->sc_handle, FIFO_A, val); 911 1.16 nat } 912 1.3 nat bus_space_write_1(sc->sc_tag, 913 1.3 nat sc->sc_handle, FIFO_B, val); 914 1.3 nat bus_space_write_1(sc->sc_tag, 915 1.3 nat sc->sc_handle, FIFO_B, val); 916 1.3 nat } 917 1.3 nat } else { 918 1.3 nat for (i = 0; i < count; i++) { 919 1.3 nat val = *sc->sc_wptr++; 920 1.3 nat val ^= 0x80; 921 1.18 nat if (sc->sc_rintr == NULL || 922 1.18 nat sc->sc_ver == EASC_VER2) { 923 1.16 nat bus_space_write_1(sc->sc_tag, 924 1.16 nat sc->sc_handle, FIFO_A, val); 925 1.16 nat } 926 1.3 nat bus_space_write_1(sc->sc_tag, 927 1.3 nat sc->sc_handle, FIFO_B, val); 928 1.1 nat } 929 1.1 nat } 930 1.3 nat if (sc->sc_wptr >= sc->sc_playbuf + BUFSIZE) 931 1.3 nat sc->sc_wptr = sc->sc_playbuf; 932 1.3 nat total -= count; 933 1.3 nat sc->sc_avail -= count; 934 1.3 nat count = total; 935 1.3 nat } 936 1.3 nat 937 1.3 nat more: 938 1.16 nat if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 939 1.16 nat if (sc->sc_rintr) 940 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); 941 1.16 nat if (sc->sc_pintr) 942 1.16 nat bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); 943 1.16 nat } 944 1.16 nat 945 1.3 nat if (sc->sc_pintr && (sc->sc_avail <= PLAYBLKSIZE)) 946 1.3 nat callout_schedule(&sc->sc_pcallout, 0); 947 1.1 nat 948 1.3 nat if (sc->sc_rintr && (sc->sc_recavail >= RECBLKSIZE)) 949 1.3 nat callout_schedule(&sc->sc_rcallout, 0); 950 1.1 nat 951 1.1 nat mutex_exit(&sc->sc_intr_lock); 952 1.1 nat } 953 1.4 riastrad 954 1.1 nat static void 955 1.1 nat ascaudio_intr_enable(void) 956 1.1 nat { 957 1.1 nat int s; 958 1.1 nat 959 1.1 nat s = splhigh(); 960 1.1 nat if (VIA2 == VIA2OFF) 961 1.1 nat via2_reg(vIER) = 0x80 | V2IF_ASC; 962 1.1 nat else 963 1.1 nat via2_reg(rIER) = 0x80 | V2IF_ASC; 964 1.1 nat splx(s); 965 1.1 nat } 966 1.1 nat 967 1.1 nat static void 968 1.1 nat ascaudio_done_output(void *arg) 969 1.1 nat { 970 1.1 nat struct ascaudio_softc *sc = arg; 971 1.1 nat 972 1.1 nat mutex_enter(&sc->sc_intr_lock); 973 1.1 nat if (sc->sc_pintr) 974 1.1 nat (*sc->sc_pintr)(sc->sc_pintrarg); 975 1.1 nat mutex_exit(&sc->sc_intr_lock); 976 1.1 nat } 977 1.1 nat 978 1.1 nat static void 979 1.1 nat ascaudio_done_input(void *arg) 980 1.1 nat { 981 1.1 nat struct ascaudio_softc *sc = arg; 982 1.1 nat 983 1.1 nat mutex_enter(&sc->sc_intr_lock); 984 1.1 nat if (sc->sc_rintr) 985 1.1 nat (*sc->sc_rintr)(sc->sc_rintrarg); 986 1.1 nat mutex_exit(&sc->sc_intr_lock); 987 1.1 nat } 988 1.14 nat 989 1.7 nat static void 990 1.7 nat configure_dfac(uint8_t config) 991 1.7 nat { 992 1.7 nat int i; 993 1.7 nat 994 1.7 nat if (pmHardware == PM_HW_PB5XX) 995 1.7 nat return; /* These macs use the pm to configure dfac */ 996 1.7 nat 997 1.7 nat for (i = 0; i < 8; i++) { 998 1.7 nat via_reg(VIA2, vBufB) &= ~DFAC_CLOCK; 999 1.7 nat 1000 1.7 nat if (config & 0x1) 1001 1.7 nat via_reg(VIA2, vBufB) |= DFAC_DATA; 1002 1.7 nat else 1003 1.7 nat via_reg(VIA2, vBufB) &= ~DFAC_DATA; 1004 1.7 nat 1005 1.7 nat via_reg(VIA2, vBufB) |= DFAC_CLOCK; 1006 1.7 nat config >>= 1; 1007 1.7 nat } 1008 1.7 nat via_reg(VIA2, vBufB) &= ~DFAC_CLOCK; 1009 1.7 nat via_reg(VIA2, vBufB) |= DFAC_LATCH; 1010 1.7 nat via_reg(VIA2, vBufB) &= ~DFAC_LATCH; 1011 1.7 nat } 1012 1.1 nat 1013 1.1 nat #ifdef _MODULE 1014 1.1 nat 1015 1.1 nat MODULE(MODULE_CLASS_DRIVER, ascaudio, "audio"); 1016 1.1 nat 1017 1.1 nat static const struct cfiattrdata audiobuscf_iattrdata = { 1018 1.1 nat "audiobus", 0, { { NULL, NULL, 0 }, } 1019 1.1 nat }; 1020 1.1 nat static const struct cfiattrdata * const ascaudio_attrs[] = { 1021 1.1 nat &audiobuscf_iattrdata, NULL 1022 1.1 nat }; 1023 1.1 nat 1024 1.1 nat CFDRIVER_DECL(ascaudio, DV_DULL, ascaud_attrs); 1025 1.1 nat extern struct cfattach ascaudio_ca; 1026 1.1 nat static int ascaudioloc[] = { -1, -1 }; 1027 1.1 nat 1028 1.1 nat static struct cfdata ascaudio_cfdata[] = { 1029 1.1 nat { 1030 1.1 nat .cf_name = "ascaudio", 1031 1.1 nat .cf_atname = "ascaudio", 1032 1.1 nat .cf_unit = 0, 1033 1.1 nat .cf_fstate = FSTATE_STAR, 1034 1.1 nat .cf_loc = ascaudioloc, 1035 1.1 nat .cf_flags = 0, 1036 1.1 nat .cf_pspec = NULL, 1037 1.1 nat }, 1038 1.1 nat { NULL, NULL, 0, 0, NULL, 0, NULL } 1039 1.1 nat }; 1040 1.1 nat 1041 1.1 nat static int 1042 1.1 nat ascaudio_modcmd(modcmd_t cmd, void *arg) 1043 1.1 nat { 1044 1.1 nat devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; 1045 1.1 nat int error; 1046 1.1 nat 1047 1.1 nat switch (cmd) { 1048 1.1 nat case MODULE_CMD_INIT: 1049 1.1 nat error = config_cfdriver_attach(&ascaudio_cd); 1050 1.1 nat if (error) { 1051 1.1 nat return error; 1052 1.1 nat } 1053 1.1 nat 1054 1.1 nat error = config_cfattach_attach(ascaudio_cd.cd_name, &ascaud_ca); 1055 1.1 nat if (error) { 1056 1.1 nat config_cfdriver_detach(&ascaudio_cd); 1057 1.1 nat aprint_error("%s: unable to register cfattach\n", 1058 1.1 nat ascaudio_cd.cd_name); 1059 1.1 nat 1060 1.1 nat return error; 1061 1.1 nat } 1062 1.1 nat 1063 1.1 nat error = config_cfdata_attach(ascaudio_cfdata, 1); 1064 1.1 nat if (error) { 1065 1.1 nat config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 1066 1.1 nat config_cfdriver_detach(&ascaudio_cd); 1067 1.1 nat aprint_error("%s: unable to register cfdata\n", 1068 1.1 nat ascaudio_cd.cd_name); 1069 1.1 nat 1070 1.1 nat return error; 1071 1.1 nat } 1072 1.1 nat 1073 1.1 nat error = devsw_attach(ascaudio_cd.cd_name, NULL, &bmajor, 1074 1.1 nat &ascaudio_cdevsw, &cmajor); 1075 1.1 nat if (error) { 1076 1.1 nat error = config_cfdata_detach(ascaudio_cfdata); 1077 1.1 nat if (error) { 1078 1.1 nat return error; 1079 1.1 nat } 1080 1.1 nat config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 1081 1.1 nat config_cfdriver_detach(&ascaudio_cd); 1082 1.1 nat aprint_error("%s: unable to register devsw\n", 1083 1.1 nat ascaudio_cd.cd_name); 1084 1.1 nat 1085 1.1 nat return error; 1086 1.1 nat } 1087 1.1 nat 1088 1.1 nat (void)config_attach_pseudo(ascaudio_cfdata); 1089 1.1 nat 1090 1.1 nat return 0; 1091 1.1 nat case MODULE_CMD_FINI: 1092 1.1 nat error = config_cfdata_detach(ascaudio_cfdata); 1093 1.1 nat if (error) { 1094 1.1 nat return error; 1095 1.1 nat } 1096 1.1 nat 1097 1.1 nat config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 1098 1.1 nat config_cfdriver_detach(&ascaudio_cd); 1099 1.1 nat devsw_detach(NULL, &ascaudio_cdevsw); 1100 1.1 nat 1101 1.1 nat return 0; 1102 1.1 nat default: 1103 1.1 nat return ENOTTY; 1104 1.1 nat } 1105 1.1 nat } 1106 1.1 nat 1107 1.1 nat #endif 1108