1/* 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <dev/sound/pcm/sound.h> 29#include <dev/sound/pcm/vchan.h>
| 1/* 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <dev/sound/pcm/sound.h> 29#include <dev/sound/pcm/vchan.h>
|
| 30#include <dev/sound/pcm/dsp.h>
|
30#include <sys/sysctl.h> 31 32#include "feeder_if.h" 33
| 31#include <sys/sysctl.h> 32 33#include "feeder_if.h" 34
|
34SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/sound.c 124617 2004-01-17 10:37:11Z phk $");
| 35SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/sound.c 124740 2004-01-20 03:58:57Z matk $");
|
35 36devclass_t pcm_devclass; 37 38int pcm_veto_load = 1; 39 40#ifdef USING_DEVFS 41int snd_unit = 0; 42TUNABLE_INT("hw.snd.unit", &snd_unit); 43#endif 44 45int snd_maxautovchans = 0; 46TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans); 47 48SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver"); 49 50static int sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose); 51 52struct sysctl_ctx_list * 53snd_sysctl_tree(device_t dev) 54{ 55 struct snddev_info *d = device_get_softc(dev); 56 57 return &d->sysctl_tree; 58} 59 60struct sysctl_oid * 61snd_sysctl_tree_top(device_t dev) 62{ 63 struct snddev_info *d = device_get_softc(dev); 64 65 return d->sysctl_tree_top; 66} 67 68void * 69snd_mtxcreate(const char *desc, const char *type) 70{ 71#ifdef USING_MUTEX 72 struct mtx *m; 73 74 m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO); 75 if (m == NULL) 76 return NULL; 77 mtx_init(m, desc, type, MTX_DEF | MTX_RECURSE); 78 return m; 79#else 80 return (void *)0xcafebabe; 81#endif 82} 83 84void 85snd_mtxfree(void *m) 86{ 87#ifdef USING_MUTEX 88 struct mtx *mtx = m; 89 90 /* mtx_assert(mtx, MA_OWNED); */ 91 mtx_destroy(mtx); 92 free(mtx, M_DEVBUF); 93#endif 94} 95 96void 97snd_mtxassert(void *m) 98{ 99#ifdef USING_MUTEX 100#ifdef INVARIANTS 101 struct mtx *mtx = m; 102 103 mtx_assert(mtx, MA_OWNED); 104#endif 105#endif 106} 107/* 108void 109snd_mtxlock(void *m) 110{ 111#ifdef USING_MUTEX 112 struct mtx *mtx = m; 113 114 mtx_lock(mtx); 115#endif 116} 117 118void 119snd_mtxunlock(void *m) 120{ 121#ifdef USING_MUTEX 122 struct mtx *mtx = m; 123 124 mtx_unlock(mtx); 125#endif 126} 127*/ 128int 129snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 130{ 131#ifdef USING_MUTEX 132 flags &= INTR_MPSAFE; 133 flags |= INTR_TYPE_AV; 134#else 135 flags = INTR_TYPE_AV; 136#endif 137 return bus_setup_intr(dev, res, flags, hand, param, cookiep); 138} 139 140#ifndef PCM_DEBUG_MTX 141void 142pcm_lock(struct snddev_info *d) 143{ 144 snd_mtxlock(d->lock); 145} 146 147void 148pcm_unlock(struct snddev_info *d) 149{ 150 snd_mtxunlock(d->lock); 151} 152#endif 153 154struct pcm_channel * 155pcm_getfakechan(struct snddev_info *d) 156{ 157 return d->fakechan; 158} 159 160/* return a locked channel */ 161struct pcm_channel * 162pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid, int chnum) 163{ 164 struct pcm_channel *c; 165 struct snddev_channel *sce; 166 int err; 167 168 snd_mtxassert(d->lock); 169 170 /* scan for a free channel */ 171 SLIST_FOREACH(sce, &d->channels, link) { 172 c = sce->channel; 173 CHN_LOCK(c); 174 if ((c->direction == direction) && !(c->flags & CHN_F_BUSY)) { 175 if (chnum == -1 || c->num == chnum) { 176 c->flags |= CHN_F_BUSY; 177 c->pid = pid; 178 return c; 179 } 180 } 181 CHN_UNLOCK(c); 182 } 183 184 /* no channel available */ 185 if (direction == PCMDIR_PLAY) { 186 if ((d->vchancount > 0) && (d->vchancount < snd_maxautovchans)) { 187 /* try to create a vchan */ 188 SLIST_FOREACH(sce, &d->channels, link) { 189 c = sce->channel; 190 if (!SLIST_EMPTY(&c->children)) { 191 err = vchan_create(c); 192 if (!err) 193 return pcm_chnalloc(d, direction, pid, -1); 194 else 195 device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err); 196 } 197 } 198 } 199 } 200 201 return NULL; 202} 203 204/* release a locked channel and unlock it */ 205int 206pcm_chnrelease(struct pcm_channel *c) 207{ 208 CHN_LOCKASSERT(c); 209 c->flags &= ~CHN_F_BUSY; 210 c->pid = -1; 211 CHN_UNLOCK(c); 212 return 0; 213} 214 215int 216pcm_chnref(struct pcm_channel *c, int ref) 217{ 218 int r; 219 220 CHN_LOCKASSERT(c); 221 c->refcount += ref; 222 r = c->refcount; 223 return r; 224} 225 226int 227pcm_inprog(struct snddev_info *d, int delta) 228{ 229 int r; 230 231 if (delta == 0) 232 return d->inprog; 233 234 /* backtrace(); */ 235 pcm_lock(d); 236 d->inprog += delta; 237 r = d->inprog; 238 pcm_unlock(d); 239 return r; 240} 241 242static void 243pcm_setmaxautovchans(struct snddev_info *d, int num) 244{ 245 struct pcm_channel *c; 246 struct snddev_channel *sce; 247 int err, done; 248 249 if (num > 0 && d->vchancount == 0) { 250 SLIST_FOREACH(sce, &d->channels, link) { 251 c = sce->channel; 252 if ((c->direction == PCMDIR_PLAY) && !(c->flags & CHN_F_BUSY)) { 253 c->flags |= CHN_F_BUSY; 254 err = vchan_create(c); 255 if (err) { 256 device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err); 257 c->flags &= ~CHN_F_BUSY; 258 } 259 return; 260 } 261 } 262 } 263 if (num == 0 && d->vchancount > 0) { 264 done = 0; 265 while (!done) { 266 done = 1; 267 SLIST_FOREACH(sce, &d->channels, link) { 268 c = sce->channel; 269 if ((c->flags & CHN_F_VIRTUAL) && !(c->flags & CHN_F_BUSY)) { 270 done = 0; 271 snd_mtxlock(d->lock); 272 err = vchan_destroy(c); 273 snd_mtxunlock(d->lock); 274 if (err) 275 device_printf(d->dev, "vchan_destroy(%s) == %d\n", c->name, err); 276 break; /* restart */ 277 } 278 } 279 } 280 } 281} 282 283#ifdef USING_DEVFS 284static int 285sysctl_hw_snd_unit(SYSCTL_HANDLER_ARGS) 286{ 287 struct snddev_info *d; 288 int error, unit; 289 290 unit = snd_unit; 291 error = sysctl_handle_int(oidp, &unit, sizeof(unit), req); 292 if (error == 0 && req->newptr != NULL) { 293 if (unit < 0 || unit >= devclass_get_maxunit(pcm_devclass)) 294 return EINVAL; 295 d = devclass_get_softc(pcm_devclass, unit); 296 if (d == NULL || SLIST_EMPTY(&d->channels)) 297 return EINVAL; 298 snd_unit = unit; 299 } 300 return (error); 301} 302SYSCTL_PROC(_hw_snd, OID_AUTO, unit, CTLTYPE_INT | CTLFLAG_RW, 303 0, sizeof(int), sysctl_hw_snd_unit, "I", ""); 304#endif 305 306static int 307sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) 308{ 309 struct snddev_info *d; 310 int i, v, error; 311 312 v = snd_maxautovchans; 313 error = sysctl_handle_int(oidp, &v, sizeof(v), req); 314 if (error == 0 && req->newptr != NULL) { 315 if (v < 0 || v >= SND_MAXVCHANS) 316 return EINVAL; 317 if (v != snd_maxautovchans) { 318 for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) { 319 d = devclass_get_softc(pcm_devclass, i); 320 if (!d) 321 continue; 322 pcm_setmaxautovchans(d, v); 323 } 324 } 325 snd_maxautovchans = v; 326 } 327 return (error); 328} 329SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, CTLTYPE_INT | CTLFLAG_RW, 330 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", ""); 331 332struct pcm_channel * 333pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo) 334{ 335 struct pcm_channel *ch; 336 char *dirs; 337 int err, *pnum; 338 339 switch(dir) { 340 case PCMDIR_PLAY: 341 dirs = "play"; 342 pnum = &d->playcount; 343 break; 344 345 case PCMDIR_REC: 346 dirs = "record"; 347 pnum = &d->reccount; 348 break; 349 350 case PCMDIR_VIRTUAL: 351 dirs = "virtual"; 352 dir = PCMDIR_PLAY; 353 pnum = &d->vchancount; 354 break; 355 356 default: 357 return NULL; 358 } 359 360 ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); 361 if (!ch) 362 return NULL; 363 364 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK); 365 if (!ch->methods) { 366 free(ch, M_DEVBUF); 367 368 return NULL; 369 } 370 371 snd_mtxlock(d->lock); 372 ch->num = (*pnum)++; 373 snd_mtxunlock(d->lock); 374 375 ch->pid = -1; 376 ch->parentsnddev = d; 377 ch->parentchannel = parent; 378 ch->dev = d->dev; 379 snprintf(ch->name, 32, "%s:%s:%d", device_get_nameunit(ch->dev), dirs, ch->num); 380 381 err = chn_init(ch, devinfo, dir); 382 if (err) { 383 device_printf(d->dev, "chn_init(%s) failed: err = %d\n", ch->name, err); 384 kobj_delete(ch->methods, M_DEVBUF); 385 free(ch, M_DEVBUF); 386 snd_mtxlock(d->lock); 387 (*pnum)--; 388 snd_mtxunlock(d->lock); 389 390 return NULL; 391 } 392 393 return ch; 394} 395 396int 397pcm_chn_destroy(struct pcm_channel *ch) 398{ 399 struct snddev_info *d; 400 int err; 401 402 d = ch->parentsnddev; 403 err = chn_kill(ch); 404 if (err) { 405 device_printf(d->dev, "chn_kill(%s) failed, err = %d\n", ch->name, err); 406 return err; 407 } 408 409 kobj_delete(ch->methods, M_DEVBUF); 410 free(ch, M_DEVBUF); 411 412 return 0; 413} 414 415int
| 36 37devclass_t pcm_devclass; 38 39int pcm_veto_load = 1; 40 41#ifdef USING_DEVFS 42int snd_unit = 0; 43TUNABLE_INT("hw.snd.unit", &snd_unit); 44#endif 45 46int snd_maxautovchans = 0; 47TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans); 48 49SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver"); 50 51static int sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose); 52 53struct sysctl_ctx_list * 54snd_sysctl_tree(device_t dev) 55{ 56 struct snddev_info *d = device_get_softc(dev); 57 58 return &d->sysctl_tree; 59} 60 61struct sysctl_oid * 62snd_sysctl_tree_top(device_t dev) 63{ 64 struct snddev_info *d = device_get_softc(dev); 65 66 return d->sysctl_tree_top; 67} 68 69void * 70snd_mtxcreate(const char *desc, const char *type) 71{ 72#ifdef USING_MUTEX 73 struct mtx *m; 74 75 m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO); 76 if (m == NULL) 77 return NULL; 78 mtx_init(m, desc, type, MTX_DEF | MTX_RECURSE); 79 return m; 80#else 81 return (void *)0xcafebabe; 82#endif 83} 84 85void 86snd_mtxfree(void *m) 87{ 88#ifdef USING_MUTEX 89 struct mtx *mtx = m; 90 91 /* mtx_assert(mtx, MA_OWNED); */ 92 mtx_destroy(mtx); 93 free(mtx, M_DEVBUF); 94#endif 95} 96 97void 98snd_mtxassert(void *m) 99{ 100#ifdef USING_MUTEX 101#ifdef INVARIANTS 102 struct mtx *mtx = m; 103 104 mtx_assert(mtx, MA_OWNED); 105#endif 106#endif 107} 108/* 109void 110snd_mtxlock(void *m) 111{ 112#ifdef USING_MUTEX 113 struct mtx *mtx = m; 114 115 mtx_lock(mtx); 116#endif 117} 118 119void 120snd_mtxunlock(void *m) 121{ 122#ifdef USING_MUTEX 123 struct mtx *mtx = m; 124 125 mtx_unlock(mtx); 126#endif 127} 128*/ 129int 130snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 131{ 132#ifdef USING_MUTEX 133 flags &= INTR_MPSAFE; 134 flags |= INTR_TYPE_AV; 135#else 136 flags = INTR_TYPE_AV; 137#endif 138 return bus_setup_intr(dev, res, flags, hand, param, cookiep); 139} 140 141#ifndef PCM_DEBUG_MTX 142void 143pcm_lock(struct snddev_info *d) 144{ 145 snd_mtxlock(d->lock); 146} 147 148void 149pcm_unlock(struct snddev_info *d) 150{ 151 snd_mtxunlock(d->lock); 152} 153#endif 154 155struct pcm_channel * 156pcm_getfakechan(struct snddev_info *d) 157{ 158 return d->fakechan; 159} 160 161/* return a locked channel */ 162struct pcm_channel * 163pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid, int chnum) 164{ 165 struct pcm_channel *c; 166 struct snddev_channel *sce; 167 int err; 168 169 snd_mtxassert(d->lock); 170 171 /* scan for a free channel */ 172 SLIST_FOREACH(sce, &d->channels, link) { 173 c = sce->channel; 174 CHN_LOCK(c); 175 if ((c->direction == direction) && !(c->flags & CHN_F_BUSY)) { 176 if (chnum == -1 || c->num == chnum) { 177 c->flags |= CHN_F_BUSY; 178 c->pid = pid; 179 return c; 180 } 181 } 182 CHN_UNLOCK(c); 183 } 184 185 /* no channel available */ 186 if (direction == PCMDIR_PLAY) { 187 if ((d->vchancount > 0) && (d->vchancount < snd_maxautovchans)) { 188 /* try to create a vchan */ 189 SLIST_FOREACH(sce, &d->channels, link) { 190 c = sce->channel; 191 if (!SLIST_EMPTY(&c->children)) { 192 err = vchan_create(c); 193 if (!err) 194 return pcm_chnalloc(d, direction, pid, -1); 195 else 196 device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err); 197 } 198 } 199 } 200 } 201 202 return NULL; 203} 204 205/* release a locked channel and unlock it */ 206int 207pcm_chnrelease(struct pcm_channel *c) 208{ 209 CHN_LOCKASSERT(c); 210 c->flags &= ~CHN_F_BUSY; 211 c->pid = -1; 212 CHN_UNLOCK(c); 213 return 0; 214} 215 216int 217pcm_chnref(struct pcm_channel *c, int ref) 218{ 219 int r; 220 221 CHN_LOCKASSERT(c); 222 c->refcount += ref; 223 r = c->refcount; 224 return r; 225} 226 227int 228pcm_inprog(struct snddev_info *d, int delta) 229{ 230 int r; 231 232 if (delta == 0) 233 return d->inprog; 234 235 /* backtrace(); */ 236 pcm_lock(d); 237 d->inprog += delta; 238 r = d->inprog; 239 pcm_unlock(d); 240 return r; 241} 242 243static void 244pcm_setmaxautovchans(struct snddev_info *d, int num) 245{ 246 struct pcm_channel *c; 247 struct snddev_channel *sce; 248 int err, done; 249 250 if (num > 0 && d->vchancount == 0) { 251 SLIST_FOREACH(sce, &d->channels, link) { 252 c = sce->channel; 253 if ((c->direction == PCMDIR_PLAY) && !(c->flags & CHN_F_BUSY)) { 254 c->flags |= CHN_F_BUSY; 255 err = vchan_create(c); 256 if (err) { 257 device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err); 258 c->flags &= ~CHN_F_BUSY; 259 } 260 return; 261 } 262 } 263 } 264 if (num == 0 && d->vchancount > 0) { 265 done = 0; 266 while (!done) { 267 done = 1; 268 SLIST_FOREACH(sce, &d->channels, link) { 269 c = sce->channel; 270 if ((c->flags & CHN_F_VIRTUAL) && !(c->flags & CHN_F_BUSY)) { 271 done = 0; 272 snd_mtxlock(d->lock); 273 err = vchan_destroy(c); 274 snd_mtxunlock(d->lock); 275 if (err) 276 device_printf(d->dev, "vchan_destroy(%s) == %d\n", c->name, err); 277 break; /* restart */ 278 } 279 } 280 } 281 } 282} 283 284#ifdef USING_DEVFS 285static int 286sysctl_hw_snd_unit(SYSCTL_HANDLER_ARGS) 287{ 288 struct snddev_info *d; 289 int error, unit; 290 291 unit = snd_unit; 292 error = sysctl_handle_int(oidp, &unit, sizeof(unit), req); 293 if (error == 0 && req->newptr != NULL) { 294 if (unit < 0 || unit >= devclass_get_maxunit(pcm_devclass)) 295 return EINVAL; 296 d = devclass_get_softc(pcm_devclass, unit); 297 if (d == NULL || SLIST_EMPTY(&d->channels)) 298 return EINVAL; 299 snd_unit = unit; 300 } 301 return (error); 302} 303SYSCTL_PROC(_hw_snd, OID_AUTO, unit, CTLTYPE_INT | CTLFLAG_RW, 304 0, sizeof(int), sysctl_hw_snd_unit, "I", ""); 305#endif 306 307static int 308sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) 309{ 310 struct snddev_info *d; 311 int i, v, error; 312 313 v = snd_maxautovchans; 314 error = sysctl_handle_int(oidp, &v, sizeof(v), req); 315 if (error == 0 && req->newptr != NULL) { 316 if (v < 0 || v >= SND_MAXVCHANS) 317 return EINVAL; 318 if (v != snd_maxautovchans) { 319 for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) { 320 d = devclass_get_softc(pcm_devclass, i); 321 if (!d) 322 continue; 323 pcm_setmaxautovchans(d, v); 324 } 325 } 326 snd_maxautovchans = v; 327 } 328 return (error); 329} 330SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, CTLTYPE_INT | CTLFLAG_RW, 331 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", ""); 332 333struct pcm_channel * 334pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo) 335{ 336 struct pcm_channel *ch; 337 char *dirs; 338 int err, *pnum; 339 340 switch(dir) { 341 case PCMDIR_PLAY: 342 dirs = "play"; 343 pnum = &d->playcount; 344 break; 345 346 case PCMDIR_REC: 347 dirs = "record"; 348 pnum = &d->reccount; 349 break; 350 351 case PCMDIR_VIRTUAL: 352 dirs = "virtual"; 353 dir = PCMDIR_PLAY; 354 pnum = &d->vchancount; 355 break; 356 357 default: 358 return NULL; 359 } 360 361 ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); 362 if (!ch) 363 return NULL; 364 365 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK); 366 if (!ch->methods) { 367 free(ch, M_DEVBUF); 368 369 return NULL; 370 } 371 372 snd_mtxlock(d->lock); 373 ch->num = (*pnum)++; 374 snd_mtxunlock(d->lock); 375 376 ch->pid = -1; 377 ch->parentsnddev = d; 378 ch->parentchannel = parent; 379 ch->dev = d->dev; 380 snprintf(ch->name, 32, "%s:%s:%d", device_get_nameunit(ch->dev), dirs, ch->num); 381 382 err = chn_init(ch, devinfo, dir); 383 if (err) { 384 device_printf(d->dev, "chn_init(%s) failed: err = %d\n", ch->name, err); 385 kobj_delete(ch->methods, M_DEVBUF); 386 free(ch, M_DEVBUF); 387 snd_mtxlock(d->lock); 388 (*pnum)--; 389 snd_mtxunlock(d->lock); 390 391 return NULL; 392 } 393 394 return ch; 395} 396 397int 398pcm_chn_destroy(struct pcm_channel *ch) 399{ 400 struct snddev_info *d; 401 int err; 402 403 d = ch->parentsnddev; 404 err = chn_kill(ch); 405 if (err) { 406 device_printf(d->dev, "chn_kill(%s) failed, err = %d\n", ch->name, err); 407 return err; 408 } 409 410 kobj_delete(ch->methods, M_DEVBUF); 411 free(ch, M_DEVBUF); 412 413 return 0; 414} 415 416int
|
416pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev)
| 417pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
|
417{ 418 struct snddev_channel *sce, *tmp, *after;
| 418{ 419 struct snddev_channel *sce, *tmp, *after;
|
419 int unit = device_get_unit(d->dev); 420 int x = -1;
| 420 int device = device_get_unit(d->dev);
|
421
| 421
|
| 422 /* 423 * Note it's confusing nomenclature. 424 * dev_t 425 * device -> pcm_device 426 * unit -> pcm_channel 427 * channel -> snddev_channel 428 * device_t 429 * unit -> pcm_device 430 */ 431
|
422 sce = malloc(sizeof(*sce), M_DEVBUF, M_WAITOK | M_ZERO); 423 if (!sce) { 424 return ENOMEM; 425 } 426 427 snd_mtxlock(d->lock); 428 sce->channel = ch;
| 432 sce = malloc(sizeof(*sce), M_DEVBUF, M_WAITOK | M_ZERO); 433 if (!sce) { 434 return ENOMEM; 435 } 436 437 snd_mtxlock(d->lock); 438 sce->channel = ch;
|
| 439 sce->chan_num= d->devcount++;
|
429 if (SLIST_EMPTY(&d->channels)) { 430 SLIST_INSERT_HEAD(&d->channels, sce, link); 431 } else { 432 after = NULL; 433 SLIST_FOREACH(tmp, &d->channels, link) { 434 after = tmp; 435 } 436 SLIST_INSERT_AFTER(after, sce, link); 437 }
| 440 if (SLIST_EMPTY(&d->channels)) { 441 SLIST_INSERT_HEAD(&d->channels, sce, link); 442 } else { 443 after = NULL; 444 SLIST_FOREACH(tmp, &d->channels, link) { 445 after = tmp; 446 } 447 SLIST_INSERT_AFTER(after, sce, link); 448 }
|
438 if (mkdev) 439 x = d->devcount++;
| |
440 snd_mtxunlock(d->lock);
| 449 snd_mtxunlock(d->lock);
|
| 450 sce->dsp_devt= make_dev(&dsp_cdevsw, 451 PCMMKMINOR(device, SND_DEV_DSP, sce->chan_num), 452 UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d", 453 device, sce->chan_num);
|
441
| 454
|
442 if (mkdev) { 443 dsp_register(unit, x); 444 if (ch->direction == PCMDIR_REC) 445 dsp_registerrec(unit, ch->num); 446 }
| 455 sce->dspW_devt= make_dev(&dsp_cdevsw, 456 PCMMKMINOR(device, SND_DEV_DSP16, sce->chan_num), 457 UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d", 458 device, sce->chan_num);
|
447
| 459
|
| 460 sce->audio_devt= make_dev(&dsp_cdevsw, 461 PCMMKMINOR(device, SND_DEV_AUDIO, sce->chan_num), 462 UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", 463 device, sce->chan_num); 464 465 if (ch->direction == PCMDIR_REC) 466 sce->dspr_devt = make_dev(&dsp_cdevsw, 467 PCMMKMINOR(device, SND_DEV_DSPREC, 468 sce->chan_num), UID_ROOT, GID_WHEEL, 469 0666, "dspr%d.%d", device, sce->chan_num); 470
|
448 return 0; 449} 450 451int
| 471 return 0; 472} 473 474int
|
452pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch, int rmdev)
| 475pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
|
453{ 454 struct snddev_channel *sce;
| 476{ 477 struct snddev_channel *sce;
|
455 int unit = device_get_unit(d->dev);
| |
456#if 0 457 int ourlock; 458 459 ourlock = 0; 460 if (!mtx_owned(d->lock)) { 461 snd_mtxlock(d->lock); 462 ourlock = 1; 463 } 464#endif 465 466 SLIST_FOREACH(sce, &d->channels, link) { 467 if (sce->channel == ch) 468 goto gotit; 469 } 470#if 0 471 if (ourlock) 472 snd_mtxunlock(d->lock); 473#endif 474 return EINVAL; 475gotit: 476 SLIST_REMOVE(&d->channels, sce, snddev_channel, link);
| 478#if 0 479 int ourlock; 480 481 ourlock = 0; 482 if (!mtx_owned(d->lock)) { 483 snd_mtxlock(d->lock); 484 ourlock = 1; 485 } 486#endif 487 488 SLIST_FOREACH(sce, &d->channels, link) { 489 if (sce->channel == ch) 490 goto gotit; 491 } 492#if 0 493 if (ourlock) 494 snd_mtxunlock(d->lock); 495#endif 496 return EINVAL; 497gotit: 498 SLIST_REMOVE(&d->channels, sce, snddev_channel, link);
|
477 if (rmdev) { 478 dsp_unregister(unit, --d->devcount); 479 if (ch->direction == PCMDIR_REC) 480 dsp_unregisterrec(unit, ch->num); 481 }
| |
482 483 if (ch->direction == PCMDIR_REC) 484 d->reccount--; 485 else if (ch->flags & CHN_F_VIRTUAL) 486 d->vchancount--; 487 else 488 d->playcount--; 489 490#if 0 491 if (ourlock) 492 snd_mtxunlock(d->lock); 493#endif 494 free(sce, M_DEVBUF); 495 496 return 0; 497} 498 499int 500pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 501{ 502 struct snddev_info *d = device_get_softc(dev); 503 struct pcm_channel *ch; 504 int err; 505 506 ch = pcm_chn_create(d, NULL, cls, dir, devinfo); 507 if (!ch) { 508 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", cls->name, dir, devinfo); 509 return ENODEV; 510 } 511
| 499 500 if (ch->direction == PCMDIR_REC) 501 d->reccount--; 502 else if (ch->flags & CHN_F_VIRTUAL) 503 d->vchancount--; 504 else 505 d->playcount--; 506 507#if 0 508 if (ourlock) 509 snd_mtxunlock(d->lock); 510#endif 511 free(sce, M_DEVBUF); 512 513 return 0; 514} 515 516int 517pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 518{ 519 struct snddev_info *d = device_get_softc(dev); 520 struct pcm_channel *ch; 521 int err; 522 523 ch = pcm_chn_create(d, NULL, cls, dir, devinfo); 524 if (!ch) { 525 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", cls->name, dir, devinfo); 526 return ENODEV; 527 } 528
|
512 err = pcm_chn_add(d, ch, 1);
| 529 err = pcm_chn_add(d, ch);
|
513 if (err) { 514 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", ch->name, err); 515 snd_mtxunlock(d->lock); 516 pcm_chn_destroy(ch); 517 return err; 518 } 519 520 if (snd_maxautovchans > 0 && (d->flags & SD_F_AUTOVCHAN) && 521 ch->direction == PCMDIR_PLAY && d->vchancount == 0) { 522 ch->flags |= CHN_F_BUSY; 523 err = vchan_create(ch); 524 if (err) { 525 device_printf(d->dev, "vchan_create(%s) == %d\n", ch->name, err); 526 ch->flags &= ~CHN_F_BUSY; 527 } 528 } 529 530 return err; 531} 532 533static int 534pcm_killchan(device_t dev) 535{ 536 struct snddev_info *d = device_get_softc(dev); 537 struct snddev_channel *sce; 538 struct pcm_channel *ch; 539 int error = 0; 540 541 sce = SLIST_FIRST(&d->channels); 542 ch = sce->channel; 543
| 530 if (err) { 531 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", ch->name, err); 532 snd_mtxunlock(d->lock); 533 pcm_chn_destroy(ch); 534 return err; 535 } 536 537 if (snd_maxautovchans > 0 && (d->flags & SD_F_AUTOVCHAN) && 538 ch->direction == PCMDIR_PLAY && d->vchancount == 0) { 539 ch->flags |= CHN_F_BUSY; 540 err = vchan_create(ch); 541 if (err) { 542 device_printf(d->dev, "vchan_create(%s) == %d\n", ch->name, err); 543 ch->flags &= ~CHN_F_BUSY; 544 } 545 } 546 547 return err; 548} 549 550static int 551pcm_killchan(device_t dev) 552{ 553 struct snddev_info *d = device_get_softc(dev); 554 struct snddev_channel *sce; 555 struct pcm_channel *ch; 556 int error = 0; 557 558 sce = SLIST_FIRST(&d->channels); 559 ch = sce->channel; 560
|
544 error = pcm_chn_remove(d, sce->channel, SLIST_EMPTY(&ch->children));
| 561 error = pcm_chn_remove(d, sce->channel);
|
545 if (error) 546 return (error); 547 return (pcm_chn_destroy(ch)); 548} 549 550int 551pcm_setstatus(device_t dev, char *str) 552{ 553 struct snddev_info *d = device_get_softc(dev); 554 555 snd_mtxlock(d->lock); 556 strncpy(d->status, str, SND_STATUSLEN); 557 snd_mtxunlock(d->lock); 558 return 0; 559} 560 561u_int32_t 562pcm_getflags(device_t dev) 563{ 564 struct snddev_info *d = device_get_softc(dev); 565 566 return d->flags; 567} 568 569void 570pcm_setflags(device_t dev, u_int32_t val) 571{ 572 struct snddev_info *d = device_get_softc(dev); 573 574 d->flags = val; 575} 576 577void * 578pcm_getdevinfo(device_t dev) 579{ 580 struct snddev_info *d = device_get_softc(dev); 581 582 return d->devinfo; 583} 584 585unsigned int 586pcm_getbuffersize(device_t dev, unsigned int min, unsigned int deflt, unsigned int max) 587{ 588 struct snddev_info *d = device_get_softc(dev); 589 int sz, x; 590 591 sz = 0; 592 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 593 x = sz; 594 RANGE(sz, min, max); 595 if (x != sz) 596 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, min, max, sz); 597 x = min; 598 while (x < sz) 599 x <<= 1; 600 if (x > sz) 601 x >>= 1; 602 if (x != sz) { 603 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 604 sz = x; 605 } 606 } else { 607 sz = deflt; 608 } 609 610 d->bufsz = sz; 611 612 return sz; 613} 614 615int 616pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 617{ 618 struct snddev_info *d = device_get_softc(dev); 619 620 if (pcm_veto_load) { 621 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 622 623 return EINVAL; 624 } 625 626 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev"); 627 628 d->flags = 0; 629 d->dev = dev; 630 d->devinfo = devinfo; 631 d->devcount = 0; 632 d->reccount = 0; 633 d->playcount = 0; 634 d->vchancount = 0; 635 d->inprog = 0; 636 637 SLIST_INIT(&d->channels); 638 SLIST_INIT(&d->channels); 639 640 if (((numplay == 0) || (numrec == 0)) && (numplay != numrec)) 641 d->flags |= SD_F_SIMPLEX; 642 643 d->fakechan = fkchan_setup(dev); 644 chn_init(d->fakechan, NULL, 0); 645 646#ifdef SND_DYNSYSCTL 647 sysctl_ctx_init(&d->sysctl_tree); 648 d->sysctl_tree_top = SYSCTL_ADD_NODE(&d->sysctl_tree, 649 SYSCTL_STATIC_CHILDREN(_hw_snd), OID_AUTO, 650 device_get_nameunit(dev), CTLFLAG_RD, 0, ""); 651 if (d->sysctl_tree_top == NULL) { 652 sysctl_ctx_free(&d->sysctl_tree); 653 goto no; 654 } 655 SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), 656 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, ""); 657#endif 658 if (numplay > 0) 659 vchan_initsys(dev); 660 if (numplay == 1) 661 d->flags |= SD_F_AUTOVCHAN; 662 663 sndstat_register(dev, d->status, sndstat_prepare_pcm); 664 return 0; 665no: 666 snd_mtxfree(d->lock); 667 return ENXIO; 668} 669 670int 671pcm_unregister(device_t dev) 672{ 673 struct snddev_info *d = device_get_softc(dev); 674 struct snddev_channel *sce; 675 struct pcm_channel *ch; 676 677 snd_mtxlock(d->lock); 678 if (d->inprog) { 679 device_printf(dev, "unregister: operation in progress\n"); 680 snd_mtxunlock(d->lock); 681 return EBUSY; 682 } 683 if (sndstat_busy() != 0) { 684 device_printf(dev, "unregister: sndstat busy\n"); 685 snd_mtxunlock(d->lock); 686 return EBUSY; 687 }
| 562 if (error) 563 return (error); 564 return (pcm_chn_destroy(ch)); 565} 566 567int 568pcm_setstatus(device_t dev, char *str) 569{ 570 struct snddev_info *d = device_get_softc(dev); 571 572 snd_mtxlock(d->lock); 573 strncpy(d->status, str, SND_STATUSLEN); 574 snd_mtxunlock(d->lock); 575 return 0; 576} 577 578u_int32_t 579pcm_getflags(device_t dev) 580{ 581 struct snddev_info *d = device_get_softc(dev); 582 583 return d->flags; 584} 585 586void 587pcm_setflags(device_t dev, u_int32_t val) 588{ 589 struct snddev_info *d = device_get_softc(dev); 590 591 d->flags = val; 592} 593 594void * 595pcm_getdevinfo(device_t dev) 596{ 597 struct snddev_info *d = device_get_softc(dev); 598 599 return d->devinfo; 600} 601 602unsigned int 603pcm_getbuffersize(device_t dev, unsigned int min, unsigned int deflt, unsigned int max) 604{ 605 struct snddev_info *d = device_get_softc(dev); 606 int sz, x; 607 608 sz = 0; 609 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 610 x = sz; 611 RANGE(sz, min, max); 612 if (x != sz) 613 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, min, max, sz); 614 x = min; 615 while (x < sz) 616 x <<= 1; 617 if (x > sz) 618 x >>= 1; 619 if (x != sz) { 620 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 621 sz = x; 622 } 623 } else { 624 sz = deflt; 625 } 626 627 d->bufsz = sz; 628 629 return sz; 630} 631 632int 633pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 634{ 635 struct snddev_info *d = device_get_softc(dev); 636 637 if (pcm_veto_load) { 638 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 639 640 return EINVAL; 641 } 642 643 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev"); 644 645 d->flags = 0; 646 d->dev = dev; 647 d->devinfo = devinfo; 648 d->devcount = 0; 649 d->reccount = 0; 650 d->playcount = 0; 651 d->vchancount = 0; 652 d->inprog = 0; 653 654 SLIST_INIT(&d->channels); 655 SLIST_INIT(&d->channels); 656 657 if (((numplay == 0) || (numrec == 0)) && (numplay != numrec)) 658 d->flags |= SD_F_SIMPLEX; 659 660 d->fakechan = fkchan_setup(dev); 661 chn_init(d->fakechan, NULL, 0); 662 663#ifdef SND_DYNSYSCTL 664 sysctl_ctx_init(&d->sysctl_tree); 665 d->sysctl_tree_top = SYSCTL_ADD_NODE(&d->sysctl_tree, 666 SYSCTL_STATIC_CHILDREN(_hw_snd), OID_AUTO, 667 device_get_nameunit(dev), CTLFLAG_RD, 0, ""); 668 if (d->sysctl_tree_top == NULL) { 669 sysctl_ctx_free(&d->sysctl_tree); 670 goto no; 671 } 672 SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), 673 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, ""); 674#endif 675 if (numplay > 0) 676 vchan_initsys(dev); 677 if (numplay == 1) 678 d->flags |= SD_F_AUTOVCHAN; 679 680 sndstat_register(dev, d->status, sndstat_prepare_pcm); 681 return 0; 682no: 683 snd_mtxfree(d->lock); 684 return ENXIO; 685} 686 687int 688pcm_unregister(device_t dev) 689{ 690 struct snddev_info *d = device_get_softc(dev); 691 struct snddev_channel *sce; 692 struct pcm_channel *ch; 693 694 snd_mtxlock(d->lock); 695 if (d->inprog) { 696 device_printf(dev, "unregister: operation in progress\n"); 697 snd_mtxunlock(d->lock); 698 return EBUSY; 699 } 700 if (sndstat_busy() != 0) { 701 device_printf(dev, "unregister: sndstat busy\n"); 702 snd_mtxunlock(d->lock); 703 return EBUSY; 704 }
|
| 705 706
|
688 SLIST_FOREACH(sce, &d->channels, link) { 689 ch = sce->channel; 690 if (ch->refcount > 0) { 691 device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid); 692 snd_mtxunlock(d->lock); 693 return EBUSY; 694 } 695 }
| 707 SLIST_FOREACH(sce, &d->channels, link) { 708 ch = sce->channel; 709 if (ch->refcount > 0) { 710 device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid); 711 snd_mtxunlock(d->lock); 712 return EBUSY; 713 } 714 }
|
| 715 716 SLIST_FOREACH(sce, &d->channels, link) { 717 destroy_dev(sce->dsp_devt); 718 destroy_dev(sce->dspW_devt); 719 destroy_dev(sce->audio_devt); 720 if (sce->dspr_devt) 721 destroy_dev(sce->dspr_devt); 722 } 723
|
696 if (mixer_uninit(dev)) { 697 device_printf(dev, "unregister: mixer busy\n"); 698 snd_mtxunlock(d->lock); 699 return EBUSY; 700 } 701 702#ifdef SND_DYNSYSCTL 703 d->sysctl_tree_top = NULL; 704 sysctl_ctx_free(&d->sysctl_tree); 705#endif 706 while (!SLIST_EMPTY(&d->channels)) 707 pcm_killchan(dev); 708 709 chn_kill(d->fakechan); 710 fkchan_kill(d->fakechan); 711 712 sndstat_unregister(dev); 713 snd_mtxunlock(d->lock); 714 snd_mtxfree(d->lock); 715 return 0; 716} 717
| 724 if (mixer_uninit(dev)) { 725 device_printf(dev, "unregister: mixer busy\n"); 726 snd_mtxunlock(d->lock); 727 return EBUSY; 728 } 729 730#ifdef SND_DYNSYSCTL 731 d->sysctl_tree_top = NULL; 732 sysctl_ctx_free(&d->sysctl_tree); 733#endif 734 while (!SLIST_EMPTY(&d->channels)) 735 pcm_killchan(dev); 736 737 chn_kill(d->fakechan); 738 fkchan_kill(d->fakechan); 739 740 sndstat_unregister(dev); 741 snd_mtxunlock(d->lock); 742 snd_mtxfree(d->lock); 743 return 0; 744} 745
|
718int 719pcm_regdevt(dev_t dev, unsigned unit, unsigned type, unsigned channel) 720{ 721 struct snddev_info *d; 722 struct snddev_devt *dt; 723 724 d = devclass_get_softc(pcm_devclass, unit); 725 KASSERT((d != NULL), ("bad d")); 726 KASSERT((dev != NULL), ("bad dev")); 727 728 dt = malloc(sizeof(*dt), M_DEVBUF, M_ZERO | M_WAITOK); 729 if (dt == NULL) 730 return ENOMEM; 731 dt->dev = dev; 732 dt->type = type; 733 dt->channel = channel; 734 735 snd_mtxlock(d->lock); 736 SLIST_INSERT_HEAD(&d->devs, dt, link); 737 snd_mtxunlock(d->lock); 738 739 return 0; 740} 741 742dev_t 743pcm_getdevt(unsigned unit, unsigned type, unsigned channel) 744{ 745 struct snddev_info *d; 746 struct snddev_devt *dt; 747 748 d = devclass_get_softc(pcm_devclass, unit); 749 KASSERT((d != NULL), ("bad d")); 750 751#if 0 752 snd_mtxlock(d->lock); 753#endif 754 SLIST_FOREACH(dt, &d->devs, link) { 755 if ((dt->type == type) && (dt->channel == channel)) 756 return dt->dev; 757 } 758#if 0 759 snd_mtxunlock(d->lock); 760#endif 761 762 return NULL; 763} 764 765int 766pcm_unregdevt(unsigned unit, unsigned type, unsigned channel) 767{ 768 struct snddev_info *d; 769 struct snddev_devt *dt; 770 771 d = devclass_get_softc(pcm_devclass, unit); 772 KASSERT((d != NULL), ("bad d")); 773 774#if 0 775 snd_mtxlock(d->lock); 776#endif 777 SLIST_FOREACH(dt, &d->devs, link) { 778 if ((dt->type == type) && (dt->channel == channel)) { 779 SLIST_REMOVE(&d->devs, dt, snddev_devt, link); 780 free(dt, M_DEVBUF); 781#if 0 782 snd_mtxunlock(d->lock); 783#endif 784 return 0; 785 } 786 } 787#if 0 788 snd_mtxunlock(d->lock); 789#endif 790 791 return ENOENT; 792} 793
| |
794/************************************************************************/ 795 796static int 797sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose) 798{ 799 struct snddev_info *d; 800 struct snddev_channel *sce; 801 struct pcm_channel *c; 802 struct pcm_feeder *f; 803 int pc, rc, vc; 804 805 if (verbose < 1) 806 return 0; 807 808 d = device_get_softc(dev); 809 if (!d) 810 return ENXIO; 811 812 snd_mtxlock(d->lock); 813 if (!SLIST_EMPTY(&d->channels)) { 814 pc = rc = vc = 0; 815 SLIST_FOREACH(sce, &d->channels, link) { 816 c = sce->channel; 817 if (c->direction == PCMDIR_PLAY) { 818 if (c->flags & CHN_F_VIRTUAL) 819 vc++; 820 else 821 pc++; 822 } else 823 rc++; 824 } 825 sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)", d->playcount, d->reccount, d->vchancount, 826 (d->flags & SD_F_SIMPLEX)? "" : " duplex", 827#ifdef USING_DEVFS 828 (device_get_unit(dev) == snd_unit)? " default" : "" 829#else 830 "" 831#endif 832 ); 833 834 if (verbose <= 1) { 835 snd_mtxunlock(d->lock); 836 return 0; 837 } 838 839 SLIST_FOREACH(sce, &d->channels, link) { 840 c = sce->channel; 841 sbuf_printf(s, "\n\t"); 842 843 /* it would be better to indent child channels */ 844 sbuf_printf(s, "%s[%s]: ", c->parentchannel? c->parentchannel->name : "", c->name); 845 sbuf_printf(s, "spd %d", c->speed); 846 if (c->speed != sndbuf_getspd(c->bufhard)) 847 sbuf_printf(s, "/%d", sndbuf_getspd(c->bufhard)); 848 sbuf_printf(s, ", fmt 0x%08x", c->format); 849 if (c->format != sndbuf_getfmt(c->bufhard)) 850 sbuf_printf(s, "/0x%08x", sndbuf_getfmt(c->bufhard)); 851 sbuf_printf(s, ", flags 0x%08x, 0x%08x", c->flags, c->feederflags); 852 if (c->pid != -1) 853 sbuf_printf(s, ", pid %d", c->pid); 854 sbuf_printf(s, "\n\t"); 855 856 if (c->bufhard != NULL && c->bufsoft != NULL) { 857 sbuf_printf(s, "interrupts %d, ", c->interrupts); 858 if (c->direction == PCMDIR_REC) 859 sbuf_printf(s, "overruns %d, hfree %d, sfree %d", 860 c->xruns, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft)); 861 else 862 sbuf_printf(s, "underruns %d, ready %d", 863 c->xruns, sndbuf_getready(c->bufsoft)); 864 sbuf_printf(s, "\n\t"); 865 } 866 867 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "hardware" : "userland"); 868 sbuf_printf(s, " -> "); 869 f = c->feeder; 870 while (f->source != NULL) 871 f = f->source; 872 while (f != NULL) { 873 sbuf_printf(s, "%s", f->class->name); 874 if (f->desc->type == FEEDER_FMT) 875 sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out); 876 if (f->desc->type == FEEDER_RATE) 877 sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST)); 878 if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER) 879 sbuf_printf(s, "(0x%08x)", f->desc->out); 880 sbuf_printf(s, " -> "); 881 f = f->parent; 882 } 883 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "userland" : "hardware"); 884 } 885 } else 886 sbuf_printf(s, " (mixer only)"); 887 snd_mtxunlock(d->lock); 888 889 return 0; 890} 891 892/************************************************************************/ 893 894#ifdef SND_DYNSYSCTL 895int 896sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS) 897{ 898 struct snddev_info *d; 899 struct snddev_channel *sce; 900 struct pcm_channel *c; 901 int err, newcnt, cnt, busy; 902 int x; 903 904 d = oidp->oid_arg1; 905 906 x = pcm_inprog(d, 1); 907 if (x != 1) { 908 printf("x: %d\n", x); 909 pcm_inprog(d, -1); 910 return EINPROGRESS; 911 } 912 913 busy = 0; 914 cnt = 0; 915 SLIST_FOREACH(sce, &d->channels, link) { 916 c = sce->channel; 917 if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL)) { 918 cnt++; 919 if (c->flags & CHN_F_BUSY) 920 busy++; 921 } 922 } 923 924 newcnt = cnt; 925 926 err = sysctl_handle_int(oidp, &newcnt, sizeof(newcnt), req); 927 928 if (err == 0 && req->newptr != NULL) { 929 930 if (newcnt < 0 || newcnt > SND_MAXVCHANS) { 931 pcm_inprog(d, -1); 932 return E2BIG; 933 } 934 935 if (newcnt > cnt) { 936 /* add new vchans - find a parent channel first */ 937 SLIST_FOREACH(sce, &d->channels, link) { 938 c = sce->channel; 939 /* not a candidate if not a play channel */ 940 if (c->direction != PCMDIR_PLAY) 941 continue; 942 /* not a candidate if a virtual channel */ 943 if (c->flags & CHN_F_VIRTUAL) 944 continue; 945 /* not a candidate if it's in use */ 946 if ((c->flags & CHN_F_BUSY) && (SLIST_EMPTY(&c->children))) 947 continue; 948 /* 949 * if we get here we're a nonvirtual play channel, and either 950 * 1) not busy 951 * 2) busy with children, not directly open 952 * 953 * thus we can add children 954 */ 955 goto addok; 956 } 957 pcm_inprog(d, -1); 958 return EBUSY; 959addok: 960 c->flags |= CHN_F_BUSY; 961 while (err == 0 && newcnt > cnt) { 962 err = vchan_create(c); 963 if (err == 0) 964 cnt++; 965 } 966 if (SLIST_EMPTY(&c->children)) 967 c->flags &= ~CHN_F_BUSY; 968 } else if (newcnt < cnt) { 969 if (busy > newcnt) { 970 printf("cnt %d, newcnt %d, busy %d\n", cnt, newcnt, busy); 971 pcm_inprog(d, -1); 972 return EBUSY; 973 } 974 975 snd_mtxlock(d->lock); 976 while (err == 0 && newcnt < cnt) { 977 SLIST_FOREACH(sce, &d->channels, link) { 978 c = sce->channel; 979 if ((c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == CHN_F_VIRTUAL) 980 goto remok; 981 } 982 snd_mtxunlock(d->lock); 983 pcm_inprog(d, -1); 984 return EINVAL; 985remok: 986 err = vchan_destroy(c); 987 if (err == 0) 988 cnt--; 989 } 990 snd_mtxunlock(d->lock); 991 } 992 } 993 pcm_inprog(d, -1); 994 return err; 995} 996#endif 997 998/************************************************************************/ 999 1000static moduledata_t sndpcm_mod = { 1001 "snd_pcm", 1002 NULL, 1003 NULL 1004}; 1005DECLARE_MODULE(snd_pcm, sndpcm_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1006MODULE_VERSION(snd_pcm, PCM_MODVER);
| 746/************************************************************************/ 747 748static int 749sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose) 750{ 751 struct snddev_info *d; 752 struct snddev_channel *sce; 753 struct pcm_channel *c; 754 struct pcm_feeder *f; 755 int pc, rc, vc; 756 757 if (verbose < 1) 758 return 0; 759 760 d = device_get_softc(dev); 761 if (!d) 762 return ENXIO; 763 764 snd_mtxlock(d->lock); 765 if (!SLIST_EMPTY(&d->channels)) { 766 pc = rc = vc = 0; 767 SLIST_FOREACH(sce, &d->channels, link) { 768 c = sce->channel; 769 if (c->direction == PCMDIR_PLAY) { 770 if (c->flags & CHN_F_VIRTUAL) 771 vc++; 772 else 773 pc++; 774 } else 775 rc++; 776 } 777 sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)", d->playcount, d->reccount, d->vchancount, 778 (d->flags & SD_F_SIMPLEX)? "" : " duplex", 779#ifdef USING_DEVFS 780 (device_get_unit(dev) == snd_unit)? " default" : "" 781#else 782 "" 783#endif 784 ); 785 786 if (verbose <= 1) { 787 snd_mtxunlock(d->lock); 788 return 0; 789 } 790 791 SLIST_FOREACH(sce, &d->channels, link) { 792 c = sce->channel; 793 sbuf_printf(s, "\n\t"); 794 795 /* it would be better to indent child channels */ 796 sbuf_printf(s, "%s[%s]: ", c->parentchannel? c->parentchannel->name : "", c->name); 797 sbuf_printf(s, "spd %d", c->speed); 798 if (c->speed != sndbuf_getspd(c->bufhard)) 799 sbuf_printf(s, "/%d", sndbuf_getspd(c->bufhard)); 800 sbuf_printf(s, ", fmt 0x%08x", c->format); 801 if (c->format != sndbuf_getfmt(c->bufhard)) 802 sbuf_printf(s, "/0x%08x", sndbuf_getfmt(c->bufhard)); 803 sbuf_printf(s, ", flags 0x%08x, 0x%08x", c->flags, c->feederflags); 804 if (c->pid != -1) 805 sbuf_printf(s, ", pid %d", c->pid); 806 sbuf_printf(s, "\n\t"); 807 808 if (c->bufhard != NULL && c->bufsoft != NULL) { 809 sbuf_printf(s, "interrupts %d, ", c->interrupts); 810 if (c->direction == PCMDIR_REC) 811 sbuf_printf(s, "overruns %d, hfree %d, sfree %d", 812 c->xruns, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft)); 813 else 814 sbuf_printf(s, "underruns %d, ready %d", 815 c->xruns, sndbuf_getready(c->bufsoft)); 816 sbuf_printf(s, "\n\t"); 817 } 818 819 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "hardware" : "userland"); 820 sbuf_printf(s, " -> "); 821 f = c->feeder; 822 while (f->source != NULL) 823 f = f->source; 824 while (f != NULL) { 825 sbuf_printf(s, "%s", f->class->name); 826 if (f->desc->type == FEEDER_FMT) 827 sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out); 828 if (f->desc->type == FEEDER_RATE) 829 sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST)); 830 if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER) 831 sbuf_printf(s, "(0x%08x)", f->desc->out); 832 sbuf_printf(s, " -> "); 833 f = f->parent; 834 } 835 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "userland" : "hardware"); 836 } 837 } else 838 sbuf_printf(s, " (mixer only)"); 839 snd_mtxunlock(d->lock); 840 841 return 0; 842} 843 844/************************************************************************/ 845 846#ifdef SND_DYNSYSCTL 847int 848sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS) 849{ 850 struct snddev_info *d; 851 struct snddev_channel *sce; 852 struct pcm_channel *c; 853 int err, newcnt, cnt, busy; 854 int x; 855 856 d = oidp->oid_arg1; 857 858 x = pcm_inprog(d, 1); 859 if (x != 1) { 860 printf("x: %d\n", x); 861 pcm_inprog(d, -1); 862 return EINPROGRESS; 863 } 864 865 busy = 0; 866 cnt = 0; 867 SLIST_FOREACH(sce, &d->channels, link) { 868 c = sce->channel; 869 if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL)) { 870 cnt++; 871 if (c->flags & CHN_F_BUSY) 872 busy++; 873 } 874 } 875 876 newcnt = cnt; 877 878 err = sysctl_handle_int(oidp, &newcnt, sizeof(newcnt), req); 879 880 if (err == 0 && req->newptr != NULL) { 881 882 if (newcnt < 0 || newcnt > SND_MAXVCHANS) { 883 pcm_inprog(d, -1); 884 return E2BIG; 885 } 886 887 if (newcnt > cnt) { 888 /* add new vchans - find a parent channel first */ 889 SLIST_FOREACH(sce, &d->channels, link) { 890 c = sce->channel; 891 /* not a candidate if not a play channel */ 892 if (c->direction != PCMDIR_PLAY) 893 continue; 894 /* not a candidate if a virtual channel */ 895 if (c->flags & CHN_F_VIRTUAL) 896 continue; 897 /* not a candidate if it's in use */ 898 if ((c->flags & CHN_F_BUSY) && (SLIST_EMPTY(&c->children))) 899 continue; 900 /* 901 * if we get here we're a nonvirtual play channel, and either 902 * 1) not busy 903 * 2) busy with children, not directly open 904 * 905 * thus we can add children 906 */ 907 goto addok; 908 } 909 pcm_inprog(d, -1); 910 return EBUSY; 911addok: 912 c->flags |= CHN_F_BUSY; 913 while (err == 0 && newcnt > cnt) { 914 err = vchan_create(c); 915 if (err == 0) 916 cnt++; 917 } 918 if (SLIST_EMPTY(&c->children)) 919 c->flags &= ~CHN_F_BUSY; 920 } else if (newcnt < cnt) { 921 if (busy > newcnt) { 922 printf("cnt %d, newcnt %d, busy %d\n", cnt, newcnt, busy); 923 pcm_inprog(d, -1); 924 return EBUSY; 925 } 926 927 snd_mtxlock(d->lock); 928 while (err == 0 && newcnt < cnt) { 929 SLIST_FOREACH(sce, &d->channels, link) { 930 c = sce->channel; 931 if ((c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == CHN_F_VIRTUAL) 932 goto remok; 933 } 934 snd_mtxunlock(d->lock); 935 pcm_inprog(d, -1); 936 return EINVAL; 937remok: 938 err = vchan_destroy(c); 939 if (err == 0) 940 cnt--; 941 } 942 snd_mtxunlock(d->lock); 943 } 944 } 945 pcm_inprog(d, -1); 946 return err; 947} 948#endif 949 950/************************************************************************/ 951 952static moduledata_t sndpcm_mod = { 953 "snd_pcm", 954 NULL, 955 NULL 956}; 957DECLARE_MODULE(snd_pcm, sndpcm_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 958MODULE_VERSION(snd_pcm, PCM_MODVER);
|