Deleted Added
full compact
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 ---