mpc5200_ac97.c revision 1.1 1 /* $NetBSD: mpc5200_ac97.c,v 1.1 2026/06/27 13:28:35 rkujawa Exp $ */
2
3 /*-
4 * Copyright (c) 2026 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Radoslaw Kujawa.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Driver for the Freescale MPC5200B on-chip AC97 controller (a PSC in AC97
34 * mode), written with the assumption that it's connected to a codec that
35 * can be driver through the ac97(4) interface.
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: mpc5200_ac97.c,v 1.1 2026/06/27 13:28:35 rkujawa Exp $");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 #include <sys/bus.h>
45 #include <sys/mutex.h>
46 #include <sys/audioio.h>
47
48 #include <dev/audio/audio_if.h>
49
50 #include <dev/ic/ac97var.h>
51
52 #include <dev/ofw/openfirm.h>
53
54 #include <machine/intr.h>
55
56 #include <powerpc/mpc5200/obiovar.h>
57 #include <powerpc/mpc5200/mpc5200reg.h>
58 #include <powerpc/mpc5200/pscreg.h>
59 #include <powerpc/mpc5200/mpc5200_ac97reg.h>
60 #include <powerpc/mpc5200/mpc5200_ac97var.h>
61 #include <powerpc/mpc5200/bestcommvar.h>
62
63 /*
64 * BestComm wiring for the PSC2 transmit path.
65 */
66 #define MPCAC97_TX_TASK 12
67 #define MPCAC97_TX_INITIATOR 12
68 #define MPCAC97_TX_PRIO 5 /* SDMA initiator priority (0-7) */
69 #define AC97_FIFO_TX PSC_TB /* DMA target: Tx Buffer (0x0c) */
70
71 #define MPCAC97_RATE 48000 /* AC97 fixed sample rate */
72 #define MPCAC97_FRAME_SIZE 8 /* 2 ch * 32-bit slot word */
73 #define MPCAC97_MAX_NBLK 256 /* SDMA descriptor-ring sanity cap */
74
75 /*
76 * Tx FIFO "almost empty" threshold
77 */
78 #define MPCAC97_TFALARM 0x100
79 #define MPCAC97_TFGRAN 0x04
80
81 /* Codec register-access poll limits. */
82 #define AC97_CMD_TIMEOUT 1000 /* x10us = 10ms for a command frame */
83 #define AC97_READY_TIMEOUT 1000 /* x1ms = 1s for codec power-up */
84
85 #define AC97_REG_POWERDOWN 0x26 /* powerdown ctrl/status (AC97_REG_POWER) */
86 #define AC97_POWER_READY 0x000f /* ADC+DAC+ANL+REF ready bits */
87
88 static int mpcac97_match(device_t, cfdata_t, void *);
89 static void mpcac97_attach(device_t, device_t, void *);
90
91 static void mpcac97_init_psc(struct mpcac97_softc *);
92 static int mpcac97_intr(void *);
93
94 /* ac97(4) host interface. */
95 static int mpcac97_ac97_attach(void *, struct ac97_codec_if *);
96 static int mpcac97_ac97_read(void *, uint8_t, uint16_t *);
97 static int mpcac97_ac97_write(void *, uint8_t, uint16_t);
98 static int mpcac97_ac97_reset(void *);
99 static enum ac97_host_flags mpcac97_ac97_flags(void *);
100
101 /* audio(4) hardware interface. */
102 static int mpcac97_open(void *, int);
103 static void mpcac97_close(void *);
104 static int mpcac97_query_format(void *, audio_format_query_t *);
105 static int mpcac97_set_format(void *, int, const audio_params_t *,
106 const audio_params_t *, audio_filter_reg_t *,
107 audio_filter_reg_t *);
108 static int mpcac97_round_blocksize(void *, int, int,
109 const audio_params_t *);
110 static size_t mpcac97_round_buffersize(void *, int, size_t);
111 static void *mpcac97_allocm(void *, int, size_t);
112 static void mpcac97_freem(void *, void *, size_t);
113 static int mpcac97_get_props(void *);
114 static int mpcac97_trigger_output(void *, void *, void *, int,
115 void (*)(void *), void *, const audio_params_t *);
116 static int mpcac97_halt_output(void *);
117 static int mpcac97_getdev(void *, struct audio_device *);
118 static int mpcac97_set_port(void *, mixer_ctrl_t *);
119 static int mpcac97_get_port(void *, mixer_ctrl_t *);
120 static int mpcac97_query_devinfo(void *, mixer_devinfo_t *);
121 static void mpcac97_get_locks(void *, kmutex_t **, kmutex_t **);
122
123 CFATTACH_DECL_NEW(mpcaudio, sizeof(struct mpcac97_softc),
124 mpcac97_match, mpcac97_attach, NULL, NULL);
125
126 static const struct bestcomm_bd_layout mpcac97_tx_layout =
127 BESTCOMM_LAYOUT_GEN_TX;
128
129 /*
130 * Data-routing-descriptor offsets
131 */
132 static const uint16_t mpcac97_tx_drd[] = {
133 0x04, 0x0c, 0x10, 0x14, 0x20, 0x28, 0x30, 0x34
134 };
135
136 static const struct audio_format mpcac97_formats[] = {
137 {
138 .mode = AUMODE_PLAY,
139 .encoding = AUDIO_ENCODING_SLINEAR_BE,
140 .validbits = 16,
141 .precision = 32,
142 .channels = 2,
143 .channel_mask = AUFMT_STEREO,
144 .frequency_type = 1,
145 .frequency = { MPCAC97_RATE },
146 },
147 };
148
149 static const struct audio_hw_if mpcac97_hw_if = {
150 .open = mpcac97_open,
151 .close = mpcac97_close,
152 .query_format = mpcac97_query_format,
153 .set_format = mpcac97_set_format,
154 .round_blocksize = mpcac97_round_blocksize,
155 .round_buffersize = mpcac97_round_buffersize,
156 .allocm = mpcac97_allocm,
157 .freem = mpcac97_freem,
158 .get_props = mpcac97_get_props,
159 .trigger_output = mpcac97_trigger_output,
160 .halt_output = mpcac97_halt_output,
161 .getdev = mpcac97_getdev,
162 .set_port = mpcac97_set_port,
163 .get_port = mpcac97_get_port,
164 .query_devinfo = mpcac97_query_devinfo,
165 .get_locks = mpcac97_get_locks,
166 };
167
168 /* Register accessors over the big-endian SoC bus_space tag. */
169 static inline uint8_t
170 RD1(struct mpcac97_softc *sc, bus_size_t o)
171 {
172 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, o);
173 }
174 static inline uint16_t
175 RD2(struct mpcac97_softc *sc, bus_size_t o)
176 {
177 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, o);
178 }
179 static inline uint32_t
180 RD4(struct mpcac97_softc *sc, bus_size_t o)
181 {
182 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, o);
183 }
184 static inline void
185 WR1(struct mpcac97_softc *sc, bus_size_t o, uint8_t v)
186 {
187 bus_space_write_1(sc->sc_iot, sc->sc_ioh, o, v);
188 }
189 static inline void
190 WR2(struct mpcac97_softc *sc, bus_size_t o, uint16_t v)
191 {
192 bus_space_write_2(sc->sc_iot, sc->sc_ioh, o, v);
193 }
194 static inline void
195 WR4(struct mpcac97_softc *sc, bus_size_t o, uint32_t v)
196 {
197 bus_space_write_4(sc->sc_iot, sc->sc_ioh, o, v);
198 }
199
200 static int
201 mpcac97_match(device_t parent, cfdata_t cf, void *aux)
202 {
203 struct obio_attach_args *oba = aux;
204 char compat[40];
205 int len;
206
207 if (strcmp(oba->obio_name, "sound") == 0)
208 return 1;
209
210 len = OF_getprop(oba->obio_node, "compatible", compat, sizeof(compat));
211 if (len > 0 &&
212 (strcmp(compat, "mpc5200-psc-ac97") == 0 ||
213 strcmp(compat, "mpc5200b-psc-ac97") == 0))
214 return 1;
215
216 return 0;
217 }
218
219 static void
220 mpcac97_attach(device_t parent, device_t self, void *aux)
221 {
222 struct mpcac97_softc *sc = device_private(self);
223 struct obio_attach_args *oba = aux;
224 bus_addr_t addr;
225 bus_size_t size;
226
227 sc->sc_dev = self;
228 sc->sc_iot = oba->obio_bst;
229 sc->sc_dmat = oba->obio_dmat;
230
231 aprint_naive("\n");
232 aprint_normal(": MPC5200 AC97 controller\n");
233
234 if (!bestcomm_available()) {
235 aprint_error_dev(self, "BestComm SDMA not available\n");
236 return;
237 }
238
239 /*
240 * XXX: we should not depend on the firmware here?
241 */
242 addr = oba->obio_addr != 0 ? oba->obio_addr :
243 (MPC5200_MBAR_DEFAULT + MPC5200_REG_PSC2);
244 size = oba->obio_size != 0 ? oba->obio_size : MPC5200_PSC_SIZE;
245 sc->sc_pa = addr;
246 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
247 aprint_error_dev(self, "can't map registers\n");
248 return;
249 }
250
251 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
252 /*
253 * XXX: The hardware interrupt lock is at IPL_NET, not usual IPL_AUDIO!
254 * The completion interrupt is a leaf on the shared BestComm SDMA cascade
255 * (along with FEC), and every leaf on that cascade MUST run at the
256 * cascade's own IPL!!! Otherwise, enjoy hard lockups.
257 */
258 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NET);
259
260 /* Put PSC2 into normal AC97 mode and enable the transceiver. */
261 mpcac97_init_psc(sc);
262
263 /*
264 * Attach the codec-independent AC97 layer.
265 */
266 sc->sc_host_if.arg = sc;
267 sc->sc_host_if.attach = mpcac97_ac97_attach;
268 sc->sc_host_if.read = mpcac97_ac97_read;
269 sc->sc_host_if.write = mpcac97_ac97_write;
270 sc->sc_host_if.reset = mpcac97_ac97_reset;
271 sc->sc_host_if.flags = mpcac97_ac97_flags;
272 if (ac97_attach(&sc->sc_host_if, self, &sc->sc_lock) != 0) {
273 aprint_error_dev(self, "no AC97 codec found\n");
274 goto fail;
275 }
276
277 /*
278 * The codec's SPDIF control is lock-gated
279 */
280 mutex_enter(&sc->sc_lock);
281 sc->sc_codec->vtbl->unlock(sc->sc_codec);
282 mutex_exit(&sc->sc_lock);
283
284 /*
285 * Route the BestComm transmit-task completion event to our block
286 * handler.
287 */
288 sc->sc_txih = intr_establish(bestcomm_task_irq(MPCAC97_TX_TASK),
289 IST_LEVEL, IPL_NET, mpcac97_intr, sc);
290 if (sc->sc_txih == NULL) {
291 aprint_error_dev(self, "can't establish SDMA interrupt\n");
292 goto fail;
293 }
294
295 sc->sc_audiodev = audio_attach_mi(&mpcac97_hw_if, sc, self);
296 return;
297
298 fail:
299 if (sc->sc_txih != NULL)
300 intr_disestablish(sc->sc_txih);
301 mutex_destroy(&sc->sc_lock);
302 mutex_destroy(&sc->sc_intr_lock);
303 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
304 }
305
306 /*
307 * Configure PSC2 for "normal" AC97 mode.
308 */
309 static void
310 mpcac97_init_psc(struct mpcac97_softc *sc)
311 {
312
313 WR1(sc, PSC_CR, CMD_RESET_RX);
314 WR1(sc, PSC_CR, CMD_RESET_TX);
315 WR1(sc, PSC_CR, CMD_RESET_ERR);
316 WR1(sc, PSC_CR, CMD_RESET_MR);
317
318 WR4(sc, PSC_SICR, SICR_NORMAL_AC97);
319 WR4(sc, PSC_AC97SLOTS, AC97SLOTS_TX_STEREO);
320
321 WR2(sc, PSC_TFALARM, MPCAC97_TFALARM);
322 WR1(sc, PSC_TFCNTL, MPCAC97_TFGRAN);
323
324 WR2(sc, PSC_IMR, 0); /* no PSC interrupts; BestComm drives playback */
325 }
326
327 /*
328 * BestComm transmit-task completion handler.
329 */
330 static int
331 mpcac97_intr(void *arg)
332 {
333 struct mpcac97_softc *sc = arg;
334 int handled = 0;
335
336 mutex_enter(&sc->sc_intr_lock);
337 if (!sc->sc_txon) {
338 mutex_exit(&sc->sc_intr_lock);
339 return 0;
340 }
341
342 while ((bestcomm_bd_status(&sc->sc_txring, sc->sc_curblk) &
343 BESTCOMM_BD_READY) == 0) {
344 u_int blk = sc->sc_curblk;
345
346 bestcomm_bd_post(&sc->sc_txring, blk,
347 sc->sc_blkbase + blk * sc->sc_blksize, sc->sc_blksize, 0);
348 sc->sc_curblk = (blk + 1) % sc->sc_nblk;
349 if (sc->sc_pintr != NULL)
350 (*sc->sc_pintr)(sc->sc_pintrarg);
351 handled = 1;
352 }
353
354 /* Restart the task if it ran the ring dry between completions. */
355 if (handled)
356 bestcomm_task_start(MPCAC97_TX_TASK);
357
358 mutex_exit(&sc->sc_intr_lock);
359 return handled;
360 }
361
362 /*
363 * ac97(4) host interface.
364 */
365 static int
366 mpcac97_ac97_attach(void *arg, struct ac97_codec_if *codec)
367 {
368 struct mpcac97_softc *sc = arg;
369
370 sc->sc_codec = codec;
371 return 0;
372 }
373
374 static int
375 mpcac97_ac97_read(void *arg, uint8_t reg, uint16_t *valp)
376 {
377 struct mpcac97_softc *sc = arg;
378 int i;
379
380 /* Drop any stale response, then issue the read command. */
381 (void)RD4(sc, PSC_AC97DATA);
382 WR4(sc, PSC_AC97CMD, AC97CMD_READ | AC97CMD_INDEX(reg));
383
384 for (i = 0; i < AC97_CMD_TIMEOUT; i++) {
385 if (RD2(sc, PSC_SR) & AC97_SR_DATA_VALID) {
386 *valp = AC97DATA_VALUE(RD4(sc, PSC_AC97DATA));
387 return 0;
388 }
389 DELAY(10);
390 }
391
392 *valp = 0xffff;
393 return ETIMEDOUT;
394 }
395
396 static int
397 mpcac97_ac97_write(void *arg, uint8_t reg, uint16_t val)
398 {
399 struct mpcac97_softc *sc = arg;
400 int i;
401
402 WR4(sc, PSC_AC97CMD, AC97CMD_WRITE(reg, val));
403
404 /* CMD_SEND is set by the write and cleared once the frame is sent. */
405 for (i = 0; i < AC97_CMD_TIMEOUT; i++) {
406 if ((RD2(sc, PSC_SR) & AC97_SR_CMD_SEND) == 0)
407 return 0;
408 DELAY(10);
409 }
410
411 return ETIMEDOUT;
412 }
413
414 static int
415 mpcac97_ac97_reset(void *arg)
416 {
417 struct mpcac97_softc *sc = arg;
418 uint16_t val;
419 int i;
420
421 /*
422 * Cold-reset the external codec by pulsing RES low then high
423 */
424 WR1(sc, PSC_CR, CMD_TX_DISABLE | CMD_RX_DISABLE);
425 WR1(sc, PSC_OP1, AC97_OP_RES); /* RES -> low */
426 DELAY(1000);
427 WR1(sc, PSC_OP0, AC97_OP_RES); /* RES -> high */
428 DELAY(1000);
429 WR1(sc, PSC_CR, CMD_TX_ENABLE | CMD_RX_ENABLE);
430
431 /* Wait for the codec's analog/digital subsections to power up. */
432 for (i = 0; i < AC97_READY_TIMEOUT; i++) {
433 if (mpcac97_ac97_read(sc, AC97_REG_POWERDOWN, &val) == 0 &&
434 (val & AC97_POWER_READY) == AC97_POWER_READY)
435 return 0;
436 DELAY(1000);
437 }
438
439 aprint_error_dev(sc->sc_dev, "codec not ready after reset\n");
440 return 0; /* best effort: let ac97_attach probe the codec ID */
441 }
442
443 static enum ac97_host_flags
444 mpcac97_ac97_flags(void *arg)
445 {
446
447 return 0;
448 }
449
450 /*
451 * audio(4) hardware interface.
452 */
453 static int
454 mpcac97_open(void *v, int flags)
455 {
456 struct mpcac97_softc *sc = v;
457
458 /*
459 * Lock the codec's SPDIF control for the duration the device is open
460 */
461 sc->sc_codec->vtbl->lock(sc->sc_codec);
462 return 0;
463 }
464
465 static void
466 mpcac97_close(void *v)
467 {
468 struct mpcac97_softc *sc = v;
469
470 sc->sc_codec->vtbl->unlock(sc->sc_codec);
471 }
472
473 static int
474 mpcac97_query_format(void *v, audio_format_query_t *afp)
475 {
476
477 return audio_query_format(mpcac97_formats,
478 __arraycount(mpcac97_formats), afp);
479 }
480
481 static int
482 mpcac97_set_format(void *v, int setmode,
483 const audio_params_t *play, const audio_params_t *rec,
484 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
485 {
486
487 /*
488 * Only the single advertised hardware format is offered
489 */
490 return 0;
491 }
492
493 static int
494 mpcac97_round_blocksize(void *v, int bs, int mode, const audio_params_t *p)
495 {
496
497 /* Keep a block a whole number of 8-byte stereo DMA frames. */
498 bs &= ~(MPCAC97_FRAME_SIZE - 1);
499 if (bs < MPCAC97_FRAME_SIZE)
500 bs = MPCAC97_FRAME_SIZE;
501 return bs;
502 }
503
504 static size_t
505 mpcac97_round_buffersize(void *v, int mode, size_t size)
506 {
507
508 /*
509 * The audio layer sizes the hardware buffer as a whole number of
510 * blocks; keep it intact.
511 */
512 return size;
513 }
514
515 static void *
516 mpcac97_allocm(void *v, int direction, size_t size)
517 {
518 struct mpcac97_softc *sc = v;
519 int rseg;
520
521 if (direction != AUMODE_PLAY) /* playback only */
522 return NULL;
523 if (sc->sc_dmakva != NULL) /* one play buffer */
524 return NULL;
525
526 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &sc->sc_dmaseg,
527 1, &rseg, BUS_DMA_WAITOK) != 0)
528 return NULL;
529 sc->sc_dmanseg = rseg;
530 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_dmaseg, rseg, size,
531 &sc->sc_dmakva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
532 goto free;
533 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_WAITOK,
534 &sc->sc_dmamap) != 0)
535 goto unmap;
536 if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmakva, size,
537 NULL, BUS_DMA_WAITOK) != 0)
538 goto destroy;
539
540 sc->sc_dmaphys = sc->sc_dmamap->dm_segs[0].ds_addr;
541 sc->sc_dmasize = size;
542 return sc->sc_dmakva;
543
544 destroy:
545 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
546 sc->sc_dmamap = NULL;
547 unmap:
548 bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmakva, size);
549 sc->sc_dmakva = NULL;
550 free:
551 bus_dmamem_free(sc->sc_dmat, &sc->sc_dmaseg, rseg);
552 return NULL;
553 }
554
555 static void
556 mpcac97_freem(void *v, void *ptr, size_t size)
557 {
558 struct mpcac97_softc *sc = v;
559
560 if (ptr != sc->sc_dmakva)
561 return;
562
563 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
564 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
565 bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmakva, size);
566 bus_dmamem_free(sc->sc_dmat, &sc->sc_dmaseg, sc->sc_dmanseg);
567 sc->sc_dmamap = NULL;
568 sc->sc_dmakva = NULL;
569 sc->sc_dmasize = 0;
570 }
571
572 static int
573 mpcac97_get_props(void *v)
574 {
575
576 return AUDIO_PROP_PLAYBACK;
577 }
578
579 static int
580 mpcac97_trigger_output(void *v, void *start, void *end, int blksize,
581 void (*intr)(void *), void *arg, const audio_params_t *param)
582 {
583 struct mpcac97_softc *sc = v;
584 bus_addr_t base;
585 u_int i, nblk;
586
587 nblk = ((char *)end - (char *)start) / blksize;
588 if (nblk == 0 || nblk > MPCAC97_MAX_NBLK)
589 return EINVAL;
590 if ((char *)start < (char *)sc->sc_dmakva ||
591 (char *)start + nblk * blksize >
592 (char *)sc->sc_dmakva + sc->sc_dmasize)
593 return EINVAL;
594
595 base = sc->sc_dmaphys + ((char *)start - (char *)sc->sc_dmakva);
596
597 /* (Re)build the BD ring: one descriptor per audio block. */
598 bestcomm_bd_teardown(&sc->sc_txring);
599 if (bestcomm_bd_setup(&sc->sc_txring, MPCAC97_TX_TASK,
600 &mpcac97_tx_layout, sc->sc_pa + AC97_FIFO_TX, nblk, blksize,
601 sizeof(uint32_t), MPCAC97_TX_INITIATOR, MPCAC97_TX_PRIO) != 0)
602 return ENOMEM;
603
604 /*
605 * GEN_TX_BD is a runtime-configurable task
606 */
607 bestcomm_task_set_initiator(MPCAC97_TX_TASK, MPCAC97_TX_INITIATOR,
608 mpcac97_tx_drd, __arraycount(mpcac97_tx_drd));
609
610 sc->sc_blkbase = base;
611 sc->sc_blksize = blksize;
612 sc->sc_nblk = nblk;
613 sc->sc_curblk = 0;
614 sc->sc_pintr = intr;
615 sc->sc_pintrarg = arg;
616 sc->sc_txon = true;
617
618 for (i = 0; i < nblk; i++)
619 bestcomm_bd_post(&sc->sc_txring, i, base + i * blksize,
620 blksize, 0);
621
622 bestcomm_task_start(MPCAC97_TX_TASK);
623 return 0;
624 }
625
626 static int
627 mpcac97_halt_output(void *v)
628 {
629 struct mpcac97_softc *sc = v;
630
631 sc->sc_txon = false;
632 sc->sc_pintr = NULL;
633 sc->sc_pintrarg = NULL;
634 bestcomm_bd_teardown(&sc->sc_txring);
635 return 0;
636 }
637
638 static int
639 mpcac97_getdev(void *v, struct audio_device *adp)
640 {
641
642 strlcpy(adp->name, "MPC5200 AC97", sizeof(adp->name));
643 strlcpy(adp->version, "", sizeof(adp->version));
644 strlcpy(adp->config, "mpcac97", sizeof(adp->config));
645 return 0;
646 }
647
648 static int
649 mpcac97_set_port(void *v, mixer_ctrl_t *mc)
650 {
651 struct mpcac97_softc *sc = v;
652
653 return sc->sc_codec->vtbl->mixer_set_port(sc->sc_codec, mc);
654 }
655
656 static int
657 mpcac97_get_port(void *v, mixer_ctrl_t *mc)
658 {
659 struct mpcac97_softc *sc = v;
660
661 return sc->sc_codec->vtbl->mixer_get_port(sc->sc_codec, mc);
662 }
663
664 static int
665 mpcac97_query_devinfo(void *v, mixer_devinfo_t *di)
666 {
667 struct mpcac97_softc *sc = v;
668
669 return sc->sc_codec->vtbl->query_devinfo(sc->sc_codec, di);
670 }
671
672 static void
673 mpcac97_get_locks(void *v, kmutex_t **intr, kmutex_t **thread)
674 {
675 struct mpcac97_softc *sc = v;
676
677 *intr = &sc->sc_intr_lock;
678 *thread = &sc->sc_lock;
679 }
680