| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: audio.c,v 1.247 2009/09/24 16:03:11 sborrill Exp $ */ | | 1 | /* $NetBSD: audio.c,v 1.248 2009/09/29 15:58:54 sborrill Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1991-1993 Regents of the University of California. | | 4 | * Copyright (c) 1991-1993 Regents of the University of California. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -51,27 +51,27 @@ | | | @@ -51,27 +51,27 @@ |
51 | * generated. | | 51 | * generated. |
52 | * | | 52 | * |
53 | * If you try to set both play and record mode on a half-duplex | | 53 | * If you try to set both play and record mode on a half-duplex |
54 | * device, playing takes precedence. | | 54 | * device, playing takes precedence. |
55 | */ | | 55 | */ |
56 | | | 56 | |
57 | /* | | 57 | /* |
58 | * Todo: | | 58 | * Todo: |
59 | * - Add softaudio() isr processing for wakeup, poll, signals, | | 59 | * - Add softaudio() isr processing for wakeup, poll, signals, |
60 | * and silence fill. | | 60 | * and silence fill. |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | #include <sys/cdefs.h> | | 63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.247 2009/09/24 16:03:11 sborrill Exp $"); | | 64 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.248 2009/09/29 15:58:54 sborrill Exp $"); |
65 | | | 65 | |
66 | #include "audio.h" | | 66 | #include "audio.h" |
67 | #if NAUDIO > 0 | | 67 | #if NAUDIO > 0 |
68 | | | 68 | |
69 | #include <sys/param.h> | | 69 | #include <sys/param.h> |
70 | #include <sys/ioctl.h> | | 70 | #include <sys/ioctl.h> |
71 | #include <sys/fcntl.h> | | 71 | #include <sys/fcntl.h> |
72 | #include <sys/vnode.h> | | 72 | #include <sys/vnode.h> |
73 | #include <sys/select.h> | | 73 | #include <sys/select.h> |
74 | #include <sys/poll.h> | | 74 | #include <sys/poll.h> |
75 | #include <sys/malloc.h> | | 75 | #include <sys/malloc.h> |
76 | #include <sys/proc.h> | | 76 | #include <sys/proc.h> |
77 | #include <sys/systm.h> | | 77 | #include <sys/systm.h> |
| @@ -182,26 +182,30 @@ int audioactivate(device_t, enum devact) | | | @@ -182,26 +182,30 @@ int audioactivate(device_t, enum devact) |
182 | static void audio_idle(void *); | | 182 | static void audio_idle(void *); |
183 | static void audio_activity(device_t, devactive_t); | | 183 | static void audio_activity(device_t, devactive_t); |
184 | #endif | | 184 | #endif |
185 | | | 185 | |
186 | static bool audio_suspend(device_t dv PMF_FN_PROTO); | | 186 | static bool audio_suspend(device_t dv PMF_FN_PROTO); |
187 | static bool audio_resume(device_t dv PMF_FN_PROTO); | | 187 | static bool audio_resume(device_t dv PMF_FN_PROTO); |
188 | static void audio_volume_down(device_t); | | 188 | static void audio_volume_down(device_t); |
189 | static void audio_volume_up(device_t); | | 189 | static void audio_volume_up(device_t); |
190 | static void audio_volume_toggle(device_t); | | 190 | static void audio_volume_toggle(device_t); |
191 | | | 191 | |
192 | static void audio_mixer_capture(struct audio_softc *); | | 192 | static void audio_mixer_capture(struct audio_softc *); |
193 | static void audio_mixer_restore(struct audio_softc *); | | 193 | static void audio_mixer_restore(struct audio_softc *); |
194 | | | 194 | |
| | | 195 | static int audio_get_props(struct audio_softc *); |
| | | 196 | static bool audio_can_playback(struct audio_softc *); |
| | | 197 | static bool audio_can_capture(struct audio_softc *); |
| | | 198 | |
195 | static void audio_softintr_rd(void *); | | 199 | static void audio_softintr_rd(void *); |
196 | static void audio_softintr_wr(void *); | | 200 | static void audio_softintr_wr(void *); |
197 | | | 201 | |
198 | struct portname { | | 202 | struct portname { |
199 | const char *name; | | 203 | const char *name; |
200 | int mask; | | 204 | int mask; |
201 | }; | | 205 | }; |
202 | static const struct portname itable[] = { | | 206 | static const struct portname itable[] = { |
203 | { AudioNmicrophone, AUDIO_MICROPHONE }, | | 207 | { AudioNmicrophone, AUDIO_MICROPHONE }, |
204 | { AudioNline, AUDIO_LINE_IN }, | | 208 | { AudioNline, AUDIO_LINE_IN }, |
205 | { AudioNcd, AUDIO_CD }, | | 209 | { AudioNcd, AUDIO_CD }, |
206 | { 0, 0 } | | 210 | { 0, 0 } |
207 | }; | | 211 | }; |
| @@ -305,61 +309,71 @@ audioattach(device_t parent, device_t se | | | @@ -305,61 +309,71 @@ audioattach(device_t parent, device_t se |
305 | hwp->halt_output == 0 || | | 309 | hwp->halt_output == 0 || |
306 | hwp->halt_input == 0 || | | 310 | hwp->halt_input == 0 || |
307 | hwp->getdev == 0 || | | 311 | hwp->getdev == 0 || |
308 | hwp->set_port == 0 || | | 312 | hwp->set_port == 0 || |
309 | hwp->get_port == 0 || | | 313 | hwp->get_port == 0 || |
310 | hwp->query_devinfo == 0 || | | 314 | hwp->query_devinfo == 0 || |
311 | hwp->get_props == 0) { | | 315 | hwp->get_props == 0) { |
312 | printf(": missing method\n"); | | 316 | printf(": missing method\n"); |
313 | sc->hw_if = 0; | | 317 | sc->hw_if = 0; |
314 | return; | | 318 | return; |
315 | } | | 319 | } |
316 | #endif | | 320 | #endif |
317 | | | 321 | |
318 | props = hwp->get_props(hdlp); | | 322 | sc->hw_if = hwp; |
| | | 323 | sc->hw_hdl = hdlp; |
| | | 324 | sc->sc_dev = parent; |
| | | 325 | sc->sc_opencnt = 0; |
| | | 326 | sc->sc_writing = sc->sc_waitcomp = 0; |
| | | 327 | sc->sc_lastinfovalid = false; |
319 | | | 328 | |
320 | aprint_naive("\n"); | | 329 | props = audio_get_props(sc); |
321 | | | 330 | |
322 | if (props & AUDIO_PROP_FULLDUPLEX) | | 331 | if (props & AUDIO_PROP_FULLDUPLEX) |
323 | aprint_normal(": full duplex"); | | 332 | aprint_normal(": full duplex"); |
324 | else | | 333 | else |
325 | aprint_normal(": half duplex"); | | 334 | aprint_normal(": half duplex"); |
326 | | | 335 | |
| | | 336 | if (props & AUDIO_PROP_PLAYBACK) |
| | | 337 | aprint_normal(", playback"); |
| | | 338 | if (props & AUDIO_PROP_CAPTURE) |
| | | 339 | aprint_normal(", capture"); |
327 | if (props & AUDIO_PROP_MMAP) | | 340 | if (props & AUDIO_PROP_MMAP) |
328 | aprint_normal(", mmap"); | | 341 | aprint_normal(", mmap"); |
329 | if (props & AUDIO_PROP_INDEPENDENT) | | 342 | if (props & AUDIO_PROP_INDEPENDENT) |
330 | aprint_normal(", independent"); | | 343 | aprint_normal(", independent"); |
331 | | | 344 | |
| | | 345 | aprint_naive("\n"); |
332 | aprint_normal("\n"); | | 346 | aprint_normal("\n"); |
333 | | | 347 | |
334 | sc->hw_if = hwp; | | 348 | if (audio_can_playback(sc)) { |
335 | sc->hw_hdl = hdlp; | | 349 | error = audio_alloc_ring(sc, &sc->sc_pr, |
336 | sc->sc_dev = parent; | | 350 | AUMODE_PLAY, AU_RING_SIZE); |
337 | sc->sc_opencnt = 0; | | 351 | if (error) { |
338 | sc->sc_writing = sc->sc_waitcomp = 0; | | 352 | sc->hw_if = NULL; |
339 | sc->sc_lastinfovalid = false; | | 353 | aprint_error("audio: could not allocate play buffer\n"); |
340 | | | 354 | return; |
341 | error = audio_alloc_ring(sc, &sc->sc_pr, AUMODE_PLAY, AU_RING_SIZE); | | 355 | } |
342 | if (error) { | | | |
343 | sc->hw_if = NULL; | | | |
344 | aprint_error("audio: could not allocate play buffer\n"); | | | |
345 | return; | | | |
346 | } | | 356 | } |
347 | error = audio_alloc_ring(sc, &sc->sc_rr, AUMODE_RECORD, AU_RING_SIZE); | | 357 | if (audio_can_capture(sc)) { |
348 | if (error) { | | 358 | error = audio_alloc_ring(sc, &sc->sc_rr, |
349 | audio_free_ring(sc, &sc->sc_pr); | | 359 | AUMODE_RECORD, AU_RING_SIZE); |
350 | sc->hw_if = NULL; | | 360 | if (error) { |
351 | aprint_error("audio: could not allocate record buffer\n"); | | 361 | if (sc->sc_pr.s.start != 0) |
352 | return; | | 362 | audio_free_ring(sc, &sc->sc_pr); |
| | | 363 | sc->hw_if = NULL; |
| | | 364 | aprint_error("audio: could not allocate record buffer\n"); |
| | | 365 | return; |
| | | 366 | } |
353 | } | | 367 | } |
354 | | | 368 | |
355 | sc->sc_lastgain = 128; | | 369 | sc->sc_lastgain = 128; |
356 | | | 370 | |
357 | if ((error = audio_set_defaults(sc, 0))) { | | 371 | if ((error = audio_set_defaults(sc, 0))) { |
358 | aprint_error("audioattach: audio_set_defaults() failed\n"); | | 372 | aprint_error("audioattach: audio_set_defaults() failed\n"); |
359 | sc->hw_if = NULL; | | 373 | sc->hw_if = NULL; |
360 | return; | | 374 | return; |
361 | } | | 375 | } |
362 | | | 376 | |
363 | sc->sc_sih_rd = softint_establish(SOFTINT_SERIAL, | | 377 | sc->sc_sih_rd = softint_establish(SOFTINT_SERIAL, |
364 | audio_softintr_rd, sc); | | 378 | audio_softintr_rd, sc); |
365 | sc->sc_sih_wr = softint_establish(SOFTINT_SERIAL, | | 379 | sc->sc_sih_wr = softint_establish(SOFTINT_SERIAL, |
| @@ -732,26 +746,28 @@ audio_alloc_ring(struct audio_softc *sc, | | | @@ -732,26 +746,28 @@ audio_alloc_ring(struct audio_softc *sc, |
732 | r->s.start = hw->allocm(hdl, direction, bufsize, | | 746 | r->s.start = hw->allocm(hdl, direction, bufsize, |
733 | M_DEVBUF, M_WAITOK); | | 747 | M_DEVBUF, M_WAITOK); |
734 | else | | 748 | else |
735 | r->s.start = malloc(bufsize, M_DEVBUF, M_WAITOK); | | 749 | r->s.start = malloc(bufsize, M_DEVBUF, M_WAITOK); |
736 | if (r->s.start == 0) | | 750 | if (r->s.start == 0) |
737 | return ENOMEM; | | 751 | return ENOMEM; |
738 | r->s.bufsize = bufsize; | | 752 | r->s.bufsize = bufsize; |
739 | return 0; | | 753 | return 0; |
740 | } | | 754 | } |
741 | | | 755 | |
742 | void | | 756 | void |
743 | audio_free_ring(struct audio_softc *sc, struct audio_ringbuffer *r) | | 757 | audio_free_ring(struct audio_softc *sc, struct audio_ringbuffer *r) |
744 | { | | 758 | { |
| | | 759 | if (r->s.start == 0) |
| | | 760 | return; |
745 | | | 761 | |
746 | if (sc->hw_if->freem) | | 762 | if (sc->hw_if->freem) |
747 | sc->hw_if->freem(sc->hw_hdl, r->s.start, M_DEVBUF); | | 763 | sc->hw_if->freem(sc->hw_hdl, r->s.start, M_DEVBUF); |
748 | else | | 764 | else |
749 | free(r->s.start, M_DEVBUF); | | 765 | free(r->s.start, M_DEVBUF); |
750 | r->s.start = 0; | | 766 | r->s.start = 0; |
751 | } | | 767 | } |
752 | | | 768 | |
753 | static int | | 769 | static int |
754 | audio_setup_pfilters(struct audio_softc *sc, const audio_params_t *pp, | | 770 | audio_setup_pfilters(struct audio_softc *sc, const audio_params_t *pp, |
755 | stream_filter_list_t *pfilters) | | 771 | stream_filter_list_t *pfilters) |
756 | { | | 772 | { |
757 | stream_filter_t *pf[AUDIO_MAX_FILTERS]; | | 773 | stream_filter_t *pf[AUDIO_MAX_FILTERS]; |
| @@ -1291,84 +1307,98 @@ audio_init_ringbuffer(struct audio_softc | | | @@ -1291,84 +1307,98 @@ audio_init_ringbuffer(struct audio_softc |
1291 | rp->copying = false; | | 1307 | rp->copying = false; |
1292 | rp->needfill = false; | | 1308 | rp->needfill = false; |
1293 | rp->mmapped = false; | | 1309 | rp->mmapped = false; |
1294 | } | | 1310 | } |
1295 | | | 1311 | |
1296 | int | | 1312 | int |
1297 | audio_initbufs(struct audio_softc *sc) | | 1313 | audio_initbufs(struct audio_softc *sc) |
1298 | { | | 1314 | { |
1299 | const struct audio_hw_if *hw; | | 1315 | const struct audio_hw_if *hw; |
1300 | int error; | | 1316 | int error; |
1301 | | | 1317 | |
1302 | DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_mode)); | | 1318 | DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_mode)); |
1303 | hw = sc->hw_if; | | 1319 | hw = sc->hw_if; |
1304 | audio_init_ringbuffer(sc, &sc->sc_rr, AUMODE_RECORD); | | 1320 | if (audio_can_capture(sc)) { |
1305 | if (hw->init_input && (sc->sc_mode & AUMODE_RECORD)) { | | 1321 | audio_init_ringbuffer(sc, &sc->sc_rr, AUMODE_RECORD); |
1306 | error = hw->init_input(sc->hw_hdl, sc->sc_rr.s.start, | | 1322 | if (hw->init_input && (sc->sc_mode & AUMODE_RECORD)) { |
| | | 1323 | error = hw->init_input(sc->hw_hdl, sc->sc_rr.s.start, |
1307 | sc->sc_rr.s.end - sc->sc_rr.s.start); | | 1324 | sc->sc_rr.s.end - sc->sc_rr.s.start); |
1308 | if (error) | | 1325 | if (error) |
1309 | return error; | | 1326 | return error; |
| | | 1327 | } |
1310 | } | | 1328 | } |
1311 | | | 1329 | |
1312 | audio_init_ringbuffer(sc, &sc->sc_pr, AUMODE_PLAY); | | 1330 | if (audio_can_playback(sc)) { |
1313 | sc->sc_sil_count = 0; | | 1331 | audio_init_ringbuffer(sc, &sc->sc_pr, AUMODE_PLAY); |
1314 | if (hw->init_output && (sc->sc_mode & AUMODE_PLAY)) { | | 1332 | sc->sc_sil_count = 0; |
1315 | error = hw->init_output(sc->hw_hdl, sc->sc_pr.s.start, | | 1333 | if (hw->init_output && (sc->sc_mode & AUMODE_PLAY)) { |
| | | 1334 | error = hw->init_output(sc->hw_hdl, sc->sc_pr.s.start, |
1316 | sc->sc_pr.s.end - sc->sc_pr.s.start); | | 1335 | sc->sc_pr.s.end - sc->sc_pr.s.start); |
1317 | if (error) | | 1336 | if (error) |
1318 | return error; | | 1337 | return error; |
| | | 1338 | } |
1319 | } | | 1339 | } |
1320 | | | 1340 | |
1321 | #ifdef AUDIO_INTR_TIME | | 1341 | #ifdef AUDIO_INTR_TIME |
1322 | #define double u_long | | 1342 | #define double u_long |
1323 | sc->sc_pnintr = 0; | | 1343 | if (audio_can_playback(sc)) { |
1324 | sc->sc_pblktime = (u_long)( | | 1344 | sc->sc_pnintr = 0; |
1325 | (double)sc->sc_pr.blksize * 100000 / | | 1345 | sc->sc_pblktime = (u_long)( |
1326 | (double)(sc->sc_pparams.precision / NBBY * | | 1346 | (double)sc->sc_pr.blksize * 100000 / |
1327 | sc->sc_pparams.channels * | | 1347 | (double)(sc->sc_pparams.precision / NBBY * |
1328 | sc->sc_pparams.sample_rate)) * 10; | | 1348 | sc->sc_pparams.channels * |
1329 | DPRINTF(("audio: play blktime = %lu for %d\n", | | 1349 | sc->sc_pparams.sample_rate)) * 10; |
1330 | sc->sc_pblktime, sc->sc_pr.blksize)); | | 1350 | DPRINTF(("audio: play blktime = %lu for %d\n", |
1331 | sc->sc_rnintr = 0; | | 1351 | sc->sc_pblktime, sc->sc_pr.blksize)); |
1332 | sc->sc_rblktime = (u_long)( | | 1352 | } |
1333 | (double)sc->sc_rr.blksize * 100000 / | | 1353 | if (audio_can_capture(sc)) { |
1334 | (double)(sc->sc_rparams.precision / NBBY * | | 1354 | sc->sc_rnintr = 0; |
1335 | sc->sc_rparams.channels * | | 1355 | sc->sc_rblktime = (u_long)( |
1336 | sc->sc_rparams.sample_rate)) * 10; | | 1356 | (double)sc->sc_rr.blksize * 100000 / |
1337 | DPRINTF(("audio: record blktime = %lu for %d\n", | | 1357 | (double)(sc->sc_rparams.precision / NBBY * |
1338 | sc->sc_rblktime, sc->sc_rr.blksize)); | | 1358 | sc->sc_rparams.channels * |
| | | 1359 | sc->sc_rparams.sample_rate)) * 10; |
| | | 1360 | DPRINTF(("audio: record blktime = %lu for %d\n", |
| | | 1361 | sc->sc_rblktime, sc->sc_rr.blksize)); |
| | | 1362 | } |
1339 | #undef double | | 1363 | #undef double |
1340 | #endif | | 1364 | #endif |
1341 | | | 1365 | |
1342 | return 0; | | 1366 | return 0; |
1343 | } | | 1367 | } |
1344 | | | 1368 | |
1345 | void | | 1369 | void |
1346 | audio_calcwater(struct audio_softc *sc) | | 1370 | audio_calcwater(struct audio_softc *sc) |
1347 | { | | 1371 | { |
1348 | | | 1372 | |
1349 | /* set high at 100% */ | | 1373 | /* set high at 100% */ |
1350 | sc->sc_pr.usedhigh = sc->sc_pustream->end - sc->sc_pustream->start; | | 1374 | if (audio_can_playback(sc)) { |
1351 | /* set low at 75% of usedhigh */ | | 1375 | sc->sc_pr.usedhigh = |
1352 | sc->sc_pr.usedlow = sc->sc_pr.usedhigh * 3 / 4; | | 1376 | sc->sc_pustream->end - sc->sc_pustream->start; |
1353 | if (sc->sc_pr.usedlow == sc->sc_pr.usedhigh) | | 1377 | /* set low at 75% of usedhigh */ |
1354 | sc->sc_pr.usedlow -= sc->sc_pr.blksize; | | 1378 | sc->sc_pr.usedlow = sc->sc_pr.usedhigh * 3 / 4; |
1355 | | | 1379 | if (sc->sc_pr.usedlow == sc->sc_pr.usedhigh) |
1356 | sc->sc_rr.usedhigh = sc->sc_rustream->end - sc->sc_rustream->start | | 1380 | sc->sc_pr.usedlow -= sc->sc_pr.blksize; |
1357 | - sc->sc_rr.blksize; | | 1381 | } |
1358 | sc->sc_rr.usedlow = 0; | | 1382 | |
1359 | DPRINTF(("%s: plow=%d phigh=%d rlow=%d rhigh=%d\n", __func__, | | 1383 | if (audio_can_capture(sc)) { |
1360 | sc->sc_pr.usedlow, sc->sc_pr.usedhigh, | | 1384 | sc->sc_rr.usedhigh = |
1361 | sc->sc_rr.usedlow, sc->sc_rr.usedhigh)); | | 1385 | sc->sc_rustream->end - sc->sc_rustream->start - |
| | | 1386 | sc->sc_rr.blksize; |
| | | 1387 | sc->sc_rr.usedlow = 0; |
| | | 1388 | DPRINTF(("%s: plow=%d phigh=%d rlow=%d rhigh=%d\n", __func__, |
| | | 1389 | sc->sc_pr.usedlow, sc->sc_pr.usedhigh, |
| | | 1390 | sc->sc_rr.usedlow, sc->sc_rr.usedhigh)); |
| | | 1391 | } |
1362 | } | | 1392 | } |
1363 | | | 1393 | |
1364 | static inline int | | 1394 | static inline int |
1365 | audio_sleep_timo(int *chan, const char *label, int timo) | | 1395 | audio_sleep_timo(int *chan, const char *label, int timo) |
1366 | { | | 1396 | { |
1367 | int st; | | 1397 | int st; |
1368 | | | 1398 | |
1369 | if (label == NULL) | | 1399 | if (label == NULL) |
1370 | label = "audio"; | | 1400 | label = "audio"; |
1371 | | | 1401 | |
1372 | DPRINTFN(3, ("audio_sleep_timo: chan=%p, label=%s, timo=%d\n", | | 1402 | DPRINTFN(3, ("audio_sleep_timo: chan=%p, label=%s, timo=%d\n", |
1373 | chan, label, timo)); | | 1403 | chan, label, timo)); |
1374 | *chan = 1; | | 1404 | *chan = 1; |
| @@ -1426,27 +1456,27 @@ audio_open(dev_t dev, struct audio_softc | | | @@ -1426,27 +1456,27 @@ audio_open(dev_t dev, struct audio_softc |
1426 | } | | 1456 | } |
1427 | | | 1457 | |
1428 | sc->sc_async_audio = 0; | | 1458 | sc->sc_async_audio = 0; |
1429 | sc->sc_rchan = 0; | | 1459 | sc->sc_rchan = 0; |
1430 | sc->sc_wchan = 0; | | 1460 | sc->sc_wchan = 0; |
1431 | sc->sc_sil_count = 0; | | 1461 | sc->sc_sil_count = 0; |
1432 | sc->sc_rbus = false; | | 1462 | sc->sc_rbus = false; |
1433 | sc->sc_pbus = false; | | 1463 | sc->sc_pbus = false; |
1434 | sc->sc_eof = 0; | | 1464 | sc->sc_eof = 0; |
1435 | sc->sc_playdrop = 0; | | 1465 | sc->sc_playdrop = 0; |
1436 | | | 1466 | |
1437 | sc->sc_full_duplex = | | 1467 | sc->sc_full_duplex = |
1438 | (flags & (FWRITE|FREAD)) == (FWRITE|FREAD) && | | 1468 | (flags & (FWRITE|FREAD)) == (FWRITE|FREAD) && |
1439 | (hw->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX); | | 1469 | (audio_get_props(sc) & AUDIO_PROP_FULLDUPLEX); |
1440 | | | 1470 | |
1441 | mode = 0; | | 1471 | mode = 0; |
1442 | if (flags & FREAD) { | | 1472 | if (flags & FREAD) { |
1443 | sc->sc_open |= AUOPEN_READ; | | 1473 | sc->sc_open |= AUOPEN_READ; |
1444 | mode |= AUMODE_RECORD; | | 1474 | mode |= AUMODE_RECORD; |
1445 | } | | 1475 | } |
1446 | if (flags & FWRITE) { | | 1476 | if (flags & FWRITE) { |
1447 | sc->sc_open |= AUOPEN_WRITE; | | 1477 | sc->sc_open |= AUOPEN_WRITE; |
1448 | mode |= AUMODE_PLAY | AUMODE_PLAY_ALL; | | 1478 | mode |= AUMODE_PLAY | AUMODE_PLAY_ALL; |
1449 | } | | 1479 | } |
1450 | | | 1480 | |
1451 | /* | | 1481 | /* |
1452 | * Multiplex device: /dev/audio (MU-Law) and /dev/sound (linear) | | 1482 | * Multiplex device: /dev/audio (MU-Law) and /dev/sound (linear) |
| @@ -2241,44 +2271,44 @@ audio_ioctl(struct audio_softc *sc, u_lo | | | @@ -2241,44 +2271,44 @@ audio_ioctl(struct audio_softc *sc, u_lo |
2241 | DPRINTF(("AUDIO_GETENC\n")); | | 2271 | DPRINTF(("AUDIO_GETENC\n")); |
2242 | error = hw->query_encoding(sc->hw_hdl, | | 2272 | error = hw->query_encoding(sc->hw_hdl, |
2243 | (struct audio_encoding *)addr); | | 2273 | (struct audio_encoding *)addr); |
2244 | break; | | 2274 | break; |
2245 | | | 2275 | |
2246 | case AUDIO_GETFD: | | 2276 | case AUDIO_GETFD: |
2247 | DPRINTF(("AUDIO_GETFD\n")); | | 2277 | DPRINTF(("AUDIO_GETFD\n")); |
2248 | *(int *)addr = sc->sc_full_duplex; | | 2278 | *(int *)addr = sc->sc_full_duplex; |
2249 | break; | | 2279 | break; |
2250 | | | 2280 | |
2251 | case AUDIO_SETFD: | | 2281 | case AUDIO_SETFD: |
2252 | DPRINTF(("AUDIO_SETFD\n")); | | 2282 | DPRINTF(("AUDIO_SETFD\n")); |
2253 | fd = *(int *)addr; | | 2283 | fd = *(int *)addr; |
2254 | if (hw->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX) { | | 2284 | if (audio_get_props(sc) & AUDIO_PROP_FULLDUPLEX) { |
2255 | if (hw->setfd) | | 2285 | if (hw->setfd) |
2256 | error = hw->setfd(sc->hw_hdl, fd); | | 2286 | error = hw->setfd(sc->hw_hdl, fd); |
2257 | else | | 2287 | else |
2258 | error = 0; | | 2288 | error = 0; |
2259 | if (!error) | | 2289 | if (!error) |
2260 | sc->sc_full_duplex = fd; | | 2290 | sc->sc_full_duplex = fd; |
2261 | } else { | | 2291 | } else { |
2262 | if (fd) | | 2292 | if (fd) |
2263 | error = ENOTTY; | | 2293 | error = ENOTTY; |
2264 | else | | 2294 | else |
2265 | error = 0; | | 2295 | error = 0; |
2266 | } | | 2296 | } |
2267 | break; | | 2297 | break; |
2268 | | | 2298 | |
2269 | case AUDIO_GETPROPS: | | 2299 | case AUDIO_GETPROPS: |
2270 | DPRINTF(("AUDIO_GETPROPS\n")); | | 2300 | DPRINTF(("AUDIO_GETPROPS\n")); |
2271 | *(int *)addr = hw->get_props(sc->hw_hdl); | | 2301 | *(int *)addr = audio_get_props(sc); |
2272 | break; | | 2302 | break; |
2273 | | | 2303 | |
2274 | default: | | 2304 | default: |
2275 | if (hw->dev_ioctl) { | | 2305 | if (hw->dev_ioctl) { |
2276 | error = hw->dev_ioctl(sc->hw_hdl, cmd, addr, flag, l); | | 2306 | error = hw->dev_ioctl(sc->hw_hdl, cmd, addr, flag, l); |
2277 | } else { | | 2307 | } else { |
2278 | DPRINTF(("audio_ioctl: unknown ioctl\n")); | | 2308 | DPRINTF(("audio_ioctl: unknown ioctl\n")); |
2279 | error = EINVAL; | | 2309 | error = EINVAL; |
2280 | } | | 2310 | } |
2281 | break; | | 2311 | break; |
2282 | } | | 2312 | } |
2283 | DPRINTF(("audio_ioctl(%lu,'%c',%lu) result %d\n", | | 2313 | DPRINTF(("audio_ioctl(%lu,'%c',%lu) result %d\n", |
2284 | IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xff, error)); | | 2314 | IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xff, error)); |
| @@ -2429,27 +2459,27 @@ audio_kqfilter(struct audio_softc *sc, s | | | @@ -2429,27 +2459,27 @@ audio_kqfilter(struct audio_softc *sc, s |
2429 | | | 2459 | |
2430 | return 0; | | 2460 | return 0; |
2431 | } | | 2461 | } |
2432 | | | 2462 | |
2433 | paddr_t | | 2463 | paddr_t |
2434 | audio_mmap(struct audio_softc *sc, off_t off, int prot) | | 2464 | audio_mmap(struct audio_softc *sc, off_t off, int prot) |
2435 | { | | 2465 | { |
2436 | const struct audio_hw_if *hw; | | 2466 | const struct audio_hw_if *hw; |
2437 | struct audio_ringbuffer *cb; | | 2467 | struct audio_ringbuffer *cb; |
2438 | int s; | | 2468 | int s; |
2439 | | | 2469 | |
2440 | DPRINTF(("audio_mmap: off=%lld, prot=%d\n", (long long)off, prot)); | | 2470 | DPRINTF(("audio_mmap: off=%lld, prot=%d\n", (long long)off, prot)); |
2441 | hw = sc->hw_if; | | 2471 | hw = sc->hw_if; |
2442 | if (!(hw->get_props(sc->hw_hdl) & AUDIO_PROP_MMAP) || !hw->mappage) | | 2472 | if (!(audio_get_props(sc) & AUDIO_PROP_MMAP) || !hw->mappage) |
2443 | return -1; | | 2473 | return -1; |
2444 | #if 0 | | 2474 | #if 0 |
2445 | /* XXX | | 2475 | /* XXX |
2446 | * The idea here was to use the protection to determine if | | 2476 | * The idea here was to use the protection to determine if |
2447 | * we are mapping the read or write buffer, but it fails. | | 2477 | * we are mapping the read or write buffer, but it fails. |
2448 | * The VM system is broken in (at least) two ways. | | 2478 | * The VM system is broken in (at least) two ways. |
2449 | * 1) If you map memory VM_PROT_WRITE you SIGSEGV | | 2479 | * 1) If you map memory VM_PROT_WRITE you SIGSEGV |
2450 | * when writing to it, so VM_PROT_READ|VM_PROT_WRITE | | 2480 | * when writing to it, so VM_PROT_READ|VM_PROT_WRITE |
2451 | * has to be used for mmapping the play buffer. | | 2481 | * has to be used for mmapping the play buffer. |
2452 | * 2) Even if calling mmap() with VM_PROT_READ|VM_PROT_WRITE | | 2482 | * 2) Even if calling mmap() with VM_PROT_READ|VM_PROT_WRITE |
2453 | * audio_mmap will get called at some point with VM_PROT_READ | | 2483 | * audio_mmap will get called at some point with VM_PROT_READ |
2454 | * only. | | 2484 | * only. |
2455 | * So, alas, we always map the play buffer for now. | | 2485 | * So, alas, we always map the play buffer for now. |
| @@ -2488,52 +2518,58 @@ audio_mmap(struct audio_softc *sc, off_t | | | @@ -2488,52 +2518,58 @@ audio_mmap(struct audio_softc *sc, off_t |
2488 | | | 2518 | |
2489 | return hw->mappage(sc->hw_hdl, cb->s.start, off, prot); | | 2519 | return hw->mappage(sc->hw_hdl, cb->s.start, off, prot); |
2490 | } | | 2520 | } |
2491 | | | 2521 | |
2492 | int | | 2522 | int |
2493 | audiostartr(struct audio_softc *sc) | | 2523 | audiostartr(struct audio_softc *sc) |
2494 | { | | 2524 | { |
2495 | int error; | | 2525 | int error; |
2496 | | | 2526 | |
2497 | DPRINTF(("audiostartr: start=%p used=%d(hi=%d) mmapped=%d\n", | | 2527 | DPRINTF(("audiostartr: start=%p used=%d(hi=%d) mmapped=%d\n", |
2498 | sc->sc_rr.s.start, audio_stream_get_used(&sc->sc_rr.s), | | 2528 | sc->sc_rr.s.start, audio_stream_get_used(&sc->sc_rr.s), |
2499 | sc->sc_rr.usedhigh, sc->sc_rr.mmapped)); | | 2529 | sc->sc_rr.usedhigh, sc->sc_rr.mmapped)); |
2500 | | | 2530 | |
| | | 2531 | if (!audio_can_capture(sc)) |
| | | 2532 | return EINVAL; |
| | | 2533 | |
2501 | if (sc->hw_if->trigger_input) | | 2534 | if (sc->hw_if->trigger_input) |
2502 | error = sc->hw_if->trigger_input(sc->hw_hdl, sc->sc_rr.s.start, | | 2535 | error = sc->hw_if->trigger_input(sc->hw_hdl, sc->sc_rr.s.start, |
2503 | sc->sc_rr.s.end, sc->sc_rr.blksize, | | 2536 | sc->sc_rr.s.end, sc->sc_rr.blksize, |
2504 | audio_rint, (void *)sc, &sc->sc_rr.s.param); | | 2537 | audio_rint, (void *)sc, &sc->sc_rr.s.param); |
2505 | else | | 2538 | else |
2506 | error = sc->hw_if->start_input(sc->hw_hdl, sc->sc_rr.s.start, | | 2539 | error = sc->hw_if->start_input(sc->hw_hdl, sc->sc_rr.s.start, |
2507 | sc->sc_rr.blksize, audio_rint, (void *)sc); | | 2540 | sc->sc_rr.blksize, audio_rint, (void *)sc); |
2508 | if (error) { | | 2541 | if (error) { |
2509 | DPRINTF(("audiostartr failed: %d\n", error)); | | 2542 | DPRINTF(("audiostartr failed: %d\n", error)); |
2510 | return error; | | 2543 | return error; |
2511 | } | | 2544 | } |
2512 | sc->sc_rbus = true; | | 2545 | sc->sc_rbus = true; |
2513 | return 0; | | 2546 | return 0; |
2514 | } | | 2547 | } |
2515 | | | 2548 | |
2516 | int | | 2549 | int |
2517 | audiostartp(struct audio_softc *sc) | | 2550 | audiostartp(struct audio_softc *sc) |
2518 | { | | 2551 | { |
2519 | int error; | | 2552 | int error; |
2520 | int used; | | 2553 | int used; |
2521 | | | 2554 | |
2522 | used = audio_stream_get_used(&sc->sc_pr.s); | | 2555 | used = audio_stream_get_used(&sc->sc_pr.s); |
2523 | DPRINTF(("audiostartp: start=%p used=%d(hi=%d blk=%d) mmapped=%d\n", | | 2556 | DPRINTF(("audiostartp: start=%p used=%d(hi=%d blk=%d) mmapped=%d\n", |
2524 | sc->sc_pr.s.start, used, sc->sc_pr.usedhigh, | | 2557 | sc->sc_pr.s.start, used, sc->sc_pr.usedhigh, |
2525 | sc->sc_pr.blksize, sc->sc_pr.mmapped)); | | 2558 | sc->sc_pr.blksize, sc->sc_pr.mmapped)); |
2526 | | | 2559 | |
| | | 2560 | if (!audio_can_playback(sc)) |
| | | 2561 | return EINVAL; |
| | | 2562 | |
2527 | if (!sc->sc_pr.mmapped && used < sc->sc_pr.blksize) { | | 2563 | if (!sc->sc_pr.mmapped && used < sc->sc_pr.blksize) { |
2528 | wakeup(&sc->sc_wchan); | | 2564 | wakeup(&sc->sc_wchan); |
2529 | DPRINTF(("%s: wakeup and return\n", __func__)); | | 2565 | DPRINTF(("%s: wakeup and return\n", __func__)); |
2530 | return 0; | | 2566 | return 0; |
2531 | } | | 2567 | } |
2532 | | | 2568 | |
2533 | if (sc->hw_if->trigger_output) { | | 2569 | if (sc->hw_if->trigger_output) { |
2534 | DPRINTF(("%s: call trigger_output\n", __func__)); | | 2570 | DPRINTF(("%s: call trigger_output\n", __func__)); |
2535 | error = sc->hw_if->trigger_output(sc->hw_hdl, sc->sc_pr.s.start, | | 2571 | error = sc->hw_if->trigger_output(sc->hw_hdl, sc->sc_pr.s.start, |
2536 | sc->sc_pr.s.end, sc->sc_pr.blksize, | | 2572 | sc->sc_pr.s.end, sc->sc_pr.blksize, |
2537 | audio_pint, (void *)sc, &sc->sc_pr.s.param); | | 2573 | audio_pint, (void *)sc, &sc->sc_pr.s.param); |
2538 | } else { | | 2574 | } else { |
2539 | DPRINTF(("%s: call start_output\n", __func__)); | | 2575 | DPRINTF(("%s: call start_output\n", __func__)); |
| @@ -3321,26 +3357,32 @@ audiosetinfo(struct audio_softc *sc, str | | | @@ -3321,26 +3357,32 @@ audiosetinfo(struct audio_softc *sc, str |
3321 | rp.precision = r->precision; | | 3357 | rp.precision = r->precision; |
3322 | /* we don't have API to specify validbits */ | | 3358 | /* we don't have API to specify validbits */ |
3323 | rp.validbits = r->precision; | | 3359 | rp.validbits = r->precision; |
3324 | nr++; | | 3360 | nr++; |
3325 | } | | 3361 | } |
3326 | if (SPECIFIED(p->channels)) { | | 3362 | if (SPECIFIED(p->channels)) { |
3327 | pp.channels = p->channels; | | 3363 | pp.channels = p->channels; |
3328 | np++; | | 3364 | np++; |
3329 | } | | 3365 | } |
3330 | if (SPECIFIED(r->channels)) { | | 3366 | if (SPECIFIED(r->channels)) { |
3331 | rp.channels = r->channels; | | 3367 | rp.channels = r->channels; |
3332 | nr++; | | 3368 | nr++; |
3333 | } | | 3369 | } |
| | | 3370 | |
| | | 3371 | if (!audio_can_capture(sc)) |
| | | 3372 | nr = 0; |
| | | 3373 | if (!audio_can_playback(sc)) |
| | | 3374 | np = 0; |
| | | 3375 | |
3334 | #ifdef AUDIO_DEBUG | | 3376 | #ifdef AUDIO_DEBUG |
3335 | if (audiodebug && nr > 0) | | 3377 | if (audiodebug && nr > 0) |
3336 | audio_print_params("audiosetinfo() Setting record params:", &rp); | | 3378 | audio_print_params("audiosetinfo() Setting record params:", &rp); |
3337 | if (audiodebug && np > 0) | | 3379 | if (audiodebug && np > 0) |
3338 | audio_print_params("audiosetinfo() Setting play params:", &pp); | | 3380 | audio_print_params("audiosetinfo() Setting play params:", &pp); |
3339 | #endif | | 3381 | #endif |
3340 | if (nr > 0 && (error = audio_check_params(&rp))) | | 3382 | if (nr > 0 && (error = audio_check_params(&rp))) |
3341 | return error; | | 3383 | return error; |
3342 | if (np > 0 && (error = audio_check_params(&pp))) | | 3384 | if (np > 0 && (error = audio_check_params(&pp))) |
3343 | return error; | | 3385 | return error; |
3344 | | | 3386 | |
3345 | oldpblksize = sc->sc_pr.blksize; | | 3387 | oldpblksize = sc->sc_pr.blksize; |
3346 | oldrblksize = sc->sc_rr.blksize; | | 3388 | oldrblksize = sc->sc_rr.blksize; |
| @@ -3372,27 +3414,27 @@ audiosetinfo(struct audio_softc *sc, str | | | @@ -3372,27 +3414,27 @@ audiosetinfo(struct audio_softc *sc, str |
3372 | sc->sc_mode = ai->mode; | | 3414 | sc->sc_mode = ai->mode; |
3373 | if (sc->sc_mode & AUMODE_PLAY_ALL) | | 3415 | if (sc->sc_mode & AUMODE_PLAY_ALL) |
3374 | sc->sc_mode |= AUMODE_PLAY; | | 3416 | sc->sc_mode |= AUMODE_PLAY; |
3375 | if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_full_duplex) | | 3417 | if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_full_duplex) |
3376 | /* Play takes precedence */ | | 3418 | /* Play takes precedence */ |
3377 | sc->sc_mode &= ~AUMODE_RECORD; | | 3419 | sc->sc_mode &= ~AUMODE_RECORD; |
3378 | } | | 3420 | } |
3379 | | | 3421 | |
3380 | oldpus = sc->sc_pustream; | | 3422 | oldpus = sc->sc_pustream; |
3381 | oldrus = sc->sc_rustream; | | 3423 | oldrus = sc->sc_rustream; |
3382 | if (modechange) { | | 3424 | if (modechange) { |
3383 | int indep; | | 3425 | int indep; |
3384 | | | 3426 | |
3385 | indep = hw->get_props(sc->hw_hdl) & AUDIO_PROP_INDEPENDENT; | | 3427 | indep = audio_get_props(sc) & AUDIO_PROP_INDEPENDENT; |
3386 | if (!indep) { | | 3428 | if (!indep) { |
3387 | if (setmode == AUMODE_RECORD) | | 3429 | if (setmode == AUMODE_RECORD) |
3388 | pp = rp; | | 3430 | pp = rp; |
3389 | else if (setmode == AUMODE_PLAY) | | 3431 | else if (setmode == AUMODE_PLAY) |
3390 | rp = pp; | | 3432 | rp = pp; |
3391 | } | | 3433 | } |
3392 | memset(&pfilters, 0, sizeof(pfilters)); | | 3434 | memset(&pfilters, 0, sizeof(pfilters)); |
3393 | memset(&rfilters, 0, sizeof(rfilters)); | | 3435 | memset(&rfilters, 0, sizeof(rfilters)); |
3394 | pfilters.append = stream_filter_list_append; | | 3436 | pfilters.append = stream_filter_list_append; |
3395 | pfilters.prepend = stream_filter_list_prepend; | | 3437 | pfilters.prepend = stream_filter_list_prepend; |
3396 | pfilters.set = stream_filter_list_set; | | 3438 | pfilters.set = stream_filter_list_set; |
3397 | rfilters.append = stream_filter_list_append; | | 3439 | rfilters.append = stream_filter_list_append; |
3398 | rfilters.prepend = stream_filter_list_prepend; | | 3440 | rfilters.prepend = stream_filter_list_prepend; |
| @@ -3706,32 +3748,35 @@ audiogetinfo(struct audio_softc *sc, str | | | @@ -3706,32 +3748,35 @@ audiogetinfo(struct audio_softc *sc, str |
3706 | r->pause = sc->sc_rr.pause; | | 3748 | r->pause = sc->sc_rr.pause; |
3707 | | | 3749 | |
3708 | p->error = sc->sc_pr.drops != 0; | | 3750 | p->error = sc->sc_pr.drops != 0; |
3709 | r->error = sc->sc_rr.drops != 0; | | 3751 | r->error = sc->sc_rr.drops != 0; |
3710 | | | 3752 | |
3711 | p->waiting = r->waiting = 0; /* open never hangs */ | | 3753 | p->waiting = r->waiting = 0; /* open never hangs */ |
3712 | | | 3754 | |
3713 | p->open = (sc->sc_open & AUOPEN_WRITE) != 0; | | 3755 | p->open = (sc->sc_open & AUOPEN_WRITE) != 0; |
3714 | r->open = (sc->sc_open & AUOPEN_READ) != 0; | | 3756 | r->open = (sc->sc_open & AUOPEN_READ) != 0; |
3715 | | | 3757 | |
3716 | p->active = sc->sc_pbus; | | 3758 | p->active = sc->sc_pbus; |
3717 | r->active = sc->sc_rbus; | | 3759 | r->active = sc->sc_rbus; |
3718 | | | 3760 | |
3719 | p->buffer_size = sc->sc_pustream->bufsize; | | 3761 | p->buffer_size = sc->sc_pustream ? sc->sc_pustream->bufsize : 0; |
3720 | r->buffer_size = sc->sc_rustream->bufsize; | | 3762 | r->buffer_size = sc->sc_rustream ? sc->sc_rustream->bufsize : 0; |
3721 | | | 3763 | |
3722 | ai->blocksize = sc->sc_pr.blksize; | | 3764 | ai->blocksize = sc->sc_pr.blksize; |
3723 | ai->hiwat = sc->sc_pr.usedhigh / sc->sc_pr.blksize; | | 3765 | if (sc->sc_pr.blksize > 0) { |
3724 | ai->lowat = sc->sc_pr.usedlow / sc->sc_pr.blksize; | | 3766 | ai->hiwat = sc->sc_pr.usedhigh / sc->sc_pr.blksize; |
| | | 3767 | ai->lowat = sc->sc_pr.usedlow / sc->sc_pr.blksize; |
| | | 3768 | } else |
| | | 3769 | ai->hiwat = ai->lowat = 0; |
3725 | ai->mode = sc->sc_mode; | | 3770 | ai->mode = sc->sc_mode; |
3726 | | | 3771 | |
3727 | return 0; | | 3772 | return 0; |
3728 | } | | 3773 | } |
3729 | | | 3774 | |
3730 | /* | | 3775 | /* |
3731 | * Mixer driver | | 3776 | * Mixer driver |
3732 | */ | | 3777 | */ |
3733 | int | | 3778 | int |
3734 | mixer_open(dev_t dev, struct audio_softc *sc, int flags, | | 3779 | mixer_open(dev_t dev, struct audio_softc *sc, int flags, |
3735 | int ifmt, struct lwp *l) | | 3780 | int ifmt, struct lwp *l) |
3736 | { | | 3781 | { |
3737 | if (sc->hw_if == NULL) | | 3782 | if (sc->hw_if == NULL) |
| @@ -4127,14 +4172,45 @@ audio_volume_toggle(device_t dv) | | | @@ -4127,14 +4172,45 @@ audio_volume_toggle(device_t dv) |
4127 | int s; | | 4172 | int s; |
4128 | | | 4173 | |
4129 | s = splaudio(); | | 4174 | s = splaudio(); |
4130 | au_get_gain(sc, &sc->sc_outports, &gain, &balance); | | 4175 | au_get_gain(sc, &sc->sc_outports, &gain, &balance); |
4131 | if (gain != 0) { | | 4176 | if (gain != 0) { |
4132 | sc->sc_lastgain = gain; | | 4177 | sc->sc_lastgain = gain; |
4133 | newgain = 0; | | 4178 | newgain = 0; |
4134 | } else | | 4179 | } else |
4135 | newgain = sc->sc_lastgain; | | 4180 | newgain = sc->sc_lastgain; |
4136 | au_set_gain(sc, &sc->sc_outports, newgain, balance); | | 4181 | au_set_gain(sc, &sc->sc_outports, newgain, balance); |
4137 | splx(s); | | 4182 | splx(s); |
4138 | } | | 4183 | } |
4139 | | | 4184 | |
| | | 4185 | static int |
| | | 4186 | audio_get_props(struct audio_softc *sc) |
| | | 4187 | { |
| | | 4188 | const struct audio_hw_if *hw; |
| | | 4189 | int props; |
| | | 4190 | |
| | | 4191 | hw = sc->hw_if; |
| | | 4192 | props = hw->get_props(sc->hw_hdl); |
| | | 4193 | |
| | | 4194 | /* |
| | | 4195 | * if neither playback nor capture properties are reported, |
| | | 4196 | * assume both are supported by the device driver |
| | | 4197 | */ |
| | | 4198 | if ((props & (AUDIO_PROP_PLAYBACK|AUDIO_PROP_CAPTURE)) == 0) |
| | | 4199 | props |= (AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE); |
| | | 4200 | |
| | | 4201 | return props; |
| | | 4202 | } |
| | | 4203 | |
| | | 4204 | static bool |
| | | 4205 | audio_can_playback(struct audio_softc *sc) |
| | | 4206 | { |
| | | 4207 | return audio_get_props(sc) & AUDIO_PROP_PLAYBACK ? true : false; |
| | | 4208 | } |
| | | 4209 | |
| | | 4210 | static bool |
| | | 4211 | audio_can_capture(struct audio_softc *sc) |
| | | 4212 | { |
| | | 4213 | return audio_get_props(sc) & AUDIO_PROP_CAPTURE ? true : false; |
| | | 4214 | } |
| | | 4215 | |
4140 | #endif /* NAUDIO > 0 */ | | 4216 | #endif /* NAUDIO > 0 */ |