sound.c (170289) | sound.c (170815) |
---|---|
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: --- 21 unchanged lines hidden (view full) --- 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: --- 21 unchanged lines hidden (view full) --- 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); --- 79 unchanged lines hidden (view full) --- 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); --- 79 unchanged lines hidden (view full) --- 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 --- 16 unchanged lines hidden (view full) --- 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 --- 16 unchanged lines hidden (view full) --- 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)) { --- 6 unchanged lines hidden (view full) --- 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)) { --- 6 unchanged lines hidden (view full) --- 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); --- 7 unchanged lines hidden (view full) --- 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); --- 7 unchanged lines hidden (view full) --- 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; --- 8 unchanged lines hidden (view full) --- 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; --- 8 unchanged lines hidden (view full) --- 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, --- 7 unchanged lines hidden (view full) --- 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, --- 7 unchanged lines hidden (view full) --- 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"); --- 11 unchanged lines hidden (view full) --- 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"); --- 11 unchanged lines hidden (view full) --- 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: --- 13 unchanged lines hidden (view full) --- 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: --- 13 unchanged lines hidden (view full) --- 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++; --- 4 unchanged lines hidden (view full) --- 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++; --- 4 unchanged lines hidden (view full) --- 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; --- 49 unchanged lines hidden (view full) --- 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; --- 49 unchanged lines hidden (view full) --- 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"); --- 14 unchanged lines hidden (view full) --- 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"); --- 14 unchanged lines hidden (view full) --- 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); --- 22 unchanged lines hidden (view full) --- 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); --- 22 unchanged lines hidden (view full) --- 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. --- 31 unchanged lines hidden (view full) --- 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. --- 31 unchanged lines hidden (view full) --- 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, --- 64 unchanged lines hidden --- | 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, --- 64 unchanged lines hidden --- |