1/*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * (C) 1997 Luigi Rizzo 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <dev/sound/pcm/sound.h> 29#include <dev/sound/pcm/ac97.h> 30#include <dev/sound/pcm/vchan.h> 31#include <dev/sound/pcm/dsp.h> 32#include <dev/sound/version.h> 33#include <sys/limits.h> 34#include <sys/sysctl.h> 35 36#include "feeder_if.h" 37
| 1/*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * (C) 1997 Luigi Rizzo 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <dev/sound/pcm/sound.h> 29#include <dev/sound/pcm/ac97.h> 30#include <dev/sound/pcm/vchan.h> 31#include <dev/sound/pcm/dsp.h> 32#include <dev/sound/version.h> 33#include <sys/limits.h> 34#include <sys/sysctl.h> 35 36#include "feeder_if.h" 37
|
38SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/sound.c 170289 2007-06-04 18:25:08Z dwmalone $");
| 38SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/sound.c 170815 2007-06-16 03:37:28Z ariff $");
|
39 40devclass_t pcm_devclass; 41 42int pcm_veto_load = 1; 43 44#ifdef USING_DEVFS 45int snd_unit = 0; 46TUNABLE_INT("hw.snd.default_unit", &snd_unit); 47#endif 48 49int snd_maxautovchans = 16; 50/* XXX: a tunable implies that we may need more than one sound channel before 51 the system can change a sysctl (/etc/sysctl.conf), do we really need 52 this? */ 53TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans); 54 55SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver"); 56 57/* 58 * XXX I've had enough with people not telling proper version/arch 59 * while reporting problems, not after 387397913213th questions/requests. 60 */ 61static const char snd_driver_version[] = 62 __XSTRING(SND_DRV_VERSION)"/"MACHINE_ARCH; 63SYSCTL_STRING(_hw_snd, OID_AUTO, version, CTLFLAG_RD, &snd_driver_version, 64 0, "Driver version/arch"); 65 66/** 67 * @brief Unit number allocator for syncgroup IDs 68 */ 69struct unrhdr *pcmsg_unrhdr = NULL; 70 71static int sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose); 72 73void * 74snd_mtxcreate(const char *desc, const char *type) 75{ 76#ifdef USING_MUTEX 77 struct mtx *m; 78 79 m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO); 80 mtx_init(m, desc, type, MTX_DEF); 81 return m; 82#else 83 return (void *)0xcafebabe; 84#endif 85} 86 87void 88snd_mtxfree(void *m) 89{ 90#ifdef USING_MUTEX 91 struct mtx *mtx = m; 92 93 /* mtx_assert(mtx, MA_OWNED); */ 94 mtx_destroy(mtx); 95 free(mtx, M_DEVBUF); 96#endif 97} 98 99void 100snd_mtxassert(void *m) 101{ 102#ifdef USING_MUTEX 103#ifdef INVARIANTS 104 struct mtx *mtx = m; 105 106 mtx_assert(mtx, MA_OWNED); 107#endif 108#endif 109} 110/* 111void 112snd_mtxlock(void *m) 113{ 114#ifdef USING_MUTEX 115 struct mtx *mtx = m; 116 117 mtx_lock(mtx); 118#endif 119} 120 121void 122snd_mtxunlock(void *m) 123{ 124#ifdef USING_MUTEX 125 struct mtx *mtx = m; 126 127 mtx_unlock(mtx); 128#endif 129} 130*/ 131int 132snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 133{
| 39 40devclass_t pcm_devclass; 41 42int pcm_veto_load = 1; 43 44#ifdef USING_DEVFS 45int snd_unit = 0; 46TUNABLE_INT("hw.snd.default_unit", &snd_unit); 47#endif 48 49int snd_maxautovchans = 16; 50/* XXX: a tunable implies that we may need more than one sound channel before 51 the system can change a sysctl (/etc/sysctl.conf), do we really need 52 this? */ 53TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans); 54 55SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver"); 56 57/* 58 * XXX I've had enough with people not telling proper version/arch 59 * while reporting problems, not after 387397913213th questions/requests. 60 */ 61static const char snd_driver_version[] = 62 __XSTRING(SND_DRV_VERSION)"/"MACHINE_ARCH; 63SYSCTL_STRING(_hw_snd, OID_AUTO, version, CTLFLAG_RD, &snd_driver_version, 64 0, "Driver version/arch"); 65 66/** 67 * @brief Unit number allocator for syncgroup IDs 68 */ 69struct unrhdr *pcmsg_unrhdr = NULL; 70 71static int sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose); 72 73void * 74snd_mtxcreate(const char *desc, const char *type) 75{ 76#ifdef USING_MUTEX 77 struct mtx *m; 78 79 m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO); 80 mtx_init(m, desc, type, MTX_DEF); 81 return m; 82#else 83 return (void *)0xcafebabe; 84#endif 85} 86 87void 88snd_mtxfree(void *m) 89{ 90#ifdef USING_MUTEX 91 struct mtx *mtx = m; 92 93 /* mtx_assert(mtx, MA_OWNED); */ 94 mtx_destroy(mtx); 95 free(mtx, M_DEVBUF); 96#endif 97} 98 99void 100snd_mtxassert(void *m) 101{ 102#ifdef USING_MUTEX 103#ifdef INVARIANTS 104 struct mtx *mtx = m; 105 106 mtx_assert(mtx, MA_OWNED); 107#endif 108#endif 109} 110/* 111void 112snd_mtxlock(void *m) 113{ 114#ifdef USING_MUTEX 115 struct mtx *mtx = m; 116 117 mtx_lock(mtx); 118#endif 119} 120 121void 122snd_mtxunlock(void *m) 123{ 124#ifdef USING_MUTEX 125 struct mtx *mtx = m; 126 127 mtx_unlock(mtx); 128#endif 129} 130*/ 131int 132snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 133{
|
| 134 struct snddev_info *d;
|
134#ifdef USING_MUTEX 135 flags &= INTR_MPSAFE; 136 flags |= INTR_TYPE_AV; 137#else 138 flags = INTR_TYPE_AV; 139#endif
| 135#ifdef USING_MUTEX 136 flags &= INTR_MPSAFE; 137 flags |= INTR_TYPE_AV; 138#else 139 flags = INTR_TYPE_AV; 140#endif
|
| 141 d = device_get_softc(dev); 142 if (d != NULL && (flags & INTR_MPSAFE)) 143 d->flags |= SD_F_MPSAFE; 144
|
140 return bus_setup_intr(dev, res, flags, 141#if __FreeBSD_version >= 700031 142 NULL, 143#endif 144 hand, param, cookiep); 145} 146 147#ifndef PCM_DEBUG_MTX 148void 149pcm_lock(struct snddev_info *d) 150{ 151 snd_mtxlock(d->lock); 152} 153 154void 155pcm_unlock(struct snddev_info *d) 156{ 157 snd_mtxunlock(d->lock); 158} 159#endif 160 161struct pcm_channel * 162pcm_getfakechan(struct snddev_info *d) 163{ 164 return d->fakechan; 165} 166 167static void 168pcm_clonereset(struct snddev_info *d) 169{ 170 int cmax; 171
| 145 return bus_setup_intr(dev, res, flags, 146#if __FreeBSD_version >= 700031 147 NULL, 148#endif 149 hand, param, cookiep); 150} 151 152#ifndef PCM_DEBUG_MTX 153void 154pcm_lock(struct snddev_info *d) 155{ 156 snd_mtxlock(d->lock); 157} 158 159void 160pcm_unlock(struct snddev_info *d) 161{ 162 snd_mtxunlock(d->lock); 163} 164#endif 165 166struct pcm_channel * 167pcm_getfakechan(struct snddev_info *d) 168{ 169 return d->fakechan; 170} 171 172static void 173pcm_clonereset(struct snddev_info *d) 174{ 175 int cmax; 176
|
172 snd_mtxassert(d->lock);
| 177 PCM_BUSYASSERT(d);
|
173 174 cmax = d->playcount + d->reccount - 1; 175 if (d->pvchancount > 0) 176 cmax += MAX(d->pvchancount, snd_maxautovchans) - 1; 177 if (d->rvchancount > 0) 178 cmax += MAX(d->rvchancount, snd_maxautovchans) - 1; 179 if (cmax > PCMMAXCLONE) 180 cmax = PCMMAXCLONE; 181 (void)snd_clone_gc(d->clones); 182 (void)snd_clone_setmaxunit(d->clones, cmax); 183} 184 185static int 186pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num) 187{ 188 struct pcm_channel *c, *ch, *nch; 189 int err, vcnt; 190
| 178 179 cmax = d->playcount + d->reccount - 1; 180 if (d->pvchancount > 0) 181 cmax += MAX(d->pvchancount, snd_maxautovchans) - 1; 182 if (d->rvchancount > 0) 183 cmax += MAX(d->rvchancount, snd_maxautovchans) - 1; 184 if (cmax > PCMMAXCLONE) 185 cmax = PCMMAXCLONE; 186 (void)snd_clone_gc(d->clones); 187 (void)snd_clone_setmaxunit(d->clones, cmax); 188} 189 190static int 191pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num) 192{ 193 struct pcm_channel *c, *ch, *nch; 194 int err, vcnt; 195
|
191 err = 0;
| 196 PCM_BUSYASSERT(d);
|
192
| 197
|
193 pcm_inprog(d, 1); 194
| |
195 if ((direction == PCMDIR_PLAY && d->playcount < 1) ||
| 198 if ((direction == PCMDIR_PLAY && d->playcount < 1) ||
|
196 (direction == PCMDIR_REC && d->reccount < 1)) { 197 err = ENODEV; 198 goto pcm_setvchans_out; 199 }
| 199 (direction == PCMDIR_REC && d->reccount < 1)) 200 return (ENODEV);
|
200
| 201
|
201 if (!(d->flags & SD_F_AUTOVCHAN)) { 202 err = EINVAL; 203 goto pcm_setvchans_out; 204 }
| 202 if (!(d->flags & SD_F_AUTOVCHAN)) 203 return (EINVAL);
|
205
| 204
|
206 if (newcnt < 0 || newcnt > SND_MAXVCHANS) { 207 err = E2BIG; 208 goto pcm_setvchans_out; 209 }
| 205 if (newcnt < 0 || newcnt > SND_MAXVCHANS) 206 return (E2BIG);
|
210 211 if (direction == PCMDIR_PLAY) 212 vcnt = d->pvchancount; 213 else if (direction == PCMDIR_REC) 214 vcnt = d->rvchancount;
| 207 208 if (direction == PCMDIR_PLAY) 209 vcnt = d->pvchancount; 210 else if (direction == PCMDIR_REC) 211 vcnt = d->rvchancount;
|
215 else { 216 err = EINVAL; 217 goto pcm_setvchans_out; 218 }
| 212 else 213 return (EINVAL);
|
219 220 if (newcnt > vcnt) { 221 KASSERT(num == -1 || 222 (num >= 0 && num < SND_MAXVCHANS && (newcnt - 1) == vcnt), 223 ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d", 224 num, newcnt, vcnt)); 225 /* add new vchans - find a parent channel first */
| 214 215 if (newcnt > vcnt) { 216 KASSERT(num == -1 || 217 (num >= 0 && num < SND_MAXVCHANS && (newcnt - 1) == vcnt), 218 ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d", 219 num, newcnt, vcnt)); 220 /* add new vchans - find a parent channel first */
|
| 221 ch = NULL;
|
226 CHN_FOREACH(c, d, channels.pcm) { 227 CHN_LOCK(c); 228 if (c->direction == direction && 229 ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 &&
| 222 CHN_FOREACH(c, d, channels.pcm) { 223 CHN_LOCK(c); 224 if (c->direction == direction && 225 ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 &&
|
230 !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) 231 goto pcm_setvchans_addok;
| 226 !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) { 227 ch = c; 228 break; 229 }
|
232 CHN_UNLOCK(c); 233 }
| 230 CHN_UNLOCK(c); 231 }
|
234 err = EBUSY; 235 goto pcm_setvchans_out; 236pcm_setvchans_addok: 237 c->flags |= CHN_F_BUSY;
| 232 if (ch == NULL) 233 return (EBUSY); 234 ch->flags |= CHN_F_BUSY; 235 err = 0;
|
238 while (err == 0 && newcnt > vcnt) {
| 236 while (err == 0 && newcnt > vcnt) {
|
239 err = vchan_create(c, num);
| 237 err = vchan_create(ch, num);
|
240 if (err == 0) 241 vcnt++; 242 else if (err == E2BIG && newcnt > vcnt) 243 device_printf(d->dev, 244 "%s: err=%d Maximum channel reached.\n", 245 __func__, err); 246 } 247 if (vcnt == 0)
| 238 if (err == 0) 239 vcnt++; 240 else if (err == E2BIG && newcnt > vcnt) 241 device_printf(d->dev, 242 "%s: err=%d Maximum channel reached.\n", 243 __func__, err); 244 } 245 if (vcnt == 0)
|
248 c->flags &= ~CHN_F_BUSY; 249 CHN_UNLOCK(c); 250 pcm_lock(d); 251 pcm_clonereset(d); 252 pcm_unlock(d);
| 246 ch->flags &= ~CHN_F_BUSY; 247 CHN_UNLOCK(ch); 248 if (err != 0) 249 return (err); 250 else 251 pcm_clonereset(d);
|
253 } else if (newcnt < vcnt) { 254 KASSERT(num == -1, 255 ("bogus vchan_destroy() request num=%d", num)); 256 CHN_FOREACH(c, d, channels.pcm) { 257 CHN_LOCK(c); 258 if (c->direction != direction || 259 CHN_EMPTY(c, children) || 260 !(c->flags & CHN_F_HAS_VCHAN)) { 261 CHN_UNLOCK(c); 262 continue; 263 } 264 CHN_FOREACH_SAFE(ch, c, nch, children) { 265 CHN_LOCK(ch); 266 if (!(ch->flags & CHN_F_BUSY)) { 267 CHN_UNLOCK(ch); 268 CHN_UNLOCK(c); 269 err = vchan_destroy(ch); 270 CHN_LOCK(c); 271 if (err == 0) 272 vcnt--; 273 } else 274 CHN_UNLOCK(ch);
| 252 } else if (newcnt < vcnt) { 253 KASSERT(num == -1, 254 ("bogus vchan_destroy() request num=%d", num)); 255 CHN_FOREACH(c, d, channels.pcm) { 256 CHN_LOCK(c); 257 if (c->direction != direction || 258 CHN_EMPTY(c, children) || 259 !(c->flags & CHN_F_HAS_VCHAN)) { 260 CHN_UNLOCK(c); 261 continue; 262 } 263 CHN_FOREACH_SAFE(ch, c, nch, children) { 264 CHN_LOCK(ch); 265 if (!(ch->flags & CHN_F_BUSY)) { 266 CHN_UNLOCK(ch); 267 CHN_UNLOCK(c); 268 err = vchan_destroy(ch); 269 CHN_LOCK(c); 270 if (err == 0) 271 vcnt--; 272 } else 273 CHN_UNLOCK(ch);
|
275 if (vcnt == newcnt) { 276 err = 0;
| 274 if (vcnt == newcnt)
|
277 break;
| 275 break;
|
278 }
| |
279 } 280 CHN_UNLOCK(c); 281 break; 282 }
| 276 } 277 CHN_UNLOCK(c); 278 break; 279 }
|
283 pcm_lock(d);
| |
284 pcm_clonereset(d);
| 280 pcm_clonereset(d);
|
285 pcm_unlock(d);
| |
286 } 287
| 281 } 282
|
288pcm_setvchans_out: 289 pcm_inprog(d, -1); 290 return err;
| 283 return (0);
|
291} 292 293/* return error status and a locked channel */ 294int 295pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction, 296 pid_t pid, int devunit) 297{ 298 struct pcm_channel *c; 299 int err, vchancount; 300 301 KASSERT(d != NULL && ch != NULL && (devunit == -1 || 302 !(devunit & ~(SND_U_MASK | SND_D_MASK | SND_C_MASK))) && 303 (direction == PCMDIR_PLAY || direction == PCMDIR_REC),
| 284} 285 286/* return error status and a locked channel */ 287int 288pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction, 289 pid_t pid, int devunit) 290{ 291 struct pcm_channel *c; 292 int err, vchancount; 293 294 KASSERT(d != NULL && ch != NULL && (devunit == -1 || 295 !(devunit & ~(SND_U_MASK | SND_D_MASK | SND_C_MASK))) && 296 (direction == PCMDIR_PLAY || direction == PCMDIR_REC),
|
304 ("%s() invalid d=%p ch=%p direction=%d pid=%d devunit=%d",
| 297 ("%s(): invalid d=%p ch=%p direction=%d pid=%d devunit=%d",
|
305 __func__, d, ch, direction, pid, devunit));
| 298 __func__, d, ch, direction, pid, devunit));
|
| 299 PCM_BUSYASSERT(d);
|
306 307 /* Double check again. */ 308 if (devunit != -1) { 309 switch (snd_unit2d(devunit)) { 310 case SND_DEV_DSPHW_PLAY: 311 case SND_DEV_DSPHW_VPLAY: 312 if (direction != PCMDIR_PLAY) 313 return (EOPNOTSUPP); 314 break; 315 case SND_DEV_DSPHW_REC: 316 case SND_DEV_DSPHW_VREC: 317 if (direction != PCMDIR_REC) 318 return (EOPNOTSUPP); 319 break; 320 default: 321 if (!(direction == PCMDIR_PLAY || 322 direction == PCMDIR_REC)) 323 return (EOPNOTSUPP); 324 break; 325 } 326 } 327 328retry_chnalloc:
| 300 301 /* Double check again. */ 302 if (devunit != -1) { 303 switch (snd_unit2d(devunit)) { 304 case SND_DEV_DSPHW_PLAY: 305 case SND_DEV_DSPHW_VPLAY: 306 if (direction != PCMDIR_PLAY) 307 return (EOPNOTSUPP); 308 break; 309 case SND_DEV_DSPHW_REC: 310 case SND_DEV_DSPHW_VREC: 311 if (direction != PCMDIR_REC) 312 return (EOPNOTSUPP); 313 break; 314 default: 315 if (!(direction == PCMDIR_PLAY || 316 direction == PCMDIR_REC)) 317 return (EOPNOTSUPP); 318 break; 319 } 320 } 321 322retry_chnalloc:
|
329 err = ENODEV;
| 323 err = EOPNOTSUPP;
|
330 /* scan for a free channel */ 331 CHN_FOREACH(c, d, channels.pcm) { 332 CHN_LOCK(c); 333 if (c->direction == direction && !(c->flags & CHN_F_BUSY) && 334 (devunit == -1 || devunit == -2 || c->unit == devunit)) { 335 c->flags |= CHN_F_BUSY; 336 c->pid = pid; 337 *ch = c; 338 return (0); 339 } else if (c->unit == devunit) { 340 if (c->direction != direction) 341 err = EOPNOTSUPP; 342 else if (c->flags & CHN_F_BUSY) 343 err = EBUSY; 344 else 345 err = EINVAL; 346 CHN_UNLOCK(c); 347 return (err); 348 } else if ((devunit == -1 || devunit == -2) && 349 c->direction == direction && (c->flags & CHN_F_BUSY)) 350 err = EBUSY; 351 CHN_UNLOCK(c); 352 } 353
| 324 /* scan for a free channel */ 325 CHN_FOREACH(c, d, channels.pcm) { 326 CHN_LOCK(c); 327 if (c->direction == direction && !(c->flags & CHN_F_BUSY) && 328 (devunit == -1 || devunit == -2 || c->unit == devunit)) { 329 c->flags |= CHN_F_BUSY; 330 c->pid = pid; 331 *ch = c; 332 return (0); 333 } else if (c->unit == devunit) { 334 if (c->direction != direction) 335 err = EOPNOTSUPP; 336 else if (c->flags & CHN_F_BUSY) 337 err = EBUSY; 338 else 339 err = EINVAL; 340 CHN_UNLOCK(c); 341 return (err); 342 } else if ((devunit == -1 || devunit == -2) && 343 c->direction == direction && (c->flags & CHN_F_BUSY)) 344 err = EBUSY; 345 CHN_UNLOCK(c); 346 } 347
|
| 348 if (devunit == -2) 349 return (err); 350
|
354 /* no channel available */
| 351 /* no channel available */
|
355 if (devunit == -1 || (devunit != -2 && 356 (snd_unit2d(devunit) == SND_DEV_DSPHW_VPLAY || 357 snd_unit2d(devunit) == SND_DEV_DSPHW_VREC))) {
| 352 if (devunit == -1 || snd_unit2d(devunit) == SND_DEV_DSPHW_VPLAY || 353 snd_unit2d(devunit) == SND_DEV_DSPHW_VREC) {
|
358 if (direction == PCMDIR_PLAY) 359 vchancount = d->pvchancount; 360 else 361 vchancount = d->rvchancount; 362 if (!(vchancount > 0 && vchancount < snd_maxautovchans) && 363 (devunit == -1 || snd_unit2c(devunit) < snd_maxautovchans)) 364 return (err); 365 err = pcm_setvchans(d, direction, vchancount + 1, 366 (devunit == -1) ? -1 : snd_unit2c(devunit)); 367 if (err == 0) { 368 if (devunit == -1) 369 devunit = -2; 370 goto retry_chnalloc; 371 } 372 } 373 374 return (err); 375} 376 377/* release a locked channel and unlock it */ 378int 379pcm_chnrelease(struct pcm_channel *c) 380{
| 354 if (direction == PCMDIR_PLAY) 355 vchancount = d->pvchancount; 356 else 357 vchancount = d->rvchancount; 358 if (!(vchancount > 0 && vchancount < snd_maxautovchans) && 359 (devunit == -1 || snd_unit2c(devunit) < snd_maxautovchans)) 360 return (err); 361 err = pcm_setvchans(d, direction, vchancount + 1, 362 (devunit == -1) ? -1 : snd_unit2c(devunit)); 363 if (err == 0) { 364 if (devunit == -1) 365 devunit = -2; 366 goto retry_chnalloc; 367 } 368 } 369 370 return (err); 371} 372 373/* release a locked channel and unlock it */ 374int 375pcm_chnrelease(struct pcm_channel *c) 376{
|
| 377 PCM_BUSYASSERT(c->parentsnddev);
|
381 CHN_LOCKASSERT(c);
| 378 CHN_LOCKASSERT(c);
|
| 379
|
382 c->flags &= ~CHN_F_BUSY; 383 c->pid = -1; 384 CHN_UNLOCK(c);
| 380 c->flags &= ~CHN_F_BUSY; 381 c->pid = -1; 382 CHN_UNLOCK(c);
|
385 return 0;
| 383 384 return (0);
|
386} 387 388int 389pcm_chnref(struct pcm_channel *c, int ref) 390{
| 385} 386 387int 388pcm_chnref(struct pcm_channel *c, int ref) 389{
|
391 int r; 392
| 390 PCM_BUSYASSERT(c->parentsnddev);
|
393 CHN_LOCKASSERT(c);
| 391 CHN_LOCKASSERT(c);
|
| 392
|
394 c->refcount += ref;
| 393 c->refcount += ref;
|
395 r = c->refcount; 396 return r;
| 394 395 return (c->refcount);
|
397} 398 399int 400pcm_inprog(struct snddev_info *d, int delta) 401{
| 396} 397 398int 399pcm_inprog(struct snddev_info *d, int delta) 400{
|
402 int r;
| 401 snd_mtxassert(d->lock);
|
403
| 402
|
404 if (delta == 0) 405 return d->inprog; 406 407 /* backtrace(); */ 408 pcm_lock(d);
| |
409 d->inprog += delta;
| 403 d->inprog += delta;
|
410 r = d->inprog; 411 pcm_unlock(d); 412 return r;
| 404 405 return (d->inprog);
|
413} 414 415static void 416pcm_setmaxautovchans(struct snddev_info *d, int num) 417{
| 406} 407 408static void 409pcm_setmaxautovchans(struct snddev_info *d, int num) 410{
|
| 411 PCM_BUSYASSERT(d); 412
|
418 if (num < 0) 419 return; 420 421 if (num >= 0 && d->pvchancount > num) 422 (void)pcm_setvchans(d, PCMDIR_PLAY, num, -1); 423 else if (num > 0 && d->pvchancount == 0) 424 (void)pcm_setvchans(d, PCMDIR_PLAY, 1, -1); 425 426 if (num >= 0 && d->rvchancount > num) 427 (void)pcm_setvchans(d, PCMDIR_REC, num, -1); 428 else if (num > 0 && d->rvchancount == 0) 429 (void)pcm_setvchans(d, PCMDIR_REC, 1, -1); 430
| 413 if (num < 0) 414 return; 415 416 if (num >= 0 && d->pvchancount > num) 417 (void)pcm_setvchans(d, PCMDIR_PLAY, num, -1); 418 else if (num > 0 && d->pvchancount == 0) 419 (void)pcm_setvchans(d, PCMDIR_PLAY, 1, -1); 420 421 if (num >= 0 && d->rvchancount > num) 422 (void)pcm_setvchans(d, PCMDIR_REC, num, -1); 423 else if (num > 0 && d->rvchancount == 0) 424 (void)pcm_setvchans(d, PCMDIR_REC, 1, -1); 425
|
431 pcm_lock(d);
| |
432 pcm_clonereset(d);
| 426 pcm_clonereset(d);
|
433 pcm_unlock(d);
| |
434} 435 436#ifdef USING_DEVFS 437static int 438sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) 439{ 440 struct snddev_info *d; 441 int error, unit; 442 443 unit = snd_unit; 444 error = sysctl_handle_int(oidp, &unit, 0, req); 445 if (error == 0 && req->newptr != NULL) { 446 d = devclass_get_softc(pcm_devclass, unit);
| 427} 428 429#ifdef USING_DEVFS 430static int 431sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) 432{ 433 struct snddev_info *d; 434 int error, unit; 435 436 unit = snd_unit; 437 error = sysctl_handle_int(oidp, &unit, 0, req); 438 if (error == 0 && req->newptr != NULL) { 439 d = devclass_get_softc(pcm_devclass, unit);
|
447 if (d == NULL || CHN_EMPTY(d, channels.pcm))
| 440 if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm))
|
448 return EINVAL; 449 snd_unit = unit; 450 } 451 return (error); 452} 453/* XXX: do we need a way to let the user change the default unit? */ 454SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, CTLTYPE_INT | CTLFLAG_RW, 455 0, sizeof(int), sysctl_hw_snd_default_unit, "I", "default sound device"); 456#endif 457 458static int 459sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) 460{ 461 struct snddev_info *d; 462 int i, v, error; 463 464 v = snd_maxautovchans; 465 error = sysctl_handle_int(oidp, &v, 0, req); 466 if (error == 0 && req->newptr != NULL) { 467 if (v < 0) 468 v = 0; 469 if (v > SND_MAXVCHANS) 470 v = SND_MAXVCHANS; 471 snd_maxautovchans = v; 472 for (i = 0; pcm_devclass != NULL && 473 i < devclass_get_maxunit(pcm_devclass); i++) { 474 d = devclass_get_softc(pcm_devclass, i);
| 441 return EINVAL; 442 snd_unit = unit; 443 } 444 return (error); 445} 446/* XXX: do we need a way to let the user change the default unit? */ 447SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, CTLTYPE_INT | CTLFLAG_RW, 448 0, sizeof(int), sysctl_hw_snd_default_unit, "I", "default sound device"); 449#endif 450 451static int 452sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) 453{ 454 struct snddev_info *d; 455 int i, v, error; 456 457 v = snd_maxautovchans; 458 error = sysctl_handle_int(oidp, &v, 0, req); 459 if (error == 0 && req->newptr != NULL) { 460 if (v < 0) 461 v = 0; 462 if (v > SND_MAXVCHANS) 463 v = SND_MAXVCHANS; 464 snd_maxautovchans = v; 465 for (i = 0; pcm_devclass != NULL && 466 i < devclass_get_maxunit(pcm_devclass); i++) { 467 d = devclass_get_softc(pcm_devclass, i);
|
475 if (d == NULL)
| 468 if (!PCM_REGISTERED(d))
|
476 continue;
| 469 continue;
|
| 470 PCM_ACQUIRE_QUICK(d);
|
477 pcm_setmaxautovchans(d, v);
| 471 pcm_setmaxautovchans(d, v);
|
| 472 PCM_RELEASE_QUICK(d);
|
478 } 479 } 480 return (error); 481} 482SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, CTLTYPE_INT | CTLFLAG_RW, 483 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", "maximum virtual channel"); 484 485struct pcm_channel * 486pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo) 487{ 488 struct pcm_channel *ch; 489 int direction, err, rpnum, *pnum, max; 490 int udc, device, chan; 491 char *dirs, *devname, buf[CHN_NAMELEN]; 492
| 473 } 474 } 475 return (error); 476} 477SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, CTLTYPE_INT | CTLFLAG_RW, 478 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", "maximum virtual channel"); 479 480struct pcm_channel * 481pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo) 482{ 483 struct pcm_channel *ch; 484 int direction, err, rpnum, *pnum, max; 485 int udc, device, chan; 486 char *dirs, *devname, buf[CHN_NAMELEN]; 487
|
| 488 PCM_BUSYASSERT(d); 489 snd_mtxassert(d->lock);
|
493 KASSERT(num >= -1, ("invalid num=%d", num)); 494
| 490 KASSERT(num >= -1, ("invalid num=%d", num)); 491
|
495 pcm_lock(d);
| |
496
| 492
|
497 switch(dir) {
| 493 switch (dir) {
|
498 case PCMDIR_PLAY: 499 dirs = "play"; 500 direction = PCMDIR_PLAY; 501 pnum = &d->playcount; 502 device = SND_DEV_DSPHW_PLAY; 503 max = SND_MAXHWCHAN; 504 break; 505 case PCMDIR_PLAY_VIRTUAL: 506 dirs = "virtual"; 507 direction = PCMDIR_PLAY; 508 pnum = &d->pvchancount; 509 device = SND_DEV_DSPHW_VPLAY; 510 max = SND_MAXVCHANS; 511 break; 512 case PCMDIR_REC: 513 dirs = "record"; 514 direction = PCMDIR_REC; 515 pnum = &d->reccount; 516 device = SND_DEV_DSPHW_REC; 517 max = SND_MAXHWCHAN; 518 break; 519 case PCMDIR_REC_VIRTUAL: 520 dirs = "virtual"; 521 direction = PCMDIR_REC; 522 pnum = &d->rvchancount; 523 device = SND_DEV_DSPHW_VREC; 524 max = SND_MAXVCHANS; 525 break; 526 default:
| 494 case PCMDIR_PLAY: 495 dirs = "play"; 496 direction = PCMDIR_PLAY; 497 pnum = &d->playcount; 498 device = SND_DEV_DSPHW_PLAY; 499 max = SND_MAXHWCHAN; 500 break; 501 case PCMDIR_PLAY_VIRTUAL: 502 dirs = "virtual"; 503 direction = PCMDIR_PLAY; 504 pnum = &d->pvchancount; 505 device = SND_DEV_DSPHW_VPLAY; 506 max = SND_MAXVCHANS; 507 break; 508 case PCMDIR_REC: 509 dirs = "record"; 510 direction = PCMDIR_REC; 511 pnum = &d->reccount; 512 device = SND_DEV_DSPHW_REC; 513 max = SND_MAXHWCHAN; 514 break; 515 case PCMDIR_REC_VIRTUAL: 516 dirs = "virtual"; 517 direction = PCMDIR_REC; 518 pnum = &d->rvchancount; 519 device = SND_DEV_DSPHW_VREC; 520 max = SND_MAXVCHANS; 521 break; 522 default:
|
527 pcm_unlock(d); 528 return NULL;
| 523 return (NULL);
|
529 } 530 531 chan = (num == -1) ? 0 : num; 532
| 524 } 525 526 chan = (num == -1) ? 0 : num; 527
|
533 if (*pnum >= max || chan >= max) { 534 pcm_unlock(d); 535 return NULL; 536 }
| 528 if (*pnum >= max || chan >= max) 529 return (NULL);
|
537 538 rpnum = 0; 539 540 CHN_FOREACH(ch, d, channels.pcm) { 541 if (CHN_DEV(ch) != device) 542 continue; 543 if (chan == CHN_CHAN(ch)) { 544 if (num != -1) { 545 device_printf(d->dev, 546 "channel num=%d allocated!\n", chan);
| 530 531 rpnum = 0; 532 533 CHN_FOREACH(ch, d, channels.pcm) { 534 if (CHN_DEV(ch) != device) 535 continue; 536 if (chan == CHN_CHAN(ch)) { 537 if (num != -1) { 538 device_printf(d->dev, 539 "channel num=%d allocated!\n", chan);
|
547 pcm_unlock(d); 548 return NULL;
| 540 return (NULL);
|
549 } 550 chan++; 551 if (chan >= max) { 552 device_printf(d->dev, 553 "chan=%d > %d\n", chan, max);
| 541 } 542 chan++; 543 if (chan >= max) { 544 device_printf(d->dev, 545 "chan=%d > %d\n", chan, max);
|
554 pcm_unlock(d); 555 return NULL;
| 546 return (NULL);
|
556 } 557 } 558 rpnum++; 559 } 560 561 if (*pnum != rpnum) { 562 device_printf(d->dev, 563 "%s(): WARNING: pnum screwed : dirs=%s pnum=%d rpnum=%d\n", 564 __func__, dirs, *pnum, rpnum);
| 547 } 548 } 549 rpnum++; 550 } 551 552 if (*pnum != rpnum) { 553 device_printf(d->dev, 554 "%s(): WARNING: pnum screwed : dirs=%s pnum=%d rpnum=%d\n", 555 __func__, dirs, *pnum, rpnum);
|
565 pcm_unlock(d); 566 return NULL;
| 556 return (NULL);
|
567 } 568 569 udc = snd_mkunit(device_get_unit(d->dev), device, chan); 570 devname = dsp_unit2name(buf, sizeof(buf), udc); 571 572 if (devname == NULL) { 573 device_printf(d->dev, 574 "Failed to query device name udc=0x%08x\n", udc);
| 557 } 558 559 udc = snd_mkunit(device_get_unit(d->dev), device, chan); 560 devname = dsp_unit2name(buf, sizeof(buf), udc); 561 562 if (devname == NULL) { 563 device_printf(d->dev, 564 "Failed to query device name udc=0x%08x\n", udc);
|
575 pcm_unlock(d); 576 return NULL;
| 565 return (NULL);
|
577 } 578
| 566 } 567
|
579 (*pnum)++;
| |
580 pcm_unlock(d);
| 568 pcm_unlock(d);
|
581
| |
582 ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); 583 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO); 584 ch->unit = udc; 585 ch->pid = -1; 586 ch->parentsnddev = d; 587 ch->parentchannel = parent; 588 ch->dev = d->dev; 589 ch->trigger = PCMTRIG_STOP; 590 snprintf(ch->name, sizeof(ch->name), "%s:%s:%s", 591 device_get_nameunit(ch->dev), dirs, devname); 592 593 err = chn_init(ch, devinfo, dir, direction);
| 569 ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); 570 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO); 571 ch->unit = udc; 572 ch->pid = -1; 573 ch->parentsnddev = d; 574 ch->parentchannel = parent; 575 ch->dev = d->dev; 576 ch->trigger = PCMTRIG_STOP; 577 snprintf(ch->name, sizeof(ch->name), "%s:%s:%s", 578 device_get_nameunit(ch->dev), dirs, devname); 579 580 err = chn_init(ch, devinfo, dir, direction);
|
| 581 pcm_lock(d);
|
594 if (err) { 595 device_printf(d->dev, "chn_init(%s) failed: err = %d\n", 596 ch->name, err); 597 kobj_delete(ch->methods, M_DEVBUF); 598 free(ch, M_DEVBUF);
| 582 if (err) { 583 device_printf(d->dev, "chn_init(%s) failed: err = %d\n", 584 ch->name, err); 585 kobj_delete(ch->methods, M_DEVBUF); 586 free(ch, M_DEVBUF);
|
599 pcm_lock(d); 600 (*pnum)--; 601 pcm_unlock(d); 602 603 return NULL;
| 587 return (NULL);
|
604 } 605
| 588 } 589
|
606 return ch;
| 590 return (ch);
|
607} 608 609int 610pcm_chn_destroy(struct pcm_channel *ch) 611{ 612 struct snddev_info *d; 613 int err; 614 615 d = ch->parentsnddev;
| 591} 592 593int 594pcm_chn_destroy(struct pcm_channel *ch) 595{ 596 struct snddev_info *d; 597 int err; 598 599 d = ch->parentsnddev;
|
| 600 PCM_BUSYASSERT(d); 601
|
616 err = chn_kill(ch); 617 if (err) {
| 602 err = chn_kill(ch); 603 if (err) {
|
618 device_printf(d->dev, "chn_kill(%s) failed, err = %d\n", ch->name, err); 619 return err;
| 604 device_printf(ch->dev, "chn_kill(%s) failed, err = %d\n", 605 ch->name, err); 606 return (err);
|
620 } 621 622 kobj_delete(ch->methods, M_DEVBUF); 623 free(ch, M_DEVBUF); 624
| 607 } 608 609 kobj_delete(ch->methods, M_DEVBUF); 610 free(ch, M_DEVBUF); 611
|
625 return 0;
| 612 return (0);
|
626} 627 628int 629pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch) 630{ 631 struct pcm_channel *tmp, *after; 632 int num; 633
| 613} 614 615int 616pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch) 617{ 618 struct pcm_channel *tmp, *after; 619 int num; 620
|
634 pcm_lock(d); 635
| 621 PCM_BUSYASSERT(d); 622 snd_mtxassert(d->lock);
|
636 KASSERT(ch != NULL && (ch->direction == PCMDIR_PLAY || 637 ch->direction == PCMDIR_REC), ("Invalid pcm channel")); 638 639 after = NULL; 640 tmp = NULL; 641 num = 0; 642 643 /* 644 * Look for possible device collision. 645 */ 646 CHN_FOREACH(tmp, d, channels.pcm) { 647 if (tmp->unit == ch->unit) { 648 device_printf(d->dev, "%s(): Device collision " 649 "old=%p new=%p devunit=0x%08x\n", 650 __func__, tmp, ch, ch->unit);
| 623 KASSERT(ch != NULL && (ch->direction == PCMDIR_PLAY || 624 ch->direction == PCMDIR_REC), ("Invalid pcm channel")); 625 626 after = NULL; 627 tmp = NULL; 628 num = 0; 629 630 /* 631 * Look for possible device collision. 632 */ 633 CHN_FOREACH(tmp, d, channels.pcm) { 634 if (tmp->unit == ch->unit) { 635 device_printf(d->dev, "%s(): Device collision " 636 "old=%p new=%p devunit=0x%08x\n", 637 __func__, tmp, ch, ch->unit);
|
651 pcm_unlock(d); 652 return ENODEV;
| 638 return (ENODEV);
|
653 } 654 if (CHN_DEV(tmp) < CHN_DEV(ch)) { 655 if (num == 0) 656 after = tmp; 657 continue; 658 } else if (CHN_DEV(tmp) > CHN_DEV(ch)) 659 break; 660 num++; 661 if (CHN_CHAN(tmp) < CHN_CHAN(ch)) 662 after = tmp; 663 else if (CHN_CHAN(tmp) > CHN_CHAN(ch)) 664 break; 665 } 666 667 if (after != NULL) { 668 CHN_INSERT_AFTER(after, ch, channels.pcm); 669 } else { 670 CHN_INSERT_HEAD(d, ch, channels.pcm); 671 } 672
| 639 } 640 if (CHN_DEV(tmp) < CHN_DEV(ch)) { 641 if (num == 0) 642 after = tmp; 643 continue; 644 } else if (CHN_DEV(tmp) > CHN_DEV(ch)) 645 break; 646 num++; 647 if (CHN_CHAN(tmp) < CHN_CHAN(ch)) 648 after = tmp; 649 else if (CHN_CHAN(tmp) > CHN_CHAN(ch)) 650 break; 651 } 652 653 if (after != NULL) { 654 CHN_INSERT_AFTER(after, ch, channels.pcm); 655 } else { 656 CHN_INSERT_HEAD(d, ch, channels.pcm); 657 } 658
|
| 659 switch (CHN_DEV(ch)) { 660 case SND_DEV_DSPHW_PLAY: 661 d->playcount++; 662 break; 663 case SND_DEV_DSPHW_VPLAY: 664 d->pvchancount++; 665 break; 666 case SND_DEV_DSPHW_REC: 667 d->reccount++; 668 break; 669 case SND_DEV_DSPHW_VREC: 670 d->rvchancount++; 671 break; 672 default: 673 break; 674 } 675
|
673 d->devcount++;
| 676 d->devcount++;
|
674 pcm_unlock(d);
| |
675
| 677
|
676 return 0;
| 678 return (0);
|
677} 678 679int 680pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch) 681{ 682 struct pcm_channel *tmp; 683
| 679} 680 681int 682pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch) 683{ 684 struct pcm_channel *tmp; 685
|
| 686 PCM_BUSYASSERT(d); 687 snd_mtxassert(d->lock); 688
|
684 tmp = NULL; 685 686 CHN_FOREACH(tmp, d, channels.pcm) { 687 if (tmp == ch) 688 break; 689 } 690 691 if (tmp != ch)
| 689 tmp = NULL; 690 691 CHN_FOREACH(tmp, d, channels.pcm) { 692 if (tmp == ch) 693 break; 694 } 695 696 if (tmp != ch)
|
692 return EINVAL;
| 697 return (EINVAL);
|
693 694 CHN_REMOVE(d, ch, channels.pcm);
| 698 699 CHN_REMOVE(d, ch, channels.pcm);
|
| 700
|
695 switch (CHN_DEV(ch)) { 696 case SND_DEV_DSPHW_PLAY: 697 d->playcount--; 698 break; 699 case SND_DEV_DSPHW_VPLAY: 700 d->pvchancount--; 701 break; 702 case SND_DEV_DSPHW_REC: 703 d->reccount--; 704 break; 705 case SND_DEV_DSPHW_VREC: 706 d->rvchancount--; 707 break; 708 default: 709 break; 710 } 711
| 701 switch (CHN_DEV(ch)) { 702 case SND_DEV_DSPHW_PLAY: 703 d->playcount--; 704 break; 705 case SND_DEV_DSPHW_VPLAY: 706 d->pvchancount--; 707 break; 708 case SND_DEV_DSPHW_REC: 709 d->reccount--; 710 break; 711 case SND_DEV_DSPHW_VREC: 712 d->rvchancount--; 713 break; 714 default: 715 break; 716 } 717
|
712 return 0;
| 718 d->devcount--; 719 720 return (0);
|
713} 714 715int 716pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 717{ 718 struct snddev_info *d = device_get_softc(dev); 719 struct pcm_channel *ch; 720 int err; 721
| 721} 722 723int 724pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 725{ 726 struct snddev_info *d = device_get_softc(dev); 727 struct pcm_channel *ch; 728 int err; 729
|
| 730 PCM_BUSYASSERT(d); 731 732 pcm_lock(d);
|
722 ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo); 723 if (!ch) {
| 733 ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo); 734 if (!ch) {
|
724 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", cls->name, dir, devinfo); 725 return ENODEV;
| 735 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", 736 cls->name, dir, devinfo); 737 pcm_unlock(d); 738 return (ENODEV);
|
726 } 727 728 err = pcm_chn_add(d, ch);
| 739 } 740 741 err = pcm_chn_add(d, ch);
|
| 742 pcm_unlock(d);
|
729 if (err) {
| 743 if (err) {
|
730 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", ch->name, err);
| 744 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", 745 ch->name, err);
|
731 pcm_chn_destroy(ch);
| 746 pcm_chn_destroy(ch);
|
732 return err;
| |
733 } 734
| 747 } 748
|
735 return err;
| 749 return (err);
|
736} 737 738static int 739pcm_killchan(device_t dev) 740{ 741 struct snddev_info *d = device_get_softc(dev); 742 struct pcm_channel *ch;
| 750} 751 752static int 753pcm_killchan(device_t dev) 754{ 755 struct snddev_info *d = device_get_softc(dev); 756 struct pcm_channel *ch;
|
743 int error = 0;
| 757 int error;
|
744
| 758
|
| 759 PCM_BUSYASSERT(d); 760
|
745 ch = CHN_FIRST(d, channels.pcm); 746
| 761 ch = CHN_FIRST(d, channels.pcm); 762
|
| 763 pcm_lock(d);
|
747 error = pcm_chn_remove(d, ch);
| 764 error = pcm_chn_remove(d, ch);
|
| 765 pcm_unlock(d);
|
748 if (error) 749 return (error); 750 return (pcm_chn_destroy(ch)); 751} 752 753int 754pcm_setstatus(device_t dev, char *str) 755{ 756 struct snddev_info *d = device_get_softc(dev); 757
| 766 if (error) 767 return (error); 768 return (pcm_chn_destroy(ch)); 769} 770 771int 772pcm_setstatus(device_t dev, char *str) 773{ 774 struct snddev_info *d = device_get_softc(dev); 775
|
758 pcm_setmaxautovchans(d, snd_maxautovchans);
| 776 PCM_BUSYASSERT(d);
|
759
| 777
|
760 pcm_lock(d);
| 778 if (d->playcount == 0 || d->reccount == 0) 779 d->flags |= SD_F_SIMPLEX;
|
761
| 780
|
| 781 if ((d->playcount > 0 || d->reccount > 0) && 782 !(d->flags & SD_F_AUTOVCHAN)) { 783 d->flags |= SD_F_AUTOVCHAN; 784 vchan_initsys(dev); 785 } 786 787 pcm_setmaxautovchans(d, snd_maxautovchans); 788
|
762 strlcpy(d->status, str, SND_STATUSLEN); 763
| 789 strlcpy(d->status, str, SND_STATUSLEN); 790
|
| 791 pcm_lock(d); 792
|
764 /* Last stage, enable cloning. */
| 793 /* Last stage, enable cloning. */
|
765 if (d->clones != NULL) {
| 794 if (d->clones != NULL)
|
766 (void)snd_clone_enable(d->clones);
| 795 (void)snd_clone_enable(d->clones);
|
767 }
| |
768
| 796
|
| 797 /* Done, we're ready.. */ 798 d->flags |= SD_F_REGISTERED; 799 800 PCM_RELEASE(d); 801
|
769 pcm_unlock(d); 770
| 802 pcm_unlock(d); 803
|
771 return 0;
| 804 return (0);
|
772} 773 774uint32_t 775pcm_getflags(device_t dev) 776{ 777 struct snddev_info *d = device_get_softc(dev); 778 779 return d->flags; 780} 781 782void 783pcm_setflags(device_t dev, uint32_t val) 784{ 785 struct snddev_info *d = device_get_softc(dev); 786 787 d->flags = val; 788} 789 790void * 791pcm_getdevinfo(device_t dev) 792{ 793 struct snddev_info *d = device_get_softc(dev); 794 795 return d->devinfo; 796} 797 798unsigned int 799pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) 800{ 801 struct snddev_info *d = device_get_softc(dev); 802 int sz, x; 803 804 sz = 0; 805 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 806 x = sz; 807 RANGE(sz, minbufsz, maxbufsz); 808 if (x != sz) 809 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz); 810 x = minbufsz; 811 while (x < sz) 812 x <<= 1; 813 if (x > sz) 814 x >>= 1; 815 if (x != sz) { 816 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 817 sz = x; 818 } 819 } else { 820 sz = deflt; 821 } 822 823 d->bufsz = sz; 824 825 return sz; 826} 827 828#if defined(SND_DYNSYSCTL) && defined(SND_DEBUG) 829static int 830sysctl_dev_pcm_clone_flags(SYSCTL_HANDLER_ARGS) 831{ 832 struct snddev_info *d; 833 uint32_t flags; 834 int err; 835 836 d = oidp->oid_arg1;
| 805} 806 807uint32_t 808pcm_getflags(device_t dev) 809{ 810 struct snddev_info *d = device_get_softc(dev); 811 812 return d->flags; 813} 814 815void 816pcm_setflags(device_t dev, uint32_t val) 817{ 818 struct snddev_info *d = device_get_softc(dev); 819 820 d->flags = val; 821} 822 823void * 824pcm_getdevinfo(device_t dev) 825{ 826 struct snddev_info *d = device_get_softc(dev); 827 828 return d->devinfo; 829} 830 831unsigned int 832pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) 833{ 834 struct snddev_info *d = device_get_softc(dev); 835 int sz, x; 836 837 sz = 0; 838 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 839 x = sz; 840 RANGE(sz, minbufsz, maxbufsz); 841 if (x != sz) 842 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz); 843 x = minbufsz; 844 while (x < sz) 845 x <<= 1; 846 if (x > sz) 847 x >>= 1; 848 if (x != sz) { 849 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 850 sz = x; 851 } 852 } else { 853 sz = deflt; 854 } 855 856 d->bufsz = sz; 857 858 return sz; 859} 860 861#if defined(SND_DYNSYSCTL) && defined(SND_DEBUG) 862static int 863sysctl_dev_pcm_clone_flags(SYSCTL_HANDLER_ARGS) 864{ 865 struct snddev_info *d; 866 uint32_t flags; 867 int err; 868 869 d = oidp->oid_arg1;
|
837 if (d == NULL || d->clones == NULL)
| 870 if (!PCM_REGISTERED(d) || d->clones == NULL)
|
838 return (ENODEV); 839
| 871 return (ENODEV); 872
|
840 pcm_lock(d);
| 873 PCM_ACQUIRE_QUICK(d); 874
|
841 flags = snd_clone_getflags(d->clones);
| 875 flags = snd_clone_getflags(d->clones);
|
842 pcm_unlock(d);
| |
843 err = sysctl_handle_int(oidp, &flags, 0, req); 844 845 if (err == 0 && req->newptr != NULL) {
| 876 err = sysctl_handle_int(oidp, &flags, 0, req); 877 878 if (err == 0 && req->newptr != NULL) {
|
846 if ((flags & ~SND_CLONE_MASK))
| 879 if (flags & ~SND_CLONE_MASK)
|
847 err = EINVAL;
| 880 err = EINVAL;
|
848 else { 849 pcm_lock(d);
| 881 else
|
850 (void)snd_clone_setflags(d->clones, flags);
| 882 (void)snd_clone_setflags(d->clones, flags);
|
851 pcm_unlock(d); 852 }
| |
853 } 854
| 883 } 884
|
| 885 PCM_RELEASE_QUICK(d); 886
|
855 return (err); 856} 857 858static int 859sysctl_dev_pcm_clone_deadline(SYSCTL_HANDLER_ARGS) 860{ 861 struct snddev_info *d; 862 int err, deadline; 863 864 d = oidp->oid_arg1;
| 887 return (err); 888} 889 890static int 891sysctl_dev_pcm_clone_deadline(SYSCTL_HANDLER_ARGS) 892{ 893 struct snddev_info *d; 894 int err, deadline; 895 896 d = oidp->oid_arg1;
|
865 if (d == NULL || d->clones == NULL)
| 897 if (!PCM_REGISTERED(d) || d->clones == NULL)
|
866 return (ENODEV); 867
| 898 return (ENODEV); 899
|
868 pcm_lock(d);
| 900 PCM_ACQUIRE_QUICK(d); 901
|
869 deadline = snd_clone_getdeadline(d->clones);
| 902 deadline = snd_clone_getdeadline(d->clones);
|
870 pcm_unlock(d);
| |
871 err = sysctl_handle_int(oidp, &deadline, 0, req); 872 873 if (err == 0 && req->newptr != NULL) { 874 if (deadline < 0) 875 err = EINVAL;
| 903 err = sysctl_handle_int(oidp, &deadline, 0, req); 904 905 if (err == 0 && req->newptr != NULL) { 906 if (deadline < 0) 907 err = EINVAL;
|
876 else { 877 pcm_lock(d);
| 908 else
|
878 (void)snd_clone_setdeadline(d->clones, deadline);
| 909 (void)snd_clone_setdeadline(d->clones, deadline);
|
879 pcm_unlock(d); 880 }
| |
881 } 882
| 910 } 911
|
| 912 PCM_RELEASE_QUICK(d); 913
|
883 return (err); 884} 885 886static int 887sysctl_dev_pcm_clone_gc(SYSCTL_HANDLER_ARGS) 888{ 889 struct snddev_info *d; 890 int err, val; 891 892 d = oidp->oid_arg1;
| 914 return (err); 915} 916 917static int 918sysctl_dev_pcm_clone_gc(SYSCTL_HANDLER_ARGS) 919{ 920 struct snddev_info *d; 921 int err, val; 922 923 d = oidp->oid_arg1;
|
893 if (d == NULL || d->clones == NULL)
| 924 if (!PCM_REGISTERED(d) || d->clones == NULL)
|
894 return (ENODEV); 895 896 val = 0; 897 err = sysctl_handle_int(oidp, &val, 0, req); 898 899 if (err == 0 && req->newptr != NULL && val != 0) {
| 925 return (ENODEV); 926 927 val = 0; 928 err = sysctl_handle_int(oidp, &val, 0, req); 929 930 if (err == 0 && req->newptr != NULL && val != 0) {
|
900 pcm_lock(d); 901 (void)snd_clone_gc(d->clones); 902 pcm_unlock(d);
| 931 PCM_ACQUIRE_QUICK(d); 932 val = snd_clone_gc(d->clones); 933 PCM_RELEASE_QUICK(d); 934 if (bootverbose != 0 || snd_verbose > 3) 935 device_printf(d->dev, "clone gc: pruned=%d\n", val);
|
903 } 904 905 return (err); 906} 907 908static int 909sysctl_hw_snd_clone_gc(SYSCTL_HANDLER_ARGS) 910{ 911 struct snddev_info *d; 912 int i, err, val; 913 914 val = 0; 915 err = sysctl_handle_int(oidp, &val, 0, req); 916 917 if (err == 0 && req->newptr != NULL && val != 0) { 918 for (i = 0; pcm_devclass != NULL && 919 i < devclass_get_maxunit(pcm_devclass); i++) { 920 d = devclass_get_softc(pcm_devclass, i);
| 936 } 937 938 return (err); 939} 940 941static int 942sysctl_hw_snd_clone_gc(SYSCTL_HANDLER_ARGS) 943{ 944 struct snddev_info *d; 945 int i, err, val; 946 947 val = 0; 948 err = sysctl_handle_int(oidp, &val, 0, req); 949 950 if (err == 0 && req->newptr != NULL && val != 0) { 951 for (i = 0; pcm_devclass != NULL && 952 i < devclass_get_maxunit(pcm_devclass); i++) { 953 d = devclass_get_softc(pcm_devclass, i);
|
921 if (d == NULL || d->clones == NULL)
| 954 if (!PCM_REGISTERED(d) || d->clones == NULL)
|
922 continue;
| 955 continue;
|
923 pcm_lock(d); 924 (void)snd_clone_gc(d->clones); 925 pcm_unlock(d);
| 956 PCM_ACQUIRE_QUICK(d); 957 val = snd_clone_gc(d->clones); 958 PCM_RELEASE_QUICK(d); 959 if (bootverbose != 0 || snd_verbose > 3) 960 device_printf(d->dev, "clone gc: pruned=%d\n", 961 val);
|
926 } 927 } 928 929 return (err); 930} 931SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc, CTLTYPE_INT | CTLFLAG_RW, 932 0, sizeof(int), sysctl_hw_snd_clone_gc, "I", 933 "global clone garbage collector"); 934#endif 935 936int 937pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 938{ 939 struct snddev_info *d; 940 941 if (pcm_veto_load) { 942 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 943 944 return EINVAL; 945 } 946 947 if (device_get_unit(dev) > PCMMAXUNIT) { 948 device_printf(dev, "PCMMAXUNIT reached : unit=%d > %d\n", 949 device_get_unit(dev), PCMMAXUNIT); 950 device_printf(dev, 951 "Use 'hw.snd.maxunit' tunable to raise the limit.\n"); 952 return ENODEV; 953 } 954 955 d = device_get_softc(dev);
| 962 } 963 } 964 965 return (err); 966} 967SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc, CTLTYPE_INT | CTLFLAG_RW, 968 0, sizeof(int), sysctl_hw_snd_clone_gc, "I", 969 "global clone garbage collector"); 970#endif 971 972int 973pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 974{ 975 struct snddev_info *d; 976 977 if (pcm_veto_load) { 978 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 979 980 return EINVAL; 981 } 982 983 if (device_get_unit(dev) > PCMMAXUNIT) { 984 device_printf(dev, "PCMMAXUNIT reached : unit=%d > %d\n", 985 device_get_unit(dev), PCMMAXUNIT); 986 device_printf(dev, 987 "Use 'hw.snd.maxunit' tunable to raise the limit.\n"); 988 return ENODEV; 989 } 990 991 d = device_get_softc(dev);
|
| 992 d->dev = dev;
|
956 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev");
| 993 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev");
|
957
| 994 cv_init(&d->cv, device_get_nameunit(dev)); 995 PCM_ACQUIRE_QUICK(d); 996 dsp_cdevinfo_init(d);
|
958#if 0 959 /* 960 * d->flags should be cleared by the allocator of the softc. 961 * We cannot clear this field here because several devices set 962 * this flag before calling pcm_register(). 963 */ 964 d->flags = 0; 965#endif
| 997#if 0 998 /* 999 * d->flags should be cleared by the allocator of the softc. 1000 * We cannot clear this field here because several devices set 1001 * this flag before calling pcm_register(). 1002 */ 1003 d->flags = 0; 1004#endif
|
966 d->dev = dev;
| |
967 d->devinfo = devinfo; 968 d->devcount = 0; 969 d->reccount = 0; 970 d->playcount = 0; 971 d->pvchancount = 0; 972 d->rvchancount = 0; 973 d->pvchanrate = 0; 974 d->pvchanformat = 0; 975 d->rvchanrate = 0; 976 d->rvchanformat = 0; 977 d->inprog = 0; 978 979 /* 980 * Create clone manager, disabled by default. Cloning will be 981 * enabled during final stage of driver iniialization through 982 * pcm_setstatus(). 983 */
| 1005 d->devinfo = devinfo; 1006 d->devcount = 0; 1007 d->reccount = 0; 1008 d->playcount = 0; 1009 d->pvchancount = 0; 1010 d->rvchancount = 0; 1011 d->pvchanrate = 0; 1012 d->pvchanformat = 0; 1013 d->rvchanrate = 0; 1014 d->rvchanformat = 0; 1015 d->inprog = 0; 1016 1017 /* 1018 * Create clone manager, disabled by default. Cloning will be 1019 * enabled during final stage of driver iniialization through 1020 * pcm_setstatus(). 1021 */
|
984 d->clones = snd_clone_create( 985#ifdef SND_DIAGNOSTIC 986 d->lock, 987#endif 988 SND_U_MASK | SND_D_MASK, PCMMAXCLONE, SND_CLONE_DEADLINE_DEFAULT,
| 1022 d->clones = snd_clone_create(SND_U_MASK | SND_D_MASK, PCMMAXCLONE, 1023 SND_CLONE_DEADLINE_DEFAULT, SND_CLONE_WAITOK |
|
989 SND_CLONE_GC_ENABLE | SND_CLONE_GC_UNREF | 990 SND_CLONE_GC_LASTREF | SND_CLONE_GC_EXPIRED); 991 992 if (bootverbose != 0 || snd_verbose > 3) {
| 1024 SND_CLONE_GC_ENABLE | SND_CLONE_GC_UNREF | 1025 SND_CLONE_GC_LASTREF | SND_CLONE_GC_EXPIRED); 1026 1027 if (bootverbose != 0 || snd_verbose > 3) {
|
993 pcm_lock(d);
| |
994 device_printf(dev, 995 "clone manager: deadline=%dms flags=0x%08x\n", 996 snd_clone_getdeadline(d->clones), 997 snd_clone_getflags(d->clones));
| 1028 device_printf(dev, 1029 "clone manager: deadline=%dms flags=0x%08x\n", 1030 snd_clone_getdeadline(d->clones), 1031 snd_clone_getflags(d->clones));
|
998 pcm_unlock(d);
| |
999 } 1000 1001 CHN_INIT(d, channels.pcm); 1002 CHN_INIT(d, channels.pcm.busy); 1003
| 1032 } 1033 1034 CHN_INIT(d, channels.pcm); 1035 CHN_INIT(d, channels.pcm.busy); 1036
|
| 1037 /* XXX This is incorrect, but lets play along for now. */
|
1004 if ((numplay == 0 || numrec == 0) && numplay != numrec) 1005 d->flags |= SD_F_SIMPLEX; 1006 1007 d->fakechan = fkchan_setup(dev); 1008 chn_init(d->fakechan, NULL, 0, 0); 1009 1010#ifdef SND_DYNSYSCTL 1011 sysctl_ctx_init(&d->play_sysctl_ctx); 1012 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx, 1013 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play", 1014 CTLFLAG_RD, 0, "playback channels node"); 1015 sysctl_ctx_init(&d->rec_sysctl_ctx); 1016 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 1017 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 1018 CTLFLAG_RD, 0, "record channels node"); 1019 /* XXX: an user should be able to set this with a control tool, the 1020 sysadmin then needs min+max sysctls for this */ 1021 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 1022 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1023 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size"); 1024#ifdef SND_DEBUG 1025 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1026 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1027 "clone_flags", CTLTYPE_UINT | CTLFLAG_RW, d, sizeof(d), 1028 sysctl_dev_pcm_clone_flags, "IU", 1029 "clone flags"); 1030 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1031 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1032 "clone_deadline", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d), 1033 sysctl_dev_pcm_clone_deadline, "I", 1034 "clone expiration deadline (ms)"); 1035 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1036 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1037 "clone_gc", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d), 1038 sysctl_dev_pcm_clone_gc, "I", 1039 "clone garbage collector"); 1040#endif 1041#endif
| 1038 if ((numplay == 0 || numrec == 0) && numplay != numrec) 1039 d->flags |= SD_F_SIMPLEX; 1040 1041 d->fakechan = fkchan_setup(dev); 1042 chn_init(d->fakechan, NULL, 0, 0); 1043 1044#ifdef SND_DYNSYSCTL 1045 sysctl_ctx_init(&d->play_sysctl_ctx); 1046 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx, 1047 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play", 1048 CTLFLAG_RD, 0, "playback channels node"); 1049 sysctl_ctx_init(&d->rec_sysctl_ctx); 1050 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 1051 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 1052 CTLFLAG_RD, 0, "record channels node"); 1053 /* XXX: an user should be able to set this with a control tool, the 1054 sysadmin then needs min+max sysctls for this */ 1055 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 1056 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1057 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size"); 1058#ifdef SND_DEBUG 1059 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1060 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1061 "clone_flags", CTLTYPE_UINT | CTLFLAG_RW, d, sizeof(d), 1062 sysctl_dev_pcm_clone_flags, "IU", 1063 "clone flags"); 1064 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1065 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1066 "clone_deadline", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d), 1067 sysctl_dev_pcm_clone_deadline, "I", 1068 "clone expiration deadline (ms)"); 1069 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1070 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1071 "clone_gc", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d), 1072 sysctl_dev_pcm_clone_gc, "I", 1073 "clone garbage collector"); 1074#endif 1075#endif
|
| 1076
|
1042 if (numplay > 0 || numrec > 0) { 1043 d->flags |= SD_F_AUTOVCHAN; 1044 vchan_initsys(dev); 1045 } 1046 1047 sndstat_register(dev, d->status, sndstat_prepare_pcm);
| 1077 if (numplay > 0 || numrec > 0) { 1078 d->flags |= SD_F_AUTOVCHAN; 1079 vchan_initsys(dev); 1080 } 1081 1082 sndstat_register(dev, d->status, sndstat_prepare_pcm);
|
| 1083
|
1048 return 0; 1049} 1050 1051int 1052pcm_unregister(device_t dev) 1053{
| 1084 return 0; 1085} 1086 1087int 1088pcm_unregister(device_t dev) 1089{
|
1054 struct snddev_info *d = device_get_softc(dev);
| 1090 struct snddev_info *d;
|
1055 struct pcm_channel *ch; 1056 struct thread *td; 1057 int i; 1058 1059 td = curthread;
| 1091 struct pcm_channel *ch; 1092 struct thread *td; 1093 int i; 1094 1095 td = curthread;
|
| 1096 d = device_get_softc(dev);
|
1060
| 1097
|
| 1098 if (!PCM_ALIVE(d)) { 1099 device_printf(dev, "unregister: device not configured\n"); 1100 return (0); 1101 } 1102
|
1061 if (sndstat_acquire(td) != 0) { 1062 device_printf(dev, "unregister: sndstat busy\n");
| 1103 if (sndstat_acquire(td) != 0) { 1104 device_printf(dev, "unregister: sndstat busy\n");
|
1063 return EBUSY;
| 1105 return (EBUSY);
|
1064 } 1065 1066 pcm_lock(d);
| 1106 } 1107 1108 pcm_lock(d);
|
1067 if (d->inprog) {
| 1109 PCM_WAIT(d); 1110 1111 if (d->inprog != 0) {
|
1068 device_printf(dev, "unregister: operation in progress\n"); 1069 pcm_unlock(d); 1070 sndstat_release(td);
| 1112 device_printf(dev, "unregister: operation in progress\n"); 1113 pcm_unlock(d); 1114 sndstat_release(td);
|
1071 return EBUSY;
| 1115 return (EBUSY);
|
1072 } 1073
| 1116 } 1117
|
| 1118 PCM_ACQUIRE(d); 1119 pcm_unlock(d); 1120
|
1074 CHN_FOREACH(ch, d, channels.pcm) {
| 1121 CHN_FOREACH(ch, d, channels.pcm) {
|
| 1122 CHN_LOCK(ch);
|
1075 if (ch->refcount > 0) {
| 1123 if (ch->refcount > 0) {
|
1076 device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid); 1077 pcm_unlock(d);
| 1124 device_printf(dev, 1125 "unregister: channel %s busy (pid %d)\n", 1126 ch->name, ch->pid); 1127 CHN_UNLOCK(ch); 1128 PCM_RELEASE_QUICK(d);
|
1078 sndstat_release(td);
| 1129 sndstat_release(td);
|
1079 return EBUSY;
| 1130 return (EBUSY);
|
1080 }
| 1131 }
|
| 1132 CHN_UNLOCK(ch);
|
1081 } 1082 1083 if (d->clones != NULL) { 1084 if (snd_clone_busy(d->clones) != 0) { 1085 device_printf(dev, "unregister: clone busy\n");
| 1133 } 1134 1135 if (d->clones != NULL) { 1136 if (snd_clone_busy(d->clones) != 0) { 1137 device_printf(dev, "unregister: clone busy\n");
|
1086 pcm_unlock(d);
| 1138 PCM_RELEASE_QUICK(d);
|
1087 sndstat_release(td);
| 1139 sndstat_release(td);
|
1088 return EBUSY; 1089 } else
| 1140 return (EBUSY); 1141 } else { 1142 pcm_lock(d);
|
1090 (void)snd_clone_disable(d->clones);
| 1143 (void)snd_clone_disable(d->clones);
|
| 1144 pcm_unlock(d); 1145 }
|
1091 } 1092 1093 if (mixer_uninit(dev) == EBUSY) { 1094 device_printf(dev, "unregister: mixer busy\n");
| 1146 } 1147 1148 if (mixer_uninit(dev) == EBUSY) { 1149 device_printf(dev, "unregister: mixer busy\n");
|
| 1150 pcm_lock(d);
|
1095 if (d->clones != NULL) 1096 (void)snd_clone_enable(d->clones);
| 1151 if (d->clones != NULL) 1152 (void)snd_clone_enable(d->clones);
|
| 1153 PCM_RELEASE(d);
|
1097 pcm_unlock(d); 1098 sndstat_release(td);
| 1154 pcm_unlock(d); 1155 sndstat_release(td);
|
1099 return EBUSY;
| 1156 return (EBUSY);
|
1100 } 1101
| 1157 } 1158
|
| 1159 pcm_lock(d); 1160 d->flags |= SD_F_DYING; 1161 d->flags &= ~SD_F_REGISTERED; 1162 pcm_unlock(d); 1163 1164 /* 1165 * No lock being held, so this thing can be flushed without 1166 * stucking into devdrn oblivion. 1167 */
|
1102 if (d->clones != NULL) { 1103 snd_clone_destroy(d->clones); 1104 d->clones = NULL; 1105 } 1106
| 1168 if (d->clones != NULL) { 1169 snd_clone_destroy(d->clones); 1170 d->clones = NULL; 1171 } 1172
|
1107 d->devcount = 0; 1108
| |
1109#ifdef SND_DYNSYSCTL 1110 if (d->play_sysctl_tree != NULL) { 1111 sysctl_ctx_free(&d->play_sysctl_ctx); 1112 d->play_sysctl_tree = NULL; 1113 } 1114 if (d->rec_sysctl_tree != NULL) { 1115 sysctl_ctx_free(&d->rec_sysctl_ctx); 1116 d->rec_sysctl_tree = NULL; 1117 } 1118#endif 1119 1120 while (!CHN_EMPTY(d, channels.pcm)) 1121 pcm_killchan(dev); 1122 1123 chn_kill(d->fakechan); 1124 fkchan_kill(d->fakechan); 1125
| 1173#ifdef SND_DYNSYSCTL 1174 if (d->play_sysctl_tree != NULL) { 1175 sysctl_ctx_free(&d->play_sysctl_ctx); 1176 d->play_sysctl_tree = NULL; 1177 } 1178 if (d->rec_sysctl_tree != NULL) { 1179 sysctl_ctx_free(&d->rec_sysctl_ctx); 1180 d->rec_sysctl_tree = NULL; 1181 } 1182#endif 1183 1184 while (!CHN_EMPTY(d, channels.pcm)) 1185 pcm_killchan(dev); 1186 1187 chn_kill(d->fakechan); 1188 fkchan_kill(d->fakechan); 1189
|
| 1190 dsp_cdevinfo_flush(d); 1191 1192 pcm_lock(d); 1193 PCM_RELEASE(d); 1194 cv_destroy(&d->cv);
|
1126 pcm_unlock(d); 1127 snd_mtxfree(d->lock); 1128 sndstat_unregister(dev); 1129 sndstat_release(td); 1130 1131 if (snd_unit == device_get_unit(dev)) { 1132 /* 1133 * Reassign default unit to the next available dev. 1134 */ 1135 for (i = 0; pcm_devclass != NULL && 1136 i < devclass_get_maxunit(pcm_devclass); i++) {
| 1195 pcm_unlock(d); 1196 snd_mtxfree(d->lock); 1197 sndstat_unregister(dev); 1198 sndstat_release(td); 1199 1200 if (snd_unit == device_get_unit(dev)) { 1201 /* 1202 * Reassign default unit to the next available dev. 1203 */ 1204 for (i = 0; pcm_devclass != NULL && 1205 i < devclass_get_maxunit(pcm_devclass); i++) {
|
1137 if (device_get_unit(dev) == i || 1138 devclass_get_softc(pcm_devclass, i) == NULL)
| 1206 if (device_get_unit(dev) == i)
|
1139 continue;
| 1207 continue;
|
1140 snd_unit = i; 1141 break;
| 1208 d = devclass_get_softc(pcm_devclass, i); 1209 if (PCM_REGISTERED(d)) { 1210 snd_unit = i; 1211 break; 1212 }
|
1142 } 1143 } 1144
| 1213 } 1214 } 1215
|
1145 return 0;
| 1216 return (0);
|
1146} 1147 1148/************************************************************************/ 1149 1150static int 1151sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose) 1152{ 1153 struct snddev_info *d; 1154 struct pcm_channel *c; 1155 struct pcm_feeder *f; 1156 1157 if (verbose < 1) 1158 return 0; 1159 1160 d = device_get_softc(dev); 1161 if (!d) 1162 return ENXIO; 1163
| 1217} 1218 1219/************************************************************************/ 1220 1221static int 1222sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose) 1223{ 1224 struct snddev_info *d; 1225 struct pcm_channel *c; 1226 struct pcm_feeder *f; 1227 1228 if (verbose < 1) 1229 return 0; 1230 1231 d = device_get_softc(dev); 1232 if (!d) 1233 return ENXIO; 1234
|
1164 pcm_lock(d); 1165 if (!CHN_EMPTY(d, channels.pcm)) { 1166 sbuf_printf(s, " (%dp:%dv/%dr:%dv channels%s%s)", 1167 d->playcount, d->pvchancount, 1168 d->reccount, d->rvchancount, 1169 (d->flags & SD_F_SIMPLEX)? "" : " duplex",
| 1235 PCM_BUSYASSERT(d); 1236 1237 if (CHN_EMPTY(d, channels.pcm)) { 1238 sbuf_printf(s, " (mixer only)"); 1239 return 0; 1240 } 1241 1242 sbuf_printf(s, " (%dp:%dv/%dr:%dv channels%s%s)", 1243 d->playcount, d->pvchancount, 1244 d->reccount, d->rvchancount, 1245 (d->flags & SD_F_SIMPLEX)? "" : " duplex",
|
1170#ifdef USING_DEVFS
| 1246#ifdef USING_DEVFS
|
1171 (device_get_unit(dev) == snd_unit)? " default" : ""
| 1247 (device_get_unit(dev) == snd_unit)? " default" : ""
|
1172#else
| 1248#else
|
1173 ""
| 1249 ""
|
1174#endif
| 1250#endif
|
1175 );
| 1251 );
|
1176
| 1252
|
1177 if (verbose <= 1) { 1178 pcm_unlock(d); 1179 return 0; 1180 }
| 1253 if (verbose <= 1) 1254 return 0;
|
1181
| 1255
|
1182 CHN_FOREACH(c, d, channels.pcm) {
| 1256 CHN_FOREACH(c, d, channels.pcm) {
|
1183
| 1257
|
1184 KASSERT(c->bufhard != NULL && c->bufsoft != NULL, 1185 ("hosed pcm channel setup"));
| 1258 KASSERT(c->bufhard != NULL && c->bufsoft != NULL, 1259 ("hosed pcm channel setup"));
|
1186
| 1260
|
1187 sbuf_printf(s, "\n\t");
| 1261 sbuf_printf(s, "\n\t");
|
1188
| 1262
|
1189 /* it would be better to indent child channels */ 1190 sbuf_printf(s, "%s[%s]: ", c->parentchannel? c->parentchannel->name : "", c->name); 1191 sbuf_printf(s, "spd %d", c->speed); 1192 if (c->speed != sndbuf_getspd(c->bufhard)) 1193 sbuf_printf(s, "/%d", sndbuf_getspd(c->bufhard)); 1194 sbuf_printf(s, ", fmt 0x%08x", c->format); 1195 if (c->format != sndbuf_getfmt(c->bufhard)) 1196 sbuf_printf(s, "/0x%08x", sndbuf_getfmt(c->bufhard)); 1197 sbuf_printf(s, ", flags 0x%08x, 0x%08x", c->flags, c->feederflags); 1198 if (c->pid != -1) 1199 sbuf_printf(s, ", pid %d", c->pid); 1200 sbuf_printf(s, "\n\t");
| 1263 /* it would be better to indent child channels */ 1264 sbuf_printf(s, "%s[%s]: ", c->parentchannel? c->parentchannel->name : "", c->name); 1265 sbuf_printf(s, "spd %d", c->speed); 1266 if (c->speed != sndbuf_getspd(c->bufhard)) 1267 sbuf_printf(s, "/%d", sndbuf_getspd(c->bufhard)); 1268 sbuf_printf(s, ", fmt 0x%08x", c->format); 1269 if (c->format != sndbuf_getfmt(c->bufhard)) 1270 sbuf_printf(s, "/0x%08x", sndbuf_getfmt(c->bufhard)); 1271 sbuf_printf(s, ", flags 0x%08x, 0x%08x", c->flags, c->feederflags); 1272 if (c->pid != -1) 1273 sbuf_printf(s, ", pid %d", c->pid); 1274 sbuf_printf(s, "\n\t");
|
1201
| 1275
|
1202 sbuf_printf(s, "interrupts %d, ", c->interrupts); 1203 if (c->direction == PCMDIR_REC) 1204 sbuf_printf(s, "overruns %d, feed %u, hfree %d, sfree %d [b:%d/%d/%d|bs:%d/%d/%d]", 1205 c->xruns, c->feedcount, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft), 1206 sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard), 1207 sndbuf_getblkcnt(c->bufhard), 1208 sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft), 1209 sndbuf_getblkcnt(c->bufsoft)); 1210 else 1211 sbuf_printf(s, "underruns %d, feed %u, ready %d [b:%d/%d/%d|bs:%d/%d/%d]", 1212 c->xruns, c->feedcount, sndbuf_getready(c->bufsoft), 1213 sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard), 1214 sndbuf_getblkcnt(c->bufhard), 1215 sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft), 1216 sndbuf_getblkcnt(c->bufsoft)); 1217 sbuf_printf(s, "\n\t");
| 1276 sbuf_printf(s, "interrupts %d, ", c->interrupts); 1277 if (c->direction == PCMDIR_REC) 1278 sbuf_printf(s, "overruns %d, feed %u, hfree %d, sfree %d [b:%d/%d/%d|bs:%d/%d/%d]", 1279 c->xruns, c->feedcount, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft), 1280 sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard), 1281 sndbuf_getblkcnt(c->bufhard), 1282 sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft), 1283 sndbuf_getblkcnt(c->bufsoft)); 1284 else 1285 sbuf_printf(s, "underruns %d, feed %u, ready %d [b:%d/%d/%d|bs:%d/%d/%d]", 1286 c->xruns, c->feedcount, sndbuf_getready(c->bufsoft), 1287 sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard), 1288 sndbuf_getblkcnt(c->bufhard), 1289 sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft), 1290 sndbuf_getblkcnt(c->bufsoft)); 1291 sbuf_printf(s, "\n\t");
|
1218
| 1292
|
1219 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "hardware" : "userland");
| 1293 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "hardware" : "userland"); 1294 sbuf_printf(s, " -> "); 1295 f = c->feeder; 1296 while (f->source != NULL) 1297 f = f->source; 1298 while (f != NULL) { 1299 sbuf_printf(s, "%s", f->class->name); 1300 if (f->desc->type == FEEDER_FMT) 1301 sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out); 1302 if (f->desc->type == FEEDER_RATE) 1303 sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST)); 1304 if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER || 1305 f->desc->type == FEEDER_VOLUME) 1306 sbuf_printf(s, "(0x%08x)", f->desc->out);
|
1220 sbuf_printf(s, " -> ");
| 1307 sbuf_printf(s, " -> ");
|
1221 f = c->feeder; 1222 while (f->source != NULL) 1223 f = f->source; 1224 while (f != NULL) { 1225 sbuf_printf(s, "%s", f->class->name); 1226 if (f->desc->type == FEEDER_FMT) 1227 sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out); 1228 if (f->desc->type == FEEDER_RATE) 1229 sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST)); 1230 if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER || 1231 f->desc->type == FEEDER_VOLUME) 1232 sbuf_printf(s, "(0x%08x)", f->desc->out); 1233 sbuf_printf(s, " -> "); 1234 f = f->parent; 1235 } 1236 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "userland" : "hardware");
| 1308 f = f->parent;
|
1237 }
| 1309 }
|
1238 } else 1239 sbuf_printf(s, " (mixer only)"); 1240 pcm_unlock(d);
| 1310 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "userland" : "hardware"); 1311 }
|
1241 1242 return 0; 1243} 1244 1245/************************************************************************/ 1246 1247#ifdef SND_DYNSYSCTL 1248int 1249sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS) 1250{ 1251 struct snddev_info *d; 1252 int direction, vchancount;
| 1312 1313 return 0; 1314} 1315 1316/************************************************************************/ 1317 1318#ifdef SND_DYNSYSCTL 1319int 1320sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS) 1321{ 1322 struct snddev_info *d; 1323 int direction, vchancount;
|
1253 int err, newcnt;
| 1324 int err, cnt;
|
1254 1255 d = devclass_get_softc(pcm_devclass, VCHAN_SYSCTL_UNIT(oidp->oid_arg1));
| 1325 1326 d = devclass_get_softc(pcm_devclass, VCHAN_SYSCTL_UNIT(oidp->oid_arg1));
|
1256 if (d == NULL) 1257 return EINVAL;
| 1327 if (!PCM_REGISTERED(d) || !(d->flags & SD_F_AUTOVCHAN)) 1328 return (EINVAL);
|
1258
| 1329
|
| 1330 pcm_lock(d); 1331 PCM_WAIT(d); 1332
|
1259 switch (VCHAN_SYSCTL_DIR(oidp->oid_arg1)) { 1260 case VCHAN_PLAY:
| 1333 switch (VCHAN_SYSCTL_DIR(oidp->oid_arg1)) { 1334 case VCHAN_PLAY:
|
1261 if (d->playcount < 1) 1262 return ENODEV;
| |
1263 direction = PCMDIR_PLAY; 1264 vchancount = d->pvchancount;
| 1335 direction = PCMDIR_PLAY; 1336 vchancount = d->pvchancount;
|
| 1337 cnt = d->playcount;
|
1265 break; 1266 case VCHAN_REC:
| 1338 break; 1339 case VCHAN_REC:
|
1267 if (d->reccount < 1) 1268 return ENODEV;
| |
1269 direction = PCMDIR_REC; 1270 vchancount = d->rvchancount;
| 1340 direction = PCMDIR_REC; 1341 vchancount = d->rvchancount;
|
| 1342 cnt = d->reccount;
|
1271 break; 1272 default:
| 1343 break; 1344 default:
|
1273 return EINVAL;
| 1345 pcm_unlock(d); 1346 return (EINVAL);
|
1274 break; 1275 } 1276
| 1347 break; 1348 } 1349
|
1277 newcnt = vchancount; 1278 err = sysctl_handle_int(oidp, &newcnt, 0, req);
| 1350 if (cnt < 1) { 1351 pcm_unlock(d); 1352 return (ENODEV); 1353 }
|
1279
| 1354
|
1280 if (err == 0 && req->newptr != NULL && vchancount != newcnt) { 1281 if (newcnt < 0) 1282 newcnt = 0; 1283 if (newcnt > SND_MAXVCHANS) 1284 newcnt = SND_MAXVCHANS; 1285 err = pcm_setvchans(d, direction, newcnt, -1);
| 1355 PCM_ACQUIRE(d); 1356 pcm_unlock(d); 1357 1358 cnt = vchancount; 1359 err = sysctl_handle_int(oidp, &cnt, 0, req); 1360 1361 if (err == 0 && req->newptr != NULL && vchancount != cnt) { 1362 if (cnt < 0) 1363 cnt = 0; 1364 if (cnt > SND_MAXVCHANS) 1365 cnt = SND_MAXVCHANS; 1366 err = pcm_setvchans(d, direction, cnt, -1);
|
1286 } 1287
| 1367 } 1368
|
| 1369 PCM_RELEASE_QUICK(d); 1370
|
1288 return err; 1289} 1290#endif 1291 1292/************************************************************************/ 1293 1294/** 1295 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl. 1296 * 1297 * @param si Pointer to oss_sysinfo struct where information about the 1298 * sound subsystem will be written/copied. 1299 * 1300 * This routine returns information about the sound system, such as the 1301 * current OSS version, number of audio, MIDI, and mixer drivers, etc. 1302 * Also includes a bitmask showing which of the above types of devices 1303 * are open (busy). 1304 * 1305 * @note 1306 * Calling threads must not hold any snddev_info or pcm_channel locks. 1307 * 1308 * @author Ryan Beasley <ryanb@FreeBSD.org> 1309 */ 1310void 1311sound_oss_sysinfo(oss_sysinfo *si) 1312{ 1313 static char si_product[] = "FreeBSD native OSS ABI"; 1314 static char si_version[] = __XSTRING(__FreeBSD_version); 1315 static int intnbits = sizeof(int) * 8; /* Better suited as macro? 1316 Must pester a C guru. */ 1317 1318 struct snddev_info *d; 1319 struct pcm_channel *c; 1320 int i, j, ncards; 1321 1322 ncards = 0; 1323 1324 strlcpy(si->product, si_product, sizeof(si->product)); 1325 strlcpy(si->version, si_version, sizeof(si->version)); 1326 si->versionnum = SOUND_VERSION; 1327 1328 /* 1329 * Iterate over PCM devices and their channels, gathering up data 1330 * for the numaudios, ncards, and openedaudio fields. 1331 */ 1332 si->numaudios = 0; 1333 bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); 1334
| 1371 return err; 1372} 1373#endif 1374 1375/************************************************************************/ 1376 1377/** 1378 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl. 1379 * 1380 * @param si Pointer to oss_sysinfo struct where information about the 1381 * sound subsystem will be written/copied. 1382 * 1383 * This routine returns information about the sound system, such as the 1384 * current OSS version, number of audio, MIDI, and mixer drivers, etc. 1385 * Also includes a bitmask showing which of the above types of devices 1386 * are open (busy). 1387 * 1388 * @note 1389 * Calling threads must not hold any snddev_info or pcm_channel locks. 1390 * 1391 * @author Ryan Beasley <ryanb@FreeBSD.org> 1392 */ 1393void 1394sound_oss_sysinfo(oss_sysinfo *si) 1395{ 1396 static char si_product[] = "FreeBSD native OSS ABI"; 1397 static char si_version[] = __XSTRING(__FreeBSD_version); 1398 static int intnbits = sizeof(int) * 8; /* Better suited as macro? 1399 Must pester a C guru. */ 1400 1401 struct snddev_info *d; 1402 struct pcm_channel *c; 1403 int i, j, ncards; 1404 1405 ncards = 0; 1406 1407 strlcpy(si->product, si_product, sizeof(si->product)); 1408 strlcpy(si->version, si_version, sizeof(si->version)); 1409 si->versionnum = SOUND_VERSION; 1410 1411 /* 1412 * Iterate over PCM devices and their channels, gathering up data 1413 * for the numaudios, ncards, and openedaudio fields. 1414 */ 1415 si->numaudios = 0; 1416 bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); 1417
|
1335 if (pcm_devclass != NULL) { 1336 j = 0;
| 1418 j = 0;
|
1337
| 1419
|
1338 for (i = 0; pcm_devclass != NULL && 1339 i < devclass_get_maxunit(pcm_devclass); i++) { 1340 d = devclass_get_softc(pcm_devclass, i); 1341 if (!d) 1342 continue;
| 1420 for (i = 0; pcm_devclass != NULL && 1421 i < devclass_get_maxunit(pcm_devclass); i++) { 1422 d = devclass_get_softc(pcm_devclass, i); 1423 if (!PCM_REGISTERED(d)) 1424 continue;
|
1343
| 1425
|
1344 /* See note in function's docblock */ 1345 mtx_assert(d->lock, MA_NOTOWNED); 1346 /* Increment device's "operations in progress" */ 1347 pcm_inprog(d, 1); 1348 pcm_lock(d);
| 1426 /* XXX Need Giant magic entry ??? */
|
1349
| 1427
|
1350 si->numaudios += d->devcount; 1351 ++ncards;
| 1428 /* See note in function's docblock */ 1429 mtx_assert(d->lock, MA_NOTOWNED); 1430 pcm_lock(d);
|
1352
| 1431
|
1353 CHN_FOREACH(c, d, channels.pcm) { 1354 mtx_assert(c->lock, MA_NOTOWNED); 1355 CHN_LOCK(c); 1356 if (c->flags & CHN_F_BUSY) 1357 si->openedaudio[j / intnbits] |= 1358 (1 << (j % intnbits)); 1359 CHN_UNLOCK(c); 1360 j++; 1361 }
| 1432 si->numaudios += d->devcount; 1433 ++ncards;
|
1362
| 1434
|
1363 pcm_unlock(d); 1364 pcm_inprog(d, -1);
| 1435 CHN_FOREACH(c, d, channels.pcm) { 1436 mtx_assert(c->lock, MA_NOTOWNED); 1437 CHN_LOCK(c); 1438 if (c->flags & CHN_F_BUSY) 1439 si->openedaudio[j / intnbits] |= 1440 (1 << (j % intnbits)); 1441 CHN_UNLOCK(c); 1442 j++;
|
1365 }
| 1443 }
|
| 1444 1445 pcm_unlock(d);
|
1366 } 1367 1368 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ 1369 /** 1370 * @todo Collect num{midis,timers}. 1371 * 1372 * Need access to sound/midi/midi.c::midistat_lock in order 1373 * to safely touch midi_devices and get a head count of, well, 1374 * MIDI devices. midistat_lock is a global static (i.e., local to 1375 * midi.c), but midi_devices is a regular global; should the mutex 1376 * be publicized, or is there another way to get this information? 1377 * 1378 * NB: MIDI/sequencer stuff is currently on hold. 1379 */ 1380 si->nummidis = 0; 1381 si->numtimers = 0; 1382 si->nummixers = mixer_count; 1383 si->numcards = ncards; 1384 /* OSSv4 docs: Intended only for test apps; API doesn't 1385 really have much of a concept of cards. Shouldn't be 1386 used by applications. */ 1387 1388 /** 1389 * @todo Fill in "busy devices" fields. 1390 * 1391 * si->openedmidi = " MIDI devices 1392 */ 1393 bzero((void *)&si->openedmidi, sizeof(si->openedmidi)); 1394 1395 /* 1396 * Si->filler is a reserved array, but according to docs each 1397 * element should be set to -1. 1398 */ 1399 for (i = 0; i < sizeof(si->filler)/sizeof(si->filler[0]); i++) 1400 si->filler[i] = -1; 1401} 1402 1403/************************************************************************/ 1404 1405static int 1406sound_modevent(module_t mod, int type, void *data) 1407{ 1408 int ret; 1409#if 0 1410 return (midi_modevent(mod, type, data)); 1411#else 1412 ret = 0; 1413 1414 switch(type) { 1415 case MOD_LOAD: 1416 pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL); 1417 break; 1418 case MOD_UNLOAD: 1419 case MOD_SHUTDOWN: 1420 ret = sndstat_acquire(curthread); 1421 if (ret != 0) 1422 break; 1423 if (pcmsg_unrhdr != NULL) { 1424 delete_unrhdr(pcmsg_unrhdr); 1425 pcmsg_unrhdr = NULL; 1426 } 1427 break; 1428 default: 1429 ret = EOPNOTSUPP; 1430 } 1431 1432 return ret; 1433#endif 1434} 1435 1436DEV_MODULE(sound, sound_modevent, NULL); 1437MODULE_VERSION(sound, SOUND_MODVER);
| 1446 } 1447 1448 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ 1449 /** 1450 * @todo Collect num{midis,timers}. 1451 * 1452 * Need access to sound/midi/midi.c::midistat_lock in order 1453 * to safely touch midi_devices and get a head count of, well, 1454 * MIDI devices. midistat_lock is a global static (i.e., local to 1455 * midi.c), but midi_devices is a regular global; should the mutex 1456 * be publicized, or is there another way to get this information? 1457 * 1458 * NB: MIDI/sequencer stuff is currently on hold. 1459 */ 1460 si->nummidis = 0; 1461 si->numtimers = 0; 1462 si->nummixers = mixer_count; 1463 si->numcards = ncards; 1464 /* OSSv4 docs: Intended only for test apps; API doesn't 1465 really have much of a concept of cards. Shouldn't be 1466 used by applications. */ 1467 1468 /** 1469 * @todo Fill in "busy devices" fields. 1470 * 1471 * si->openedmidi = " MIDI devices 1472 */ 1473 bzero((void *)&si->openedmidi, sizeof(si->openedmidi)); 1474 1475 /* 1476 * Si->filler is a reserved array, but according to docs each 1477 * element should be set to -1. 1478 */ 1479 for (i = 0; i < sizeof(si->filler)/sizeof(si->filler[0]); i++) 1480 si->filler[i] = -1; 1481} 1482 1483/************************************************************************/ 1484 1485static int 1486sound_modevent(module_t mod, int type, void *data) 1487{ 1488 int ret; 1489#if 0 1490 return (midi_modevent(mod, type, data)); 1491#else 1492 ret = 0; 1493 1494 switch(type) { 1495 case MOD_LOAD: 1496 pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL); 1497 break; 1498 case MOD_UNLOAD: 1499 case MOD_SHUTDOWN: 1500 ret = sndstat_acquire(curthread); 1501 if (ret != 0) 1502 break; 1503 if (pcmsg_unrhdr != NULL) { 1504 delete_unrhdr(pcmsg_unrhdr); 1505 pcmsg_unrhdr = NULL; 1506 } 1507 break; 1508 default: 1509 ret = EOPNOTSUPP; 1510 } 1511 1512 return ret; 1513#endif 1514} 1515 1516DEV_MODULE(sound, sound_modevent, NULL); 1517MODULE_VERSION(sound, SOUND_MODVER);
|