| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: audio.c,v 1.55 2020/02/23 04:24:56 isaki Exp $ */ | | 1 | /* $NetBSD: audio.c,v 1.56 2020/02/23 07:17:01 isaki Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran. | | 8 | * by Andrew Doran. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -132,27 +132,27 @@ | | | @@ -132,27 +132,27 @@ |
132 | * these may be also called after attach, the thread lock is required. | | 132 | * these may be also called after attach, the thread lock is required. |
133 | * | | 133 | * |
134 | * In addition, there is an additional lock. | | 134 | * In addition, there is an additional lock. |
135 | * | | 135 | * |
136 | * - track->lock. This is an atomic variable and is similar to the | | 136 | * - track->lock. This is an atomic variable and is similar to the |
137 | * "interrupt lock". This is one for each track. If any thread context | | 137 | * "interrupt lock". This is one for each track. If any thread context |
138 | * (and software interrupt context) and hardware interrupt context who | | 138 | * (and software interrupt context) and hardware interrupt context who |
139 | * want to access some variables on this track, they must acquire this | | 139 | * want to access some variables on this track, they must acquire this |
140 | * lock before. It protects track's consistency between hardware | | 140 | * lock before. It protects track's consistency between hardware |
141 | * interrupt context and others. | | 141 | * interrupt context and others. |
142 | */ | | 142 | */ |
143 | | | 143 | |
144 | #include <sys/cdefs.h> | | 144 | #include <sys/cdefs.h> |
145 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.55 2020/02/23 04:24:56 isaki Exp $"); | | 145 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.56 2020/02/23 07:17:01 isaki Exp $"); |
146 | | | 146 | |
147 | #ifdef _KERNEL_OPT | | 147 | #ifdef _KERNEL_OPT |
148 | #include "audio.h" | | 148 | #include "audio.h" |
149 | #include "midi.h" | | 149 | #include "midi.h" |
150 | #endif | | 150 | #endif |
151 | | | 151 | |
152 | #if NAUDIO > 0 | | 152 | #if NAUDIO > 0 |
153 | | | 153 | |
154 | #include <sys/types.h> | | 154 | #include <sys/types.h> |
155 | #include <sys/param.h> | | 155 | #include <sys/param.h> |
156 | #include <sys/atomic.h> | | 156 | #include <sys/atomic.h> |
157 | #include <sys/audioio.h> | | 157 | #include <sys/audioio.h> |
158 | #include <sys/conf.h> | | 158 | #include <sys/conf.h> |
| @@ -489,58 +489,60 @@ static bool audio_suspend(device_t dv, c | | | @@ -489,58 +489,60 @@ static bool audio_suspend(device_t dv, c |
489 | static bool audio_resume(device_t dv, const pmf_qual_t *); | | 489 | static bool audio_resume(device_t dv, const pmf_qual_t *); |
490 | static void audio_volume_down(device_t); | | 490 | static void audio_volume_down(device_t); |
491 | static void audio_volume_up(device_t); | | 491 | static void audio_volume_up(device_t); |
492 | static void audio_volume_toggle(device_t); | | 492 | static void audio_volume_toggle(device_t); |
493 | | | 493 | |
494 | static void audio_mixer_capture(struct audio_softc *); | | 494 | static void audio_mixer_capture(struct audio_softc *); |
495 | static void audio_mixer_restore(struct audio_softc *); | | 495 | static void audio_mixer_restore(struct audio_softc *); |
496 | | | 496 | |
497 | static void audio_softintr_rd(void *); | | 497 | static void audio_softintr_rd(void *); |
498 | static void audio_softintr_wr(void *); | | 498 | static void audio_softintr_wr(void *); |
499 | | | 499 | |
500 | static int audio_enter_exclusive(struct audio_softc *); | | 500 | static int audio_enter_exclusive(struct audio_softc *); |
501 | static void audio_exit_exclusive(struct audio_softc *); | | 501 | static void audio_exit_exclusive(struct audio_softc *); |
| | | 502 | static struct audio_softc *audio_file_enter(audio_file_t *, struct psref *); |
| | | 503 | static void audio_file_exit(struct audio_softc *, struct psref *); |
502 | static int audio_track_waitio(struct audio_softc *, audio_track_t *); | | 504 | static int audio_track_waitio(struct audio_softc *, audio_track_t *); |
503 | | | 505 | |
504 | static int audioclose(struct file *); | | 506 | static int audioclose(struct file *); |
505 | static int audioread(struct file *, off_t *, struct uio *, kauth_cred_t, int); | | 507 | static int audioread(struct file *, off_t *, struct uio *, kauth_cred_t, int); |
506 | static int audiowrite(struct file *, off_t *, struct uio *, kauth_cred_t, int); | | 508 | static int audiowrite(struct file *, off_t *, struct uio *, kauth_cred_t, int); |
507 | static int audioioctl(struct file *, u_long, void *); | | 509 | static int audioioctl(struct file *, u_long, void *); |
508 | static int audiopoll(struct file *, int); | | 510 | static int audiopoll(struct file *, int); |
509 | static int audiokqfilter(struct file *, struct knote *); | | 511 | static int audiokqfilter(struct file *, struct knote *); |
510 | static int audiommap(struct file *, off_t *, size_t, int, int *, int *, | | 512 | static int audiommap(struct file *, off_t *, size_t, int, int *, int *, |
511 | struct uvm_object **, int *); | | 513 | struct uvm_object **, int *); |
512 | static int audiostat(struct file *, struct stat *); | | 514 | static int audiostat(struct file *, struct stat *); |
513 | | | 515 | |
514 | static void filt_audiowrite_detach(struct knote *); | | 516 | static void filt_audiowrite_detach(struct knote *); |
515 | static int filt_audiowrite_event(struct knote *, long); | | 517 | static int filt_audiowrite_event(struct knote *, long); |
516 | static void filt_audioread_detach(struct knote *); | | 518 | static void filt_audioread_detach(struct knote *); |
517 | static int filt_audioread_event(struct knote *, long); | | 519 | static int filt_audioread_event(struct knote *, long); |
518 | | | 520 | |
519 | static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *, | | 521 | static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *, |
520 | audio_file_t **); | | 522 | audio_file_t **); |
521 | static int audio_close(struct audio_softc *, audio_file_t *); | | 523 | static int audio_close(struct audio_softc *, audio_file_t *); |
| | | 524 | static int audio_unlink(struct audio_softc *, audio_file_t *); |
522 | static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *); | | 525 | static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *); |
523 | static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *); | | 526 | static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *); |
524 | static void audio_file_clear(struct audio_softc *, audio_file_t *); | | 527 | static void audio_file_clear(struct audio_softc *, audio_file_t *); |
525 | static int audio_ioctl(dev_t, struct audio_softc *, u_long, void *, int, | | 528 | static int audio_ioctl(dev_t, struct audio_softc *, u_long, void *, int, |
526 | struct lwp *, audio_file_t *); | | 529 | struct lwp *, audio_file_t *); |
527 | static int audio_poll(struct audio_softc *, int, struct lwp *, audio_file_t *); | | 530 | static int audio_poll(struct audio_softc *, int, struct lwp *, audio_file_t *); |
528 | static int audio_kqfilter(struct audio_softc *, audio_file_t *, struct knote *); | | 531 | static int audio_kqfilter(struct audio_softc *, audio_file_t *, struct knote *); |
529 | static int audio_mmap(struct audio_softc *, off_t *, size_t, int, int *, int *, | | 532 | static int audio_mmap(struct audio_softc *, off_t *, size_t, int, int *, int *, |
530 | struct uvm_object **, int *, audio_file_t *); | | 533 | struct uvm_object **, int *, audio_file_t *); |
531 | | | 534 | |
532 | static int audioctl_open(dev_t, struct audio_softc *, int, int, struct lwp *); | | 535 | static int audioctl_open(dev_t, struct audio_softc *, int, int, struct lwp *); |
533 | static int audioctl_close(struct audio_softc *, audio_file_t *); | | | |
534 | | | 536 | |
535 | static void audio_pintr(void *); | | 537 | static void audio_pintr(void *); |
536 | static void audio_rintr(void *); | | 538 | static void audio_rintr(void *); |
537 | | | 539 | |
538 | static int audio_query_devinfo(struct audio_softc *, mixer_devinfo_t *); | | 540 | static int audio_query_devinfo(struct audio_softc *, mixer_devinfo_t *); |
539 | | | 541 | |
540 | static __inline int audio_track_readablebytes(const audio_track_t *); | | 542 | static __inline int audio_track_readablebytes(const audio_track_t *); |
541 | static int audio_file_setinfo(struct audio_softc *, audio_file_t *, | | 543 | static int audio_file_setinfo(struct audio_softc *, audio_file_t *, |
542 | const struct audio_info *); | | 544 | const struct audio_info *); |
543 | static int audio_track_setinfo_check(audio_format2_t *, | | 545 | static int audio_track_setinfo_check(audio_format2_t *, |
544 | const struct audio_prinfo *, const audio_format2_t *); | | 546 | const struct audio_prinfo *, const audio_format2_t *); |
545 | static void audio_track_setinfo_water(audio_track_t *, | | 547 | static void audio_track_setinfo_water(audio_track_t *, |
546 | const struct audio_info *); | | 548 | const struct audio_info *); |
| @@ -800,26 +802,28 @@ static const audio_encoding_t audio_enco | | | @@ -800,26 +802,28 @@ static const audio_encoding_t audio_enco |
800 | static const struct portname itable[] = { | | 802 | static const struct portname itable[] = { |
801 | { AudioNmicrophone, AUDIO_MICROPHONE }, | | 803 | { AudioNmicrophone, AUDIO_MICROPHONE }, |
802 | { AudioNline, AUDIO_LINE_IN }, | | 804 | { AudioNline, AUDIO_LINE_IN }, |
803 | { AudioNcd, AUDIO_CD }, | | 805 | { AudioNcd, AUDIO_CD }, |
804 | { 0, 0 } | | 806 | { 0, 0 } |
805 | }; | | 807 | }; |
806 | static const struct portname otable[] = { | | 808 | static const struct portname otable[] = { |
807 | { AudioNspeaker, AUDIO_SPEAKER }, | | 809 | { AudioNspeaker, AUDIO_SPEAKER }, |
808 | { AudioNheadphone, AUDIO_HEADPHONE }, | | 810 | { AudioNheadphone, AUDIO_HEADPHONE }, |
809 | { AudioNline, AUDIO_LINE_OUT }, | | 811 | { AudioNline, AUDIO_LINE_OUT }, |
810 | { 0, 0 } | | 812 | { 0, 0 } |
811 | }; | | 813 | }; |
812 | | | 814 | |
| | | 815 | static struct psref_class *audio_psref_class __read_mostly; |
| | | 816 | |
813 | CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc), | | 817 | CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc), |
814 | audiomatch, audioattach, audiodetach, audioactivate, audiorescan, | | 818 | audiomatch, audioattach, audiodetach, audioactivate, audiorescan, |
815 | audiochilddet, DVF_DETACH_SHUTDOWN); | | 819 | audiochilddet, DVF_DETACH_SHUTDOWN); |
816 | | | 820 | |
817 | static int | | 821 | static int |
818 | audiomatch(device_t parent, cfdata_t match, void *aux) | | 822 | audiomatch(device_t parent, cfdata_t match, void *aux) |
819 | { | | 823 | { |
820 | struct audio_attach_args *sa; | | 824 | struct audio_attach_args *sa; |
821 | | | 825 | |
822 | sa = aux; | | 826 | sa = aux; |
823 | DPRINTF(1, "%s: type=%d sa=%p hw=%p\n", | | 827 | DPRINTF(1, "%s: type=%d sa=%p hw=%p\n", |
824 | __func__, sa->type, sa, sa->hwif); | | 828 | __func__, sa->type, sa, sa->hwif); |
825 | return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0; | | 829 | return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0; |
| @@ -988,26 +992,29 @@ audioattach(device_t parent, device_t se | | | @@ -988,26 +992,29 @@ audioattach(device_t parent, device_t se |
988 | | | 992 | |
989 | /* | | 993 | /* |
990 | * Init track mixers. If at least one direction is available on | | 994 | * Init track mixers. If at least one direction is available on |
991 | * attach time, we assume a success. | | 995 | * attach time, we assume a success. |
992 | */ | | 996 | */ |
993 | error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); | | 997 | error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); |
994 | mutex_exit(sc->sc_lock); | | 998 | mutex_exit(sc->sc_lock); |
995 | if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) { | | 999 | if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) { |
996 | aprint_error_dev(self, "audio_mixers_init failed, " | | 1000 | aprint_error_dev(self, "audio_mixers_init failed, " |
997 | "error = %d\n", error); | | 1001 | "error = %d\n", error); |
998 | goto bad; | | 1002 | goto bad; |
999 | } | | 1003 | } |
1000 | | | 1004 | |
| | | 1005 | sc->sc_psz = pserialize_create(); |
| | | 1006 | psref_target_init(&sc->sc_psref, audio_psref_class); |
| | | 1007 | |
1001 | selinit(&sc->sc_wsel); | | 1008 | selinit(&sc->sc_wsel); |
1002 | selinit(&sc->sc_rsel); | | 1009 | selinit(&sc->sc_rsel); |
1003 | | | 1010 | |
1004 | /* Initial parameter of /dev/sound */ | | 1011 | /* Initial parameter of /dev/sound */ |
1005 | sc->sc_sound_pparams = params_to_format2(&audio_default); | | 1012 | sc->sc_sound_pparams = params_to_format2(&audio_default); |
1006 | sc->sc_sound_rparams = params_to_format2(&audio_default); | | 1013 | sc->sc_sound_rparams = params_to_format2(&audio_default); |
1007 | sc->sc_sound_ppause = false; | | 1014 | sc->sc_sound_ppause = false; |
1008 | sc->sc_sound_rpause = false; | | 1015 | sc->sc_sound_rpause = false; |
1009 | | | 1016 | |
1010 | /* XXX TODO: consider about sc_ai */ | | 1017 | /* XXX TODO: consider about sc_ai */ |
1011 | | | 1018 | |
1012 | mixer_init(sc); | | 1019 | mixer_init(sc); |
1013 | TRACE(2, "inputs ports=0x%x, input master=%d, " | | 1020 | TRACE(2, "inputs ports=0x%x, input master=%d, " |
| @@ -1245,65 +1252,81 @@ audioactivate(device_t self, enum devact | | | @@ -1245,65 +1252,81 @@ audioactivate(device_t self, enum devact |
1245 | sc->sc_dying = true; | | 1252 | sc->sc_dying = true; |
1246 | cv_broadcast(&sc->sc_exlockcv); | | 1253 | cv_broadcast(&sc->sc_exlockcv); |
1247 | mutex_exit(sc->sc_lock); | | 1254 | mutex_exit(sc->sc_lock); |
1248 | return 0; | | 1255 | return 0; |
1249 | default: | | 1256 | default: |
1250 | return EOPNOTSUPP; | | 1257 | return EOPNOTSUPP; |
1251 | } | | 1258 | } |
1252 | } | | 1259 | } |
1253 | | | 1260 | |
1254 | static int | | 1261 | static int |
1255 | audiodetach(device_t self, int flags) | | 1262 | audiodetach(device_t self, int flags) |
1256 | { | | 1263 | { |
1257 | struct audio_softc *sc; | | 1264 | struct audio_softc *sc; |
1258 | int maj, mn; | | 1265 | struct audio_file *file; |
1259 | int error; | | 1266 | int error; |
1260 | | | 1267 | |
1261 | sc = device_private(self); | | 1268 | sc = device_private(self); |
1262 | TRACE(2, "flags=%d", flags); | | 1269 | TRACE(2, "flags=%d", flags); |
1263 | | | 1270 | |
1264 | /* device is not initialized */ | | 1271 | /* device is not initialized */ |
1265 | if (sc->hw_if == NULL) | | 1272 | if (sc->hw_if == NULL) |
1266 | return 0; | | 1273 | return 0; |
1267 | | | 1274 | |
1268 | /* Start draining existing accessors of the device. */ | | 1275 | /* Start draining existing accessors of the device. */ |
1269 | error = config_detach_children(self, flags); | | 1276 | error = config_detach_children(self, flags); |
1270 | if (error) | | 1277 | if (error) |
1271 | return error; | | 1278 | return error; |
1272 | | | 1279 | |
| | | 1280 | /* delete sysctl nodes */ |
| | | 1281 | sysctl_teardown(&sc->sc_log); |
| | | 1282 | |
1273 | mutex_enter(sc->sc_lock); | | 1283 | mutex_enter(sc->sc_lock); |
1274 | sc->sc_dying = true; | | 1284 | sc->sc_dying = true; |
1275 | cv_broadcast(&sc->sc_exlockcv); | | 1285 | cv_broadcast(&sc->sc_exlockcv); |
1276 | if (sc->sc_pmixer) | | 1286 | if (sc->sc_pmixer) |
1277 | cv_broadcast(&sc->sc_pmixer->outcv); | | 1287 | cv_broadcast(&sc->sc_pmixer->outcv); |
1278 | if (sc->sc_rmixer) | | 1288 | if (sc->sc_rmixer) |
1279 | cv_broadcast(&sc->sc_rmixer->outcv); | | 1289 | cv_broadcast(&sc->sc_rmixer->outcv); |
1280 | mutex_exit(sc->sc_lock); | | | |
1281 | | | 1290 | |
1282 | /* delete sysctl nodes */ | | 1291 | /* Prevent new users */ |
1283 | sysctl_teardown(&sc->sc_log); | | 1292 | SLIST_FOREACH(file, &sc->sc_files, entry) { |
| | | 1293 | atomic_store_relaxed(&file->dying, true); |
| | | 1294 | } |
| | | 1295 | |
| | | 1296 | /* |
| | | 1297 | * Wait for existing users to drain. |
| | | 1298 | * - pserialize_perform waits for all pserialize_read sections on |
| | | 1299 | * all CPUs; after this, no more new psref_acquire can happen. |
| | | 1300 | * - psref_target_destroy waits for all extant acquired psrefs to |
| | | 1301 | * be psref_released. |
| | | 1302 | */ |
| | | 1303 | pserialize_perform(sc->sc_psz); |
| | | 1304 | mutex_exit(sc->sc_lock); |
| | | 1305 | psref_target_destroy(&sc->sc_psref, audio_psref_class); |
1284 | | | 1306 | |
1285 | /* locate the major number */ | | 1307 | /* |
1286 | maj = cdevsw_lookup_major(&audio_cdevsw); | | 1308 | * We are now guaranteed that there are no calls to audio fileops |
| | | 1309 | * that hold sc, and any new calls with files that were for sc will |
| | | 1310 | * fail. Thus, we now have exclusive access to the softc. |
| | | 1311 | */ |
1287 | | | 1312 | |
1288 | /* | | 1313 | /* |
1289 | * Nuke the vnodes for any open instances (calls close). | | 1314 | * Nuke all open instances. |
1290 | * Will wait until any activity on the device nodes has ceased. | | 1315 | * Here, we no longer need any locks to traverse sc_files. |
1291 | */ | | 1316 | */ |
1292 | mn = device_unit(self); | | 1317 | while ((file = SLIST_FIRST(&sc->sc_files)) != NULL) { |
1293 | vdevgone(maj, mn | SOUND_DEVICE, mn | SOUND_DEVICE, VCHR); | | 1318 | audio_unlink(sc, file); |
1294 | vdevgone(maj, mn | AUDIO_DEVICE, mn | AUDIO_DEVICE, VCHR); | | 1319 | } |
1295 | vdevgone(maj, mn | AUDIOCTL_DEVICE, mn | AUDIOCTL_DEVICE, VCHR); | | | |
1296 | vdevgone(maj, mn | MIXER_DEVICE, mn | MIXER_DEVICE, VCHR); | | | |
1297 | | | 1320 | |
1298 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_DOWN, | | 1321 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_DOWN, |
1299 | audio_volume_down, true); | | 1322 | audio_volume_down, true); |
1300 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_UP, | | 1323 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_UP, |
1301 | audio_volume_up, true); | | 1324 | audio_volume_up, true); |
1302 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_TOGGLE, | | 1325 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_TOGGLE, |
1303 | audio_volume_toggle, true); | | 1326 | audio_volume_toggle, true); |
1304 | | | 1327 | |
1305 | #ifdef AUDIO_PM_IDLE | | 1328 | #ifdef AUDIO_PM_IDLE |
1306 | callout_halt(&sc->sc_idle_counter, sc->sc_lock); | | 1329 | callout_halt(&sc->sc_idle_counter, sc->sc_lock); |
1307 | | | 1330 | |
1308 | device_active_deregister(self, audio_activity); | | 1331 | device_active_deregister(self, audio_activity); |
1309 | #endif | | 1332 | #endif |
| @@ -1430,26 +1453,68 @@ static void | | | @@ -1430,26 +1453,68 @@ static void |
1430 | audio_exit_exclusive(struct audio_softc *sc) | | 1453 | audio_exit_exclusive(struct audio_softc *sc) |
1431 | { | | 1454 | { |
1432 | | | 1455 | |
1433 | KASSERT(mutex_owned(sc->sc_lock)); | | 1456 | KASSERT(mutex_owned(sc->sc_lock)); |
1434 | KASSERT(sc->sc_exlock); | | 1457 | KASSERT(sc->sc_exlock); |
1435 | | | 1458 | |
1436 | /* Leave critical section */ | | 1459 | /* Leave critical section */ |
1437 | sc->sc_exlock = 0; | | 1460 | sc->sc_exlock = 0; |
1438 | cv_broadcast(&sc->sc_exlockcv); | | 1461 | cv_broadcast(&sc->sc_exlockcv); |
1439 | mutex_exit(sc->sc_lock); | | 1462 | mutex_exit(sc->sc_lock); |
1440 | } | | 1463 | } |
1441 | | | 1464 | |
1442 | /* | | 1465 | /* |
| | | 1466 | * Acquire sc from file, and increment the psref count. |
| | | 1467 | * If successful, returns sc. Otherwise returns NULL. |
| | | 1468 | */ |
| | | 1469 | struct audio_softc * |
| | | 1470 | audio_file_enter(audio_file_t *file, struct psref *refp) |
| | | 1471 | { |
| | | 1472 | int s; |
| | | 1473 | bool dying; |
| | | 1474 | |
| | | 1475 | /* psref(9) forbids to migrate CPUs */ |
| | | 1476 | curlwp_bind(); |
| | | 1477 | |
| | | 1478 | /* Block audiodetach while we acquire a reference */ |
| | | 1479 | s = pserialize_read_enter(); |
| | | 1480 | |
| | | 1481 | /* If close or audiodetach already ran, tough -- no more audio */ |
| | | 1482 | dying = atomic_load_relaxed(&file->dying); |
| | | 1483 | if (dying) { |
| | | 1484 | pserialize_read_exit(s); |
| | | 1485 | return NULL; |
| | | 1486 | } |
| | | 1487 | |
| | | 1488 | /* Acquire a reference */ |
| | | 1489 | psref_acquire(refp, &file->sc->sc_psref, audio_psref_class); |
| | | 1490 | |
| | | 1491 | /* Now sc won't go away until we drop the reference count */ |
| | | 1492 | pserialize_read_exit(s); |
| | | 1493 | |
| | | 1494 | return file->sc; |
| | | 1495 | } |
| | | 1496 | |
| | | 1497 | /* |
| | | 1498 | * Decrement the psref count. |
| | | 1499 | */ |
| | | 1500 | void |
| | | 1501 | audio_file_exit(struct audio_softc *sc, struct psref *refp) |
| | | 1502 | { |
| | | 1503 | |
| | | 1504 | psref_release(refp, &sc->sc_psref, audio_psref_class); |
| | | 1505 | } |
| | | 1506 | |
| | | 1507 | /* |
1443 | * Wait for I/O to complete, releasing sc_lock. | | 1508 | * Wait for I/O to complete, releasing sc_lock. |
1444 | * Must be called with sc_lock held. | | 1509 | * Must be called with sc_lock held. |
1445 | */ | | 1510 | */ |
1446 | static int | | 1511 | static int |
1447 | audio_track_waitio(struct audio_softc *sc, audio_track_t *track) | | 1512 | audio_track_waitio(struct audio_softc *sc, audio_track_t *track) |
1448 | { | | 1513 | { |
1449 | int error; | | 1514 | int error; |
1450 | | | 1515 | |
1451 | KASSERT(track); | | 1516 | KASSERT(track); |
1452 | KASSERT(mutex_owned(sc->sc_lock)); | | 1517 | KASSERT(mutex_owned(sc->sc_lock)); |
1453 | | | 1518 | |
1454 | /* Wait for pending I/O to complete. */ | | 1519 | /* Wait for pending I/O to complete. */ |
1455 | error = cv_timedwait_sig(&track->mixer->outcv, sc->sc_lock, | | 1520 | error = cv_timedwait_sig(&track->mixer->outcv, sc->sc_lock, |
| @@ -1530,274 +1595,329 @@ audioopen(dev_t dev, int flags, int ifmt | | | @@ -1530,274 +1595,329 @@ audioopen(dev_t dev, int flags, int ifmt |
1530 | default: | | 1595 | default: |
1531 | error = ENXIO; | | 1596 | error = ENXIO; |
1532 | break; | | 1597 | break; |
1533 | } | | 1598 | } |
1534 | audio_exit_exclusive(sc); | | 1599 | audio_exit_exclusive(sc); |
1535 | | | 1600 | |
1536 | return error; | | 1601 | return error; |
1537 | } | | 1602 | } |
1538 | | | 1603 | |
1539 | static int | | 1604 | static int |
1540 | audioclose(struct file *fp) | | 1605 | audioclose(struct file *fp) |
1541 | { | | 1606 | { |
1542 | struct audio_softc *sc; | | 1607 | struct audio_softc *sc; |
| | | 1608 | struct psref sc_ref; |
1543 | audio_file_t *file; | | 1609 | audio_file_t *file; |
1544 | int error; | | 1610 | int error; |
1545 | dev_t dev; | | 1611 | dev_t dev; |
1546 | | | 1612 | |
1547 | KASSERT(fp->f_audioctx); | | 1613 | KASSERT(fp->f_audioctx); |
1548 | file = fp->f_audioctx; | | 1614 | file = fp->f_audioctx; |
1549 | sc = file->sc; | | | |
1550 | dev = file->dev; | | 1615 | dev = file->dev; |
| | | 1616 | error = 0; |
1551 | | | 1617 | |
1552 | /* audio_{enter,exit}_exclusive() is called by lower audio_close() */ | | 1618 | /* |
| | | 1619 | * audioclose() must |
| | | 1620 | * - unplug track from the trackmixer (and unplug anything from softc), |
| | | 1621 | * if sc exists. |
| | | 1622 | * - free all memory objects, regardless of sc. |
| | | 1623 | */ |
1553 | | | 1624 | |
1554 | device_active(sc->sc_dev, DVA_SYSTEM); | | 1625 | sc = audio_file_enter(file, &sc_ref); |
1555 | switch (AUDIODEV(dev)) { | | 1626 | if (sc) { |
1556 | case SOUND_DEVICE: | | 1627 | switch (AUDIODEV(dev)) { |
1557 | case AUDIO_DEVICE: | | 1628 | case SOUND_DEVICE: |
1558 | error = audio_close(sc, file); | | 1629 | case AUDIO_DEVICE: |
1559 | break; | | 1630 | error = audio_close(sc, file); |
1560 | case AUDIOCTL_DEVICE: | | 1631 | break; |
1561 | error = audioctl_close(sc, file); | | 1632 | case AUDIOCTL_DEVICE: |
1562 | break; | | 1633 | error = 0; |
1563 | case MIXER_DEVICE: | | 1634 | break; |
1564 | error = mixer_close(sc, file); | | 1635 | case MIXER_DEVICE: |
1565 | break; | | 1636 | error = mixer_close(sc, file); |
1566 | default: | | 1637 | break; |
1567 | error = ENXIO; | | 1638 | default: |
1568 | break; | | 1639 | error = ENXIO; |
| | | 1640 | break; |
| | | 1641 | } |
| | | 1642 | |
| | | 1643 | audio_file_exit(sc, &sc_ref); |
1569 | } | | 1644 | } |
1570 | /* f_audioctx has already been freed in lower *_close() */ | | 1645 | |
| | | 1646 | /* Free memory objects anyway */ |
| | | 1647 | TRACEF(2, file, "free memory"); |
| | | 1648 | if (file->ptrack) |
| | | 1649 | audio_track_destroy(file->ptrack); |
| | | 1650 | if (file->rtrack) |
| | | 1651 | audio_track_destroy(file->rtrack); |
| | | 1652 | kmem_free(file, sizeof(*file)); |
1571 | fp->f_audioctx = NULL; | | 1653 | fp->f_audioctx = NULL; |
1572 | | | 1654 | |
1573 | return error; | | 1655 | return error; |
1574 | } | | 1656 | } |
1575 | | | 1657 | |
1576 | static int | | 1658 | static int |
1577 | audioread(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, | | 1659 | audioread(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, |
1578 | int ioflag) | | 1660 | int ioflag) |
1579 | { | | 1661 | { |
1580 | struct audio_softc *sc; | | 1662 | struct audio_softc *sc; |
| | | 1663 | struct psref sc_ref; |
1581 | audio_file_t *file; | | 1664 | audio_file_t *file; |
1582 | int error; | | 1665 | int error; |
1583 | dev_t dev; | | 1666 | dev_t dev; |
1584 | | | 1667 | |
1585 | KASSERT(fp->f_audioctx); | | 1668 | KASSERT(fp->f_audioctx); |
1586 | file = fp->f_audioctx; | | 1669 | file = fp->f_audioctx; |
1587 | sc = file->sc; | | | |
1588 | dev = file->dev; | | 1670 | dev = file->dev; |
1589 | | | 1671 | |
| | | 1672 | sc = audio_file_enter(file, &sc_ref); |
| | | 1673 | if (sc == NULL) |
| | | 1674 | return EIO; |
| | | 1675 | |
1590 | if (fp->f_flag & O_NONBLOCK) | | 1676 | if (fp->f_flag & O_NONBLOCK) |
1591 | ioflag |= IO_NDELAY; | | 1677 | ioflag |= IO_NDELAY; |
1592 | | | 1678 | |
1593 | switch (AUDIODEV(dev)) { | | 1679 | switch (AUDIODEV(dev)) { |
1594 | case SOUND_DEVICE: | | 1680 | case SOUND_DEVICE: |
1595 | case AUDIO_DEVICE: | | 1681 | case AUDIO_DEVICE: |
1596 | error = audio_read(sc, uio, ioflag, file); | | 1682 | error = audio_read(sc, uio, ioflag, file); |
1597 | break; | | 1683 | break; |
1598 | case AUDIOCTL_DEVICE: | | 1684 | case AUDIOCTL_DEVICE: |
1599 | case MIXER_DEVICE: | | 1685 | case MIXER_DEVICE: |
1600 | error = ENODEV; | | 1686 | error = ENODEV; |
1601 | break; | | 1687 | break; |
1602 | default: | | 1688 | default: |
1603 | error = ENXIO; | | 1689 | error = ENXIO; |
1604 | break; | | 1690 | break; |
1605 | } | | 1691 | } |
1606 | | | 1692 | |
| | | 1693 | audio_file_exit(sc, &sc_ref); |
1607 | return error; | | 1694 | return error; |
1608 | } | | 1695 | } |
1609 | | | 1696 | |
1610 | static int | | 1697 | static int |
1611 | audiowrite(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, | | 1698 | audiowrite(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, |
1612 | int ioflag) | | 1699 | int ioflag) |
1613 | { | | 1700 | { |
1614 | struct audio_softc *sc; | | 1701 | struct audio_softc *sc; |
| | | 1702 | struct psref sc_ref; |
1615 | audio_file_t *file; | | 1703 | audio_file_t *file; |
1616 | int error; | | 1704 | int error; |
1617 | dev_t dev; | | 1705 | dev_t dev; |
1618 | | | 1706 | |
1619 | KASSERT(fp->f_audioctx); | | 1707 | KASSERT(fp->f_audioctx); |
1620 | file = fp->f_audioctx; | | 1708 | file = fp->f_audioctx; |
1621 | sc = file->sc; | | | |
1622 | dev = file->dev; | | 1709 | dev = file->dev; |
1623 | | | 1710 | |
| | | 1711 | sc = audio_file_enter(file, &sc_ref); |
| | | 1712 | if (sc == NULL) |
| | | 1713 | return EIO; |
| | | 1714 | |
1624 | if (fp->f_flag & O_NONBLOCK) | | 1715 | if (fp->f_flag & O_NONBLOCK) |
1625 | ioflag |= IO_NDELAY; | | 1716 | ioflag |= IO_NDELAY; |
1626 | | | 1717 | |
1627 | switch (AUDIODEV(dev)) { | | 1718 | switch (AUDIODEV(dev)) { |
1628 | case SOUND_DEVICE: | | 1719 | case SOUND_DEVICE: |
1629 | case AUDIO_DEVICE: | | 1720 | case AUDIO_DEVICE: |
1630 | error = audio_write(sc, uio, ioflag, file); | | 1721 | error = audio_write(sc, uio, ioflag, file); |
1631 | break; | | 1722 | break; |
1632 | case AUDIOCTL_DEVICE: | | 1723 | case AUDIOCTL_DEVICE: |
1633 | case MIXER_DEVICE: | | 1724 | case MIXER_DEVICE: |
1634 | error = ENODEV; | | 1725 | error = ENODEV; |
1635 | break; | | 1726 | break; |
1636 | default: | | 1727 | default: |
1637 | error = ENXIO; | | 1728 | error = ENXIO; |
1638 | break; | | 1729 | break; |
1639 | } | | 1730 | } |
1640 | | | 1731 | |
| | | 1732 | audio_file_exit(sc, &sc_ref); |
1641 | return error; | | 1733 | return error; |
1642 | } | | 1734 | } |
1643 | | | 1735 | |
1644 | static int | | 1736 | static int |
1645 | audioioctl(struct file *fp, u_long cmd, void *addr) | | 1737 | audioioctl(struct file *fp, u_long cmd, void *addr) |
1646 | { | | 1738 | { |
1647 | struct audio_softc *sc; | | 1739 | struct audio_softc *sc; |
| | | 1740 | struct psref sc_ref; |
1648 | audio_file_t *file; | | 1741 | audio_file_t *file; |
1649 | struct lwp *l = curlwp; | | 1742 | struct lwp *l = curlwp; |
1650 | int error; | | 1743 | int error; |
1651 | dev_t dev; | | 1744 | dev_t dev; |
1652 | | | 1745 | |
1653 | KASSERT(fp->f_audioctx); | | 1746 | KASSERT(fp->f_audioctx); |
1654 | file = fp->f_audioctx; | | 1747 | file = fp->f_audioctx; |
1655 | sc = file->sc; | | | |
1656 | dev = file->dev; | | 1748 | dev = file->dev; |
1657 | | | 1749 | |
| | | 1750 | sc = audio_file_enter(file, &sc_ref); |
| | | 1751 | if (sc == NULL) |
| | | 1752 | return EIO; |
| | | 1753 | |
1658 | switch (AUDIODEV(dev)) { | | 1754 | switch (AUDIODEV(dev)) { |
1659 | case SOUND_DEVICE: | | 1755 | case SOUND_DEVICE: |
1660 | case AUDIO_DEVICE: | | 1756 | case AUDIO_DEVICE: |
1661 | case AUDIOCTL_DEVICE: | | 1757 | case AUDIOCTL_DEVICE: |
1662 | mutex_enter(sc->sc_lock); | | 1758 | mutex_enter(sc->sc_lock); |
1663 | device_active(sc->sc_dev, DVA_SYSTEM); | | 1759 | device_active(sc->sc_dev, DVA_SYSTEM); |
1664 | mutex_exit(sc->sc_lock); | | 1760 | mutex_exit(sc->sc_lock); |
1665 | if (IOCGROUP(cmd) == IOCGROUP(AUDIO_MIXER_READ)) | | 1761 | if (IOCGROUP(cmd) == IOCGROUP(AUDIO_MIXER_READ)) |
1666 | error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l); | | 1762 | error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l); |
1667 | else | | 1763 | else |
1668 | error = audio_ioctl(dev, sc, cmd, addr, fp->f_flag, l, | | 1764 | error = audio_ioctl(dev, sc, cmd, addr, fp->f_flag, l, |
1669 | file); | | 1765 | file); |
1670 | break; | | 1766 | break; |
1671 | case MIXER_DEVICE: | | 1767 | case MIXER_DEVICE: |
1672 | error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l); | | 1768 | error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l); |
1673 | break; | | 1769 | break; |
1674 | default: | | 1770 | default: |
1675 | error = ENXIO; | | 1771 | error = ENXIO; |
1676 | break; | | 1772 | break; |
1677 | } | | 1773 | } |
1678 | | | 1774 | |
| | | 1775 | audio_file_exit(sc, &sc_ref); |
1679 | return error; | | 1776 | return error; |
1680 | } | | 1777 | } |
1681 | | | 1778 | |
1682 | static int | | 1779 | static int |
1683 | audiostat(struct file *fp, struct stat *st) | | 1780 | audiostat(struct file *fp, struct stat *st) |
1684 | { | | 1781 | { |
| | | 1782 | struct audio_softc *sc; |
| | | 1783 | struct psref sc_ref; |
1685 | audio_file_t *file; | | 1784 | audio_file_t *file; |
1686 | | | 1785 | |
1687 | KASSERT(fp->f_audioctx); | | 1786 | KASSERT(fp->f_audioctx); |
1688 | file = fp->f_audioctx; | | 1787 | file = fp->f_audioctx; |
1689 | | | 1788 | |
| | | 1789 | sc = audio_file_enter(file, &sc_ref); |
| | | 1790 | if (sc == NULL) |
| | | 1791 | return EIO; |
| | | 1792 | |
1690 | memset(st, 0, sizeof(*st)); | | 1793 | memset(st, 0, sizeof(*st)); |
1691 | | | 1794 | |
1692 | st->st_dev = file->dev; | | 1795 | st->st_dev = file->dev; |
1693 | st->st_uid = kauth_cred_geteuid(fp->f_cred); | | 1796 | st->st_uid = kauth_cred_geteuid(fp->f_cred); |
1694 | st->st_gid = kauth_cred_getegid(fp->f_cred); | | 1797 | st->st_gid = kauth_cred_getegid(fp->f_cred); |
1695 | st->st_mode = S_IFCHR; | | 1798 | st->st_mode = S_IFCHR; |
| | | 1799 | |
| | | 1800 | audio_file_exit(sc, &sc_ref); |
1696 | return 0; | | 1801 | return 0; |
1697 | } | | 1802 | } |
1698 | | | 1803 | |
1699 | static int | | 1804 | static int |
1700 | audiopoll(struct file *fp, int events) | | 1805 | audiopoll(struct file *fp, int events) |
1701 | { | | 1806 | { |
1702 | struct audio_softc *sc; | | 1807 | struct audio_softc *sc; |
| | | 1808 | struct psref sc_ref; |
1703 | audio_file_t *file; | | 1809 | audio_file_t *file; |
1704 | struct lwp *l = curlwp; | | 1810 | struct lwp *l = curlwp; |
1705 | int revents; | | 1811 | int revents; |
1706 | dev_t dev; | | 1812 | dev_t dev; |
1707 | | | 1813 | |
1708 | KASSERT(fp->f_audioctx); | | 1814 | KASSERT(fp->f_audioctx); |
1709 | file = fp->f_audioctx; | | 1815 | file = fp->f_audioctx; |
1710 | sc = file->sc; | | | |
1711 | dev = file->dev; | | 1816 | dev = file->dev; |
1712 | | | 1817 | |
| | | 1818 | sc = audio_file_enter(file, &sc_ref); |
| | | 1819 | if (sc == NULL) |
| | | 1820 | return EIO; |
| | | 1821 | |
1713 | switch (AUDIODEV(dev)) { | | 1822 | switch (AUDIODEV(dev)) { |
1714 | case SOUND_DEVICE: | | 1823 | case SOUND_DEVICE: |
1715 | case AUDIO_DEVICE: | | 1824 | case AUDIO_DEVICE: |
1716 | revents = audio_poll(sc, events, l, file); | | 1825 | revents = audio_poll(sc, events, l, file); |
1717 | break; | | 1826 | break; |
1718 | case AUDIOCTL_DEVICE: | | 1827 | case AUDIOCTL_DEVICE: |
1719 | case MIXER_DEVICE: | | 1828 | case MIXER_DEVICE: |
1720 | revents = 0; | | 1829 | revents = 0; |
1721 | break; | | 1830 | break; |
1722 | default: | | 1831 | default: |
1723 | revents = POLLERR; | | 1832 | revents = POLLERR; |
1724 | break; | | 1833 | break; |
1725 | } | | 1834 | } |
1726 | | | 1835 | |
| | | 1836 | audio_file_exit(sc, &sc_ref); |
1727 | return revents; | | 1837 | return revents; |
1728 | } | | 1838 | } |
1729 | | | 1839 | |
1730 | static int | | 1840 | static int |
1731 | audiokqfilter(struct file *fp, struct knote *kn) | | 1841 | audiokqfilter(struct file *fp, struct knote *kn) |
1732 | { | | 1842 | { |
1733 | struct audio_softc *sc; | | 1843 | struct audio_softc *sc; |
| | | 1844 | struct psref sc_ref; |
1734 | audio_file_t *file; | | 1845 | audio_file_t *file; |
1735 | dev_t dev; | | 1846 | dev_t dev; |
1736 | int error; | | 1847 | int error; |
1737 | | | 1848 | |
1738 | KASSERT(fp->f_audioctx); | | 1849 | KASSERT(fp->f_audioctx); |
1739 | file = fp->f_audioctx; | | 1850 | file = fp->f_audioctx; |
1740 | sc = file->sc; | | | |
1741 | dev = file->dev; | | 1851 | dev = file->dev; |
1742 | | | 1852 | |
| | | 1853 | sc = audio_file_enter(file, &sc_ref); |
| | | 1854 | if (sc == NULL) |
| | | 1855 | return EIO; |
| | | 1856 | |
1743 | switch (AUDIODEV(dev)) { | | 1857 | switch (AUDIODEV(dev)) { |
1744 | case SOUND_DEVICE: | | 1858 | case SOUND_DEVICE: |
1745 | case AUDIO_DEVICE: | | 1859 | case AUDIO_DEVICE: |
1746 | error = audio_kqfilter(sc, file, kn); | | 1860 | error = audio_kqfilter(sc, file, kn); |
1747 | break; | | 1861 | break; |
1748 | case AUDIOCTL_DEVICE: | | 1862 | case AUDIOCTL_DEVICE: |
1749 | case MIXER_DEVICE: | | 1863 | case MIXER_DEVICE: |
1750 | error = ENODEV; | | 1864 | error = ENODEV; |
1751 | break; | | 1865 | break; |
1752 | default: | | 1866 | default: |
1753 | error = ENXIO; | | 1867 | error = ENXIO; |
1754 | break; | | 1868 | break; |
1755 | } | | 1869 | } |
1756 | | | 1870 | |
| | | 1871 | audio_file_exit(sc, &sc_ref); |
1757 | return error; | | 1872 | return error; |
1758 | } | | 1873 | } |
1759 | | | 1874 | |
1760 | static int | | 1875 | static int |
1761 | audiommap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, | | 1876 | audiommap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, |
1762 | int *advicep, struct uvm_object **uobjp, int *maxprotp) | | 1877 | int *advicep, struct uvm_object **uobjp, int *maxprotp) |
1763 | { | | 1878 | { |
1764 | struct audio_softc *sc; | | 1879 | struct audio_softc *sc; |
| | | 1880 | struct psref sc_ref; |
1765 | audio_file_t *file; | | 1881 | audio_file_t *file; |
1766 | dev_t dev; | | 1882 | dev_t dev; |
1767 | int error; | | 1883 | int error; |
1768 | | | 1884 | |
1769 | KASSERT(fp->f_audioctx); | | 1885 | KASSERT(fp->f_audioctx); |
1770 | file = fp->f_audioctx; | | 1886 | file = fp->f_audioctx; |
1771 | sc = file->sc; | | | |
1772 | dev = file->dev; | | 1887 | dev = file->dev; |
1773 | | | 1888 | |
| | | 1889 | sc = audio_file_enter(file, &sc_ref); |
| | | 1890 | if (sc == NULL) |
| | | 1891 | return EIO; |
| | | 1892 | |
1774 | mutex_enter(sc->sc_lock); | | 1893 | mutex_enter(sc->sc_lock); |
1775 | device_active(sc->sc_dev, DVA_SYSTEM); /* XXXJDM */ | | 1894 | device_active(sc->sc_dev, DVA_SYSTEM); /* XXXJDM */ |
1776 | mutex_exit(sc->sc_lock); | | 1895 | mutex_exit(sc->sc_lock); |
1777 | | | 1896 | |
1778 | switch (AUDIODEV(dev)) { | | 1897 | switch (AUDIODEV(dev)) { |
1779 | case SOUND_DEVICE: | | 1898 | case SOUND_DEVICE: |
1780 | case AUDIO_DEVICE: | | 1899 | case AUDIO_DEVICE: |
1781 | error = audio_mmap(sc, offp, len, prot, flagsp, advicep, | | 1900 | error = audio_mmap(sc, offp, len, prot, flagsp, advicep, |
1782 | uobjp, maxprotp, file); | | 1901 | uobjp, maxprotp, file); |
1783 | break; | | 1902 | break; |
1784 | case AUDIOCTL_DEVICE: | | 1903 | case AUDIOCTL_DEVICE: |
1785 | case MIXER_DEVICE: | | 1904 | case MIXER_DEVICE: |
1786 | default: | | 1905 | default: |
1787 | error = ENOTSUP; | | 1906 | error = ENOTSUP; |
1788 | break; | | 1907 | break; |
1789 | } | | 1908 | } |
1790 | | | 1909 | |
| | | 1910 | audio_file_exit(sc, &sc_ref); |
1791 | return error; | | 1911 | return error; |
1792 | } | | 1912 | } |
1793 | | | 1913 | |
1794 | | | 1914 | |
1795 | /* Exported interfaces for audiobell. */ | | 1915 | /* Exported interfaces for audiobell. */ |
1796 | | | 1916 | |
1797 | /* | | 1917 | /* |
1798 | * Open for audiobell. | | 1918 | * Open for audiobell. |
1799 | * It stores allocated file to *filep. | | 1919 | * It stores allocated file to *filep. |
1800 | * If successful returns 0, otherwise errno. | | 1920 | * If successful returns 0, otherwise errno. |
1801 | */ | | 1921 | */ |
1802 | int | | 1922 | int |
1803 | audiobellopen(dev_t dev, audio_file_t **filep) | | 1923 | audiobellopen(dev_t dev, audio_file_t **filep) |
| @@ -1816,67 +1936,81 @@ audiobellopen(dev_t dev, audio_file_t ** | | | @@ -1816,67 +1936,81 @@ audiobellopen(dev_t dev, audio_file_t ** |
1816 | | | 1936 | |
1817 | device_active(sc->sc_dev, DVA_SYSTEM); | | 1937 | device_active(sc->sc_dev, DVA_SYSTEM); |
1818 | error = audio_open(dev, sc, FWRITE, 0, curlwp, filep); | | 1938 | error = audio_open(dev, sc, FWRITE, 0, curlwp, filep); |
1819 | | | 1939 | |
1820 | audio_exit_exclusive(sc); | | 1940 | audio_exit_exclusive(sc); |
1821 | return error; | | 1941 | return error; |
1822 | } | | 1942 | } |
1823 | | | 1943 | |
1824 | /* Close for audiobell */ | | 1944 | /* Close for audiobell */ |
1825 | int | | 1945 | int |
1826 | audiobellclose(audio_file_t *file) | | 1946 | audiobellclose(audio_file_t *file) |
1827 | { | | 1947 | { |
1828 | struct audio_softc *sc; | | 1948 | struct audio_softc *sc; |
| | | 1949 | struct psref sc_ref; |
1829 | int error; | | 1950 | int error; |
1830 | | | 1951 | |
1831 | sc = file->sc; | | 1952 | sc = audio_file_enter(file, &sc_ref); |
| | | 1953 | if (sc == NULL) |
| | | 1954 | return EIO; |
1832 | | | 1955 | |
1833 | device_active(sc->sc_dev, DVA_SYSTEM); | | | |
1834 | error = audio_close(sc, file); | | 1956 | error = audio_close(sc, file); |
1835 | | | 1957 | |
| | | 1958 | audio_file_exit(sc, &sc_ref); |
1836 | return error; | | 1959 | return error; |
1837 | } | | 1960 | } |
1838 | | | 1961 | |
1839 | /* Set sample rate for audiobell */ | | 1962 | /* Set sample rate for audiobell */ |
1840 | int | | 1963 | int |
1841 | audiobellsetrate(audio_file_t *file, u_int sample_rate) | | 1964 | audiobellsetrate(audio_file_t *file, u_int sample_rate) |
1842 | { | | 1965 | { |
1843 | struct audio_softc *sc; | | 1966 | struct audio_softc *sc; |
| | | 1967 | struct psref sc_ref; |
1844 | struct audio_info ai; | | 1968 | struct audio_info ai; |
1845 | int error; | | 1969 | int error; |
1846 | | | 1970 | |
1847 | sc = file->sc; | | 1971 | sc = audio_file_enter(file, &sc_ref); |
| | | 1972 | if (sc == NULL) |
| | | 1973 | return EIO; |
1848 | | | 1974 | |
1849 | AUDIO_INITINFO(&ai); | | 1975 | AUDIO_INITINFO(&ai); |
1850 | ai.play.sample_rate = sample_rate; | | 1976 | ai.play.sample_rate = sample_rate; |
1851 | | | 1977 | |
1852 | error = audio_enter_exclusive(sc); | | 1978 | error = audio_enter_exclusive(sc); |
1853 | if (error) | | 1979 | if (error) |
1854 | return error; | | 1980 | goto done; |
1855 | error = audio_file_setinfo(sc, file, &ai); | | 1981 | error = audio_file_setinfo(sc, file, &ai); |
1856 | audio_exit_exclusive(sc); | | 1982 | audio_exit_exclusive(sc); |
1857 | | | 1983 | |
| | | 1984 | done: |
| | | 1985 | audio_file_exit(sc, &sc_ref); |
1858 | return error; | | 1986 | return error; |
1859 | } | | 1987 | } |
1860 | | | 1988 | |
1861 | /* Playback for audiobell */ | | 1989 | /* Playback for audiobell */ |
1862 | int | | 1990 | int |
1863 | audiobellwrite(audio_file_t *file, struct uio *uio) | | 1991 | audiobellwrite(audio_file_t *file, struct uio *uio) |
1864 | { | | 1992 | { |
1865 | struct audio_softc *sc; | | 1993 | struct audio_softc *sc; |
| | | 1994 | struct psref sc_ref; |
1866 | int error; | | 1995 | int error; |
1867 | | | 1996 | |
1868 | sc = file->sc; | | 1997 | sc = audio_file_enter(file, &sc_ref); |
| | | 1998 | if (sc == NULL) |
| | | 1999 | return EIO; |
| | | 2000 | |
1869 | error = audio_write(sc, uio, 0, file); | | 2001 | error = audio_write(sc, uio, 0, file); |
| | | 2002 | |
| | | 2003 | audio_file_exit(sc, &sc_ref); |
1870 | return error; | | 2004 | return error; |
1871 | } | | 2005 | } |
1872 | | | 2006 | |
1873 | | | 2007 | |
1874 | /* | | 2008 | /* |
1875 | * Audio driver | | 2009 | * Audio driver |
1876 | */ | | 2010 | */ |
1877 | int | | 2011 | int |
1878 | audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt, | | 2012 | audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt, |
1879 | struct lwp *l, audio_file_t **bellfile) | | 2013 | struct lwp *l, audio_file_t **bellfile) |
1880 | { | | 2014 | { |
1881 | struct audio_info ai; | | 2015 | struct audio_info ai; |
1882 | struct file *fp; | | 2016 | struct file *fp; |
| @@ -2121,126 +2255,144 @@ bad2: | | | @@ -2121,126 +2255,144 @@ bad2: |
2121 | af->ptrack = NULL; | | 2255 | af->ptrack = NULL; |
2122 | } | | 2256 | } |
2123 | bad1: | | 2257 | bad1: |
2124 | kmem_free(af, sizeof(*af)); | | 2258 | kmem_free(af, sizeof(*af)); |
2125 | return error; | | 2259 | return error; |
2126 | } | | 2260 | } |
2127 | | | 2261 | |
2128 | /* | | 2262 | /* |
2129 | * Must be called without sc_lock nor sc_exlock held. | | 2263 | * Must be called without sc_lock nor sc_exlock held. |
2130 | */ | | 2264 | */ |
2131 | int | | 2265 | int |
2132 | audio_close(struct audio_softc *sc, audio_file_t *file) | | 2266 | audio_close(struct audio_softc *sc, audio_file_t *file) |
2133 | { | | 2267 | { |
2134 | audio_track_t *oldtrack; | | 2268 | |
| | | 2269 | /* Protect entering new fileops to this file */ |
| | | 2270 | atomic_store_relaxed(&file->dying, true); |
| | | 2271 | |
| | | 2272 | /* |
| | | 2273 | * Drain first. |
| | | 2274 | * It must be done before unlinking(acquiring exclusive lock). |
| | | 2275 | */ |
| | | 2276 | if (file->ptrack) { |
| | | 2277 | mutex_enter(sc->sc_lock); |
| | | 2278 | audio_track_drain(sc, file->ptrack); |
| | | 2279 | mutex_exit(sc->sc_lock); |
| | | 2280 | } |
| | | 2281 | |
| | | 2282 | return audio_unlink(sc, file); |
| | | 2283 | } |
| | | 2284 | |
| | | 2285 | /* |
| | | 2286 | * Unlink this file, but not freeing memory here. |
| | | 2287 | * Must be called without sc_lock nor sc_exlock held. |
| | | 2288 | */ |
| | | 2289 | int |
| | | 2290 | audio_unlink(struct audio_softc *sc, audio_file_t *file) |
| | | 2291 | { |
2135 | int error; | | 2292 | int error; |
2136 | | | 2293 | |
2137 | TRACEF(1, file, "%spid=%d.%d po=%d ro=%d", | | 2294 | TRACEF(1, file, "%spid=%d.%d po=%d ro=%d", |
2138 | (audiodebug >= 3) ? "start " : "", | | 2295 | (audiodebug >= 3) ? "start " : "", |
2139 | (int)curproc->p_pid, (int)curlwp->l_lid, | | 2296 | (int)curproc->p_pid, (int)curlwp->l_lid, |
2140 | sc->sc_popens, sc->sc_ropens); | | 2297 | sc->sc_popens, sc->sc_ropens); |
2141 | KASSERTMSG(sc->sc_popens + sc->sc_ropens > 0, | | 2298 | KASSERTMSG(sc->sc_popens + sc->sc_ropens > 0, |
2142 | "sc->sc_popens=%d, sc->sc_ropens=%d", | | 2299 | "sc->sc_popens=%d, sc->sc_ropens=%d", |
2143 | sc->sc_popens, sc->sc_ropens); | | 2300 | sc->sc_popens, sc->sc_ropens); |
2144 | | | 2301 | |
| | | 2302 | mutex_enter(sc->sc_lock); |
2145 | /* | | 2303 | /* |
2146 | * Drain first. | | 2304 | * Acquire exclusive lock to protect counters. |
2147 | * It must be done before acquiring exclusive lock. | | 2305 | * Does not use audio_enter_exclusive() due to sc_dying. |
2148 | */ | | 2306 | */ |
2149 | if (file->ptrack) { | | 2307 | while (__predict_false(sc->sc_exlock != 0)) { |
2150 | mutex_enter(sc->sc_lock); | | 2308 | error = cv_timedwait_sig(&sc->sc_exlockcv, sc->sc_lock, |
2151 | audio_track_drain(sc, file->ptrack); | | 2309 | mstohz(AUDIO_TIMEOUT)); |
2152 | mutex_exit(sc->sc_lock); | | 2310 | /* XXX what should I do on error? */ |
| | | 2311 | if (error == EWOULDBLOCK) { |
| | | 2312 | mutex_exit(sc->sc_lock); |
| | | 2313 | device_printf(sc->sc_dev, |
| | | 2314 | "%s: cv_timedwait_sig failed %d", __func__, error); |
| | | 2315 | return error; |
| | | 2316 | } |
2153 | } | | 2317 | } |
| | | 2318 | sc->sc_exlock = 1; |
2154 | | | 2319 | |
2155 | /* Then, acquire exclusive lock to protect counters. */ | | 2320 | device_active(sc->sc_dev, DVA_SYSTEM); |
2156 | /* XXX what should I do when an error occurs? */ | | 2321 | |
2157 | error = audio_enter_exclusive(sc); | | 2322 | mutex_enter(sc->sc_intr_lock); |
2158 | if (error) | | 2323 | SLIST_REMOVE(&sc->sc_files, file, audio_file, entry); |
2159 | return error; | | 2324 | mutex_exit(sc->sc_intr_lock); |
2160 | | | 2325 | |
2161 | if (file->ptrack) { | | 2326 | if (file->ptrack) { |
| | | 2327 | TRACET(3, file->ptrack, "dropframes=%" PRIu64, |
| | | 2328 | file->ptrack->dropframes); |
| | | 2329 | |
| | | 2330 | KASSERT(sc->sc_popens > 0); |
| | | 2331 | sc->sc_popens--; |
| | | 2332 | |
2162 | /* Call hw halt_output if this is the last playback track. */ | | 2333 | /* Call hw halt_output if this is the last playback track. */ |
2163 | if (sc->sc_popens == 1 && sc->sc_pbusy) { | | 2334 | if (sc->sc_popens == 0 && sc->sc_pbusy) { |
2164 | error = audio_pmixer_halt(sc); | | 2335 | error = audio_pmixer_halt(sc); |
2165 | if (error) { | | 2336 | if (error) { |
2166 | device_printf(sc->sc_dev, | | 2337 | device_printf(sc->sc_dev, |
2167 | "halt_output failed with %d\n", error); | | 2338 | "halt_output failed with %d (ignored)\n", |
| | | 2339 | error); |
2168 | } | | 2340 | } |
2169 | } | | 2341 | } |
2170 | | | 2342 | |
2171 | /* Destroy the track. */ | | | |
2172 | oldtrack = file->ptrack; | | | |
2173 | mutex_enter(sc->sc_intr_lock); | | | |
2174 | file->ptrack = NULL; | | | |
2175 | mutex_exit(sc->sc_intr_lock); | | | |
2176 | TRACET(3, oldtrack, "dropframes=%" PRIu64, | | | |
2177 | oldtrack->dropframes); | | | |
2178 | audio_track_destroy(oldtrack); | | | |
2179 | | | | |
2180 | KASSERT(sc->sc_popens > 0); | | | |
2181 | sc->sc_popens--; | | | |
2182 | | | | |
2183 | /* Restore mixing volume if all tracks are gone. */ | | 2343 | /* Restore mixing volume if all tracks are gone. */ |
2184 | if (sc->sc_popens == 0) { | | 2344 | if (sc->sc_popens == 0) { |
| | | 2345 | /* intr_lock is not necessary, but just manners. */ |
2185 | mutex_enter(sc->sc_intr_lock); | | 2346 | mutex_enter(sc->sc_intr_lock); |
2186 | sc->sc_pmixer->volume = 256; | | 2347 | sc->sc_pmixer->volume = 256; |
2187 | sc->sc_pmixer->voltimer = 0; | | 2348 | sc->sc_pmixer->voltimer = 0; |
2188 | mutex_exit(sc->sc_intr_lock); | | 2349 | mutex_exit(sc->sc_intr_lock); |
2189 | } | | 2350 | } |
2190 | } | | 2351 | } |
2191 | if (file->rtrack) { | | 2352 | if (file->rtrack) { |
| | | 2353 | TRACET(3, file->rtrack, "dropframes=%" PRIu64, |
| | | 2354 | file->rtrack->dropframes); |
| | | 2355 | |
| | | 2356 | KASSERT(sc->sc_ropens > 0); |
| | | 2357 | sc->sc_ropens--; |
| | | 2358 | |
2192 | /* Call hw halt_input if this is the last recording track. */ | | 2359 | /* Call hw halt_input if this is the last recording track. */ |
2193 | if (sc->sc_ropens == 1 && sc->sc_rbusy) { | | 2360 | if (sc->sc_ropens == 0 && sc->sc_rbusy) { |
2194 | error = audio_rmixer_halt(sc); | | 2361 | error = audio_rmixer_halt(sc); |
2195 | if (error) { | | 2362 | if (error) { |
2196 | device_printf(sc->sc_dev, | | 2363 | device_printf(sc->sc_dev, |
2197 | "halt_input failed with %d\n", error); | | 2364 | "halt_input failed with %d (ignored)\n", |
| | | 2365 | error); |
2198 | } | | 2366 | } |
2199 | } | | 2367 | } |
2200 | | | 2368 | |
2201 | /* Destroy the track. */ | | | |
2202 | oldtrack = file->rtrack; | | | |
2203 | mutex_enter(sc->sc_intr_lock); | | | |
2204 | file->rtrack = NULL; | | | |
2205 | mutex_exit(sc->sc_intr_lock); | | | |
2206 | TRACET(3, oldtrack, "dropframes=%" PRIu64, | | | |
2207 | oldtrack->dropframes); | | | |
2208 | audio_track_destroy(oldtrack); | | | |
2209 | | | | |
2210 | KASSERT(sc->sc_ropens > 0); | | | |
2211 | sc->sc_ropens--; | | | |
2212 | } | | 2369 | } |
2213 | | | 2370 | |
2214 | /* Call hw close if this is the last track. */ | | 2371 | /* Call hw close if this is the last track. */ |
2215 | if (sc->sc_popens + sc->sc_ropens == 0) { | | 2372 | if (sc->sc_popens + sc->sc_ropens == 0) { |
2216 | if (sc->hw_if->close) { | | 2373 | if (sc->hw_if->close) { |
2217 | TRACE(2, "hw_if close"); | | 2374 | TRACE(2, "hw_if close"); |
2218 | mutex_enter(sc->sc_intr_lock); | | 2375 | mutex_enter(sc->sc_intr_lock); |
2219 | sc->hw_if->close(sc->hw_hdl); | | 2376 | sc->hw_if->close(sc->hw_hdl); |
2220 | mutex_exit(sc->sc_intr_lock); | | 2377 | mutex_exit(sc->sc_intr_lock); |
2221 | } | | 2378 | } |
2222 | | | 2379 | |
2223 | kauth_cred_free(sc->sc_cred); | | 2380 | kauth_cred_free(sc->sc_cred); |
2224 | } | | 2381 | } |
2225 | | | 2382 | |
2226 | mutex_enter(sc->sc_intr_lock); | | | |
2227 | SLIST_REMOVE(&sc->sc_files, file, audio_file, entry); | | | |
2228 | mutex_exit(sc->sc_intr_lock); | | | |
2229 | | | | |
2230 | TRACE(3, "done"); | | 2383 | TRACE(3, "done"); |
2231 | audio_exit_exclusive(sc); | | 2384 | audio_exit_exclusive(sc); |
2232 | | | 2385 | |
2233 | kmem_free(file, sizeof(*file)); | | | |
2234 | return 0; | | 2386 | return 0; |
2235 | } | | 2387 | } |
2236 | | | 2388 | |
2237 | /* | | 2389 | /* |
2238 | * Must be called without sc_lock nor sc_exlock held. | | 2390 | * Must be called without sc_lock nor sc_exlock held. |
2239 | */ | | 2391 | */ |
2240 | int | | 2392 | int |
2241 | audio_read(struct audio_softc *sc, struct uio *uio, int ioflag, | | 2393 | audio_read(struct audio_softc *sc, struct uio *uio, int ioflag, |
2242 | audio_file_t *file) | | 2394 | audio_file_t *file) |
2243 | { | | 2395 | { |
2244 | audio_track_t *track; | | 2396 | audio_track_t *track; |
2245 | audio_ring_t *usrbuf; | | 2397 | audio_ring_t *usrbuf; |
2246 | audio_ring_t *input; | | 2398 | audio_ring_t *input; |
| @@ -3082,34 +3234,26 @@ audioctl_open(dev_t dev, struct audio_so | | | @@ -3082,34 +3234,26 @@ audioctl_open(dev_t dev, struct audio_so |
3082 | | | 3234 | |
3083 | af = kmem_zalloc(sizeof(audio_file_t), KM_SLEEP); | | 3235 | af = kmem_zalloc(sizeof(audio_file_t), KM_SLEEP); |
3084 | af->sc = sc; | | 3236 | af->sc = sc; |
3085 | af->dev = dev; | | 3237 | af->dev = dev; |
3086 | | | 3238 | |
3087 | /* Not necessary to insert sc_files. */ | | 3239 | /* Not necessary to insert sc_files. */ |
3088 | | | 3240 | |
3089 | error = fd_clone(fp, fd, flags, &audio_fileops, af); | | 3241 | error = fd_clone(fp, fd, flags, &audio_fileops, af); |
3090 | KASSERTMSG(error == EMOVEFD, "error=%d", error); | | 3242 | KASSERTMSG(error == EMOVEFD, "error=%d", error); |
3091 | | | 3243 | |
3092 | return error; | | 3244 | return error; |
3093 | } | | 3245 | } |
3094 | | | 3246 | |
3095 | static int | | | |
3096 | audioctl_close(struct audio_softc *sc, audio_file_t *file) | | | |
3097 | { | | | |
3098 | | | | |
3099 | kmem_free(file, sizeof(*file)); | | | |
3100 | return 0; | | | |
3101 | } | | | |
3102 | | | | |
3103 | /* | | 3247 | /* |
3104 | * Free 'mem' if available, and initialize the pointer. | | 3248 | * Free 'mem' if available, and initialize the pointer. |
3105 | * For this reason, this is implemented as macro. | | 3249 | * For this reason, this is implemented as macro. |
3106 | */ | | 3250 | */ |
3107 | #define audio_free(mem) do { \ | | 3251 | #define audio_free(mem) do { \ |
3108 | if (mem != NULL) { \ | | 3252 | if (mem != NULL) { \ |
3109 | kern_free(mem); \ | | 3253 | kern_free(mem); \ |
3110 | mem = NULL; \ | | 3254 | mem = NULL; \ |
3111 | } \ | | 3255 | } \ |
3112 | } while (0) | | 3256 | } while (0) |
3113 | | | 3257 | |
3114 | /* | | 3258 | /* |
3115 | * (Re)allocate 'memblock' with specified 'bytes'. | | 3259 | * (Re)allocate 'memblock' with specified 'bytes'. |
| @@ -7683,27 +7827,26 @@ mixer_signal(struct audio_softc *sc) | | | @@ -7683,27 +7827,26 @@ mixer_signal(struct audio_softc *sc) |
7683 | | | 7827 | |
7684 | /* | | 7828 | /* |
7685 | * Close a mixer device | | 7829 | * Close a mixer device |
7686 | */ | | 7830 | */ |
7687 | int | | 7831 | int |
7688 | mixer_close(struct audio_softc *sc, audio_file_t *file) | | 7832 | mixer_close(struct audio_softc *sc, audio_file_t *file) |
7689 | { | | 7833 | { |
7690 | | | 7834 | |
7691 | mutex_enter(sc->sc_lock); | | 7835 | mutex_enter(sc->sc_lock); |
7692 | TRACE(1, ""); | | 7836 | TRACE(1, ""); |
7693 | mixer_async_remove(sc, curproc->p_pid); | | 7837 | mixer_async_remove(sc, curproc->p_pid); |
7694 | mutex_exit(sc->sc_lock); | | 7838 | mutex_exit(sc->sc_lock); |
7695 | | | 7839 | |
7696 | kmem_free(file, sizeof(*file)); | | | |
7697 | return 0; | | 7840 | return 0; |
7698 | } | | 7841 | } |
7699 | | | 7842 | |
7700 | /* | | 7843 | /* |
7701 | * Must be called without sc_lock nor sc_exlock held. | | 7844 | * Must be called without sc_lock nor sc_exlock held. |
7702 | */ | | 7845 | */ |
7703 | int | | 7846 | int |
7704 | mixer_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag, | | 7847 | mixer_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag, |
7705 | struct lwp *l) | | 7848 | struct lwp *l) |
7706 | { | | 7849 | { |
7707 | mixer_devinfo_t *mi; | | 7850 | mixer_devinfo_t *mi; |
7708 | mixer_ctrl_t *mc; | | 7851 | mixer_ctrl_t *mc; |
7709 | int error; | | 7852 | int error; |
| @@ -8435,43 +8578,48 @@ audioprint(void *aux, const char *pnp) | | | @@ -8435,43 +8578,48 @@ audioprint(void *aux, const char *pnp) |
8435 | devmajor_t audio_bmajor = -1, audio_cmajor = -1; | | 8578 | devmajor_t audio_bmajor = -1, audio_cmajor = -1; |
8436 | | | 8579 | |
8437 | #include "ioconf.c" | | 8580 | #include "ioconf.c" |
8438 | | | 8581 | |
8439 | #endif | | 8582 | #endif |
8440 | | | 8583 | |
8441 | MODULE(MODULE_CLASS_DRIVER, audio, NULL); | | 8584 | MODULE(MODULE_CLASS_DRIVER, audio, NULL); |
8442 | | | 8585 | |
8443 | static int | | 8586 | static int |
8444 | audio_modcmd(modcmd_t cmd, void *arg) | | 8587 | audio_modcmd(modcmd_t cmd, void *arg) |
8445 | { | | 8588 | { |
8446 | int error = 0; | | 8589 | int error = 0; |
8447 | | | 8590 | |
8448 | #ifdef _MODULE | | | |
8449 | switch (cmd) { | | 8591 | switch (cmd) { |
8450 | case MODULE_CMD_INIT: | | 8592 | case MODULE_CMD_INIT: |
| | | 8593 | /* XXX interrupt level? */ |
| | | 8594 | audio_psref_class = psref_class_create("audio", IPL_SOFTSERIAL); |
| | | 8595 | #ifdef _MODULE |
8451 | error = devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor, | | 8596 | error = devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor, |
8452 | &audio_cdevsw, &audio_cmajor); | | 8597 | &audio_cdevsw, &audio_cmajor); |
8453 | if (error) | | 8598 | if (error) |
8454 | break; | | 8599 | break; |
8455 | | | 8600 | |
8456 | error = config_init_component(cfdriver_ioconf_audio, | | 8601 | error = config_init_component(cfdriver_ioconf_audio, |
8457 | cfattach_ioconf_audio, cfdata_ioconf_audio); | | 8602 | cfattach_ioconf_audio, cfdata_ioconf_audio); |
8458 | if (error) { | | 8603 | if (error) { |
8459 | devsw_detach(NULL, &audio_cdevsw); | | 8604 | devsw_detach(NULL, &audio_cdevsw); |
8460 | } | | 8605 | } |
| | | 8606 | #endif |
8461 | break; | | 8607 | break; |
8462 | case MODULE_CMD_FINI: | | 8608 | case MODULE_CMD_FINI: |
| | | 8609 | #ifdef _MODULE |
8463 | devsw_detach(NULL, &audio_cdevsw); | | 8610 | devsw_detach(NULL, &audio_cdevsw); |
8464 | error = config_fini_component(cfdriver_ioconf_audio, | | 8611 | error = config_fini_component(cfdriver_ioconf_audio, |
8465 | cfattach_ioconf_audio, cfdata_ioconf_audio); | | 8612 | cfattach_ioconf_audio, cfdata_ioconf_audio); |
8466 | if (error) | | 8613 | if (error) |
8467 | devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor, | | 8614 | devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor, |
8468 | &audio_cdevsw, &audio_cmajor); | | 8615 | &audio_cdevsw, &audio_cmajor); |
| | | 8616 | #endif |
| | | 8617 | psref_class_destroy(audio_psref_class); |
8469 | break; | | 8618 | break; |
8470 | default: | | 8619 | default: |
8471 | error = ENOTTY; | | 8620 | error = ENOTTY; |
8472 | break; | | 8621 | break; |
8473 | } | | 8622 | } |
8474 | #endif | | | |
8475 | | | 8623 | |
8476 | return error; | | 8624 | return error; |
8477 | } | | 8625 | } |