Deleted Added
full compact
sound.c (192920) sound.c (193640)
1/*-
1/*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
2 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
4 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
3 * Copyright (c) 1997 Luigi Rizzo
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.

--- 9 unchanged lines hidden (view full) ---

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
5 * Copyright (c) 1997 Luigi Rizzo
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.

--- 9 unchanged lines hidden (view full) ---

22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifdef HAVE_KERNEL_OPTION_HEADERS
31#include "opt_snd.h"
32#endif
33
28#include <dev/sound/pcm/sound.h>
29#include <dev/sound/pcm/ac97.h>
30#include <dev/sound/pcm/vchan.h>
31#include <dev/sound/pcm/dsp.h>
34#include <dev/sound/pcm/sound.h>
35#include <dev/sound/pcm/ac97.h>
36#include <dev/sound/pcm/vchan.h>
37#include <dev/sound/pcm/dsp.h>
38#include <dev/sound/pcm/sndstat.h>
32#include <dev/sound/version.h>
33#include <sys/limits.h>
34#include <sys/sysctl.h>
35
36#include "feeder_if.h"
37
39#include <dev/sound/version.h>
40#include <sys/limits.h>
41#include <sys/sysctl.h>
42
43#include "feeder_if.h"
44
38SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/sound.c 192920 2009-05-27 18:16:53Z joel $");
45SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/sound.c 193640 2009-06-07 19:12:08Z ariff $");
39
40devclass_t pcm_devclass;
41
42int pcm_veto_load = 1;
43
46
47devclass_t pcm_devclass;
48
49int pcm_veto_load = 1;
50
44#ifdef USING_DEVFS
45int snd_unit = -1;
46TUNABLE_INT("hw.snd.default_unit", &snd_unit);
51int snd_unit = -1;
52TUNABLE_INT("hw.snd.default_unit", &snd_unit);
47#endif
48
49static int snd_unit_auto = 0;
50TUNABLE_INT("hw.snd.default_auto", &snd_unit_auto);
51SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RW,
52 &snd_unit_auto, 0, "assign default unit to a newly attached device");
53
54int snd_maxautovchans = 16;
55/* XXX: a tunable implies that we may need more than one sound channel before

--- 5 unchanged lines hidden (view full) ---

61
62/*
63 * XXX I've had enough with people not telling proper version/arch
64 * while reporting problems, not after 387397913213th questions/requests.
65 */
66static const char snd_driver_version[] =
67 __XSTRING(SND_DRV_VERSION)"/"MACHINE_ARCH;
68SYSCTL_STRING(_hw_snd, OID_AUTO, version, CTLFLAG_RD, &snd_driver_version,
53
54static int snd_unit_auto = 0;
55TUNABLE_INT("hw.snd.default_auto", &snd_unit_auto);
56SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RW,
57 &snd_unit_auto, 0, "assign default unit to a newly attached device");
58
59int snd_maxautovchans = 16;
60/* XXX: a tunable implies that we may need more than one sound channel before

--- 5 unchanged lines hidden (view full) ---

66
67/*
68 * XXX I've had enough with people not telling proper version/arch
69 * while reporting problems, not after 387397913213th questions/requests.
70 */
71static const char snd_driver_version[] =
72 __XSTRING(SND_DRV_VERSION)"/"MACHINE_ARCH;
73SYSCTL_STRING(_hw_snd, OID_AUTO, version, CTLFLAG_RD, &snd_driver_version,
69 0, "Driver version/arch");
74 0, "driver version/arch");
70
71/**
72 * @brief Unit number allocator for syncgroup IDs
73 */
74struct unrhdr *pcmsg_unrhdr = NULL;
75
75
76/**
77 * @brief Unit number allocator for syncgroup IDs
78 */
79struct unrhdr *pcmsg_unrhdr = NULL;
80
76static int sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose);
81static int
82sndstat_prepare_pcm(SNDSTAT_PREPARE_PCM_ARGS)
83{
84 SNDSTAT_PREPARE_PCM_BEGIN();
85 SNDSTAT_PREPARE_PCM_END();
86}
77
78void *
79snd_mtxcreate(const char *desc, const char *type)
80{
87
88void *
89snd_mtxcreate(const char *desc, const char *type)
90{
81#ifdef USING_MUTEX
82 struct mtx *m;
83
84 m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO);
85 mtx_init(m, desc, type, MTX_DEF);
86 return m;
91 struct mtx *m;
92
93 m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO);
94 mtx_init(m, desc, type, MTX_DEF);
95 return m;
87#else
88 return (void *)0xcafebabe;
89#endif
90}
91
92void
93snd_mtxfree(void *m)
94{
96}
97
98void
99snd_mtxfree(void *m)
100{
95#ifdef USING_MUTEX
96 struct mtx *mtx = m;
97
101 struct mtx *mtx = m;
102
98 /* mtx_assert(mtx, MA_OWNED); */
99 mtx_destroy(mtx);
100 free(mtx, M_DEVBUF);
103 mtx_destroy(mtx);
104 free(mtx, M_DEVBUF);
101#endif
102}
103
104void
105snd_mtxassert(void *m)
106{
105}
106
107void
108snd_mtxassert(void *m)
109{
107#ifdef USING_MUTEX
108#ifdef INVARIANTS
109 struct mtx *mtx = m;
110
111 mtx_assert(mtx, MA_OWNED);
112#endif
110#ifdef INVARIANTS
111 struct mtx *mtx = m;
112
113 mtx_assert(mtx, MA_OWNED);
114#endif
113#endif
114}
115}
115/*
116void
117snd_mtxlock(void *m)
118{
119#ifdef USING_MUTEX
120 struct mtx *mtx = m;
121
116
122 mtx_lock(mtx);
123#endif
124}
125
126void
127snd_mtxunlock(void *m)
128{
129#ifdef USING_MUTEX
130 struct mtx *mtx = m;
131
132 mtx_unlock(mtx);
133#endif
134}
135*/
136int
137snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep)
138{
139 struct snddev_info *d;
117int
118snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep)
119{
120 struct snddev_info *d;
140#ifdef USING_MUTEX
121
141 flags &= INTR_MPSAFE;
142 flags |= INTR_TYPE_AV;
122 flags &= INTR_MPSAFE;
123 flags |= INTR_TYPE_AV;
143#else
144 flags = INTR_TYPE_AV;
145#endif
146 d = device_get_softc(dev);
147 if (d != NULL && (flags & INTR_MPSAFE))
148 d->flags |= SD_F_MPSAFE;
149
150 return bus_setup_intr(dev, res, flags,
151#if __FreeBSD_version >= 700031
152 NULL,
153#endif
154 hand, param, cookiep);
155}
156
124 d = device_get_softc(dev);
125 if (d != NULL && (flags & INTR_MPSAFE))
126 d->flags |= SD_F_MPSAFE;
127
128 return bus_setup_intr(dev, res, flags,
129#if __FreeBSD_version >= 700031
130 NULL,
131#endif
132 hand, param, cookiep);
133}
134
157#ifndef PCM_DEBUG_MTX
158void
159pcm_lock(struct snddev_info *d)
160{
161 snd_mtxlock(d->lock);
162}
163
164void
165pcm_unlock(struct snddev_info *d)
166{
167 snd_mtxunlock(d->lock);
168}
169#endif
170
171struct pcm_channel *
172pcm_getfakechan(struct snddev_info *d)
173{
174 return d->fakechan;
175}
176
177static void
178pcm_clonereset(struct snddev_info *d)
179{
180 int cmax;
181
182 PCM_BUSYASSERT(d);
183
184 cmax = d->playcount + d->reccount - 1;
185 if (d->pvchancount > 0)
135static void
136pcm_clonereset(struct snddev_info *d)
137{
138 int cmax;
139
140 PCM_BUSYASSERT(d);
141
142 cmax = d->playcount + d->reccount - 1;
143 if (d->pvchancount > 0)
186 cmax += MAX(d->pvchancount, snd_maxautovchans) - 1;
144 cmax += max(d->pvchancount, snd_maxautovchans) - 1;
187 if (d->rvchancount > 0)
145 if (d->rvchancount > 0)
188 cmax += MAX(d->rvchancount, snd_maxautovchans) - 1;
146 cmax += max(d->rvchancount, snd_maxautovchans) - 1;
189 if (cmax > PCMMAXCLONE)
190 cmax = PCMMAXCLONE;
191 (void)snd_clone_gc(d->clones);
192 (void)snd_clone_setmaxunit(d->clones, cmax);
193}
194
147 if (cmax > PCMMAXCLONE)
148 cmax = PCMMAXCLONE;
149 (void)snd_clone_gc(d->clones);
150 (void)snd_clone_setmaxunit(d->clones, cmax);
151}
152
195static int
153int
196pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num)
197{
198 struct pcm_channel *c, *ch, *nch;
154pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num)
155{
156 struct pcm_channel *c, *ch, *nch;
199 int err, vcnt;
157 struct pcmchan_caps *caps;
158 int i, err, vcnt;
200
201 PCM_BUSYASSERT(d);
202
203 if ((direction == PCMDIR_PLAY && d->playcount < 1) ||
204 (direction == PCMDIR_REC && d->reccount < 1))
205 return (ENODEV);
206
207 if (!(d->flags & SD_F_AUTOVCHAN))

--- 15 unchanged lines hidden (view full) ---

223 ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d",
224 num, newcnt, vcnt));
225 /* add new vchans - find a parent channel first */
226 ch = NULL;
227 CHN_FOREACH(c, d, channels.pcm) {
228 CHN_LOCK(c);
229 if (c->direction == direction &&
230 ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 &&
159
160 PCM_BUSYASSERT(d);
161
162 if ((direction == PCMDIR_PLAY && d->playcount < 1) ||
163 (direction == PCMDIR_REC && d->reccount < 1))
164 return (ENODEV);
165
166 if (!(d->flags & SD_F_AUTOVCHAN))

--- 15 unchanged lines hidden (view full) ---

182 ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d",
183 num, newcnt, vcnt));
184 /* add new vchans - find a parent channel first */
185 ch = NULL;
186 CHN_FOREACH(c, d, channels.pcm) {
187 CHN_LOCK(c);
188 if (c->direction == direction &&
189 ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 &&
190 c->refcount < 1 &&
231 !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) {
191 !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) {
232 ch = c;
233 break;
192 /*
193 * Reuse hw channel with vchans already
194 * created.
195 */
196 if (c->flags & CHN_F_HAS_VCHAN) {
197 ch = c;
198 break;
199 }
200 /*
201 * No vchans ever created, look for
202 * channels with supported formats.
203 */
204 caps = chn_getcaps(c);
205 if (caps == NULL) {
206 CHN_UNLOCK(c);
207 continue;
208 }
209 for (i = 0; caps->fmtlist[i] != 0; i++) {
210 if (caps->fmtlist[i] & AFMT_CONVERTIBLE)
211 break;
212 }
213 if (caps->fmtlist[i] != 0) {
214 ch = c;
215 break;
216 }
234 }
235 CHN_UNLOCK(c);
236 }
237 if (ch == NULL)
238 return (EBUSY);
239 ch->flags |= CHN_F_BUSY;
240 err = 0;
241 while (err == 0 && newcnt > vcnt) {

--- 20 unchanged lines hidden (view full) ---

262 if (c->direction != direction ||
263 CHN_EMPTY(c, children) ||
264 !(c->flags & CHN_F_HAS_VCHAN)) {
265 CHN_UNLOCK(c);
266 continue;
267 }
268 CHN_FOREACH_SAFE(ch, c, nch, children) {
269 CHN_LOCK(ch);
217 }
218 CHN_UNLOCK(c);
219 }
220 if (ch == NULL)
221 return (EBUSY);
222 ch->flags |= CHN_F_BUSY;
223 err = 0;
224 while (err == 0 && newcnt > vcnt) {

--- 20 unchanged lines hidden (view full) ---

245 if (c->direction != direction ||
246 CHN_EMPTY(c, children) ||
247 !(c->flags & CHN_F_HAS_VCHAN)) {
248 CHN_UNLOCK(c);
249 continue;
250 }
251 CHN_FOREACH_SAFE(ch, c, nch, children) {
252 CHN_LOCK(ch);
270 if (!(ch->flags & CHN_F_BUSY)) {
253 if (vcnt == 1 && c->refcount > 0) {
271 CHN_UNLOCK(ch);
254 CHN_UNLOCK(ch);
272 CHN_UNLOCK(c);
255 break;
256 }
257 if (!(ch->flags & CHN_F_BUSY) &&
258 ch->refcount < 1) {
273 err = vchan_destroy(ch);
259 err = vchan_destroy(ch);
274 CHN_LOCK(c);
275 if (err == 0)
276 vcnt--;
277 } else
278 CHN_UNLOCK(ch);
279 if (vcnt == newcnt)
280 break;
281 }
282 CHN_UNLOCK(c);
283 break;
284 }
285 pcm_clonereset(d);
286 }
287
288 return (0);
289}
290
291/* return error status and a locked channel */
292int
293pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
260 if (err == 0)
261 vcnt--;
262 } else
263 CHN_UNLOCK(ch);
264 if (vcnt == newcnt)
265 break;
266 }
267 CHN_UNLOCK(c);
268 break;
269 }
270 pcm_clonereset(d);
271 }
272
273 return (0);
274}
275
276/* return error status and a locked channel */
277int
278pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
294 pid_t pid, int devunit)
279 pid_t pid, char *comm, int devunit)
295{
296 struct pcm_channel *c;
280{
281 struct pcm_channel *c;
297 int err, vchancount;
282 int err, vchancount, vchan_num;
298
299 KASSERT(d != NULL && ch != NULL && (devunit == -1 ||
300 !(devunit & ~(SND_U_MASK | SND_D_MASK | SND_C_MASK))) &&
301 (direction == PCMDIR_PLAY || direction == PCMDIR_REC),
302 ("%s(): invalid d=%p ch=%p direction=%d pid=%d devunit=%d",
303 __func__, d, ch, direction, pid, devunit));
304 PCM_BUSYASSERT(d);
305
306 /* Double check again. */
307 if (devunit != -1) {
308 switch (snd_unit2d(devunit)) {
309 case SND_DEV_DSPHW_PLAY:
310 case SND_DEV_DSPHW_VPLAY:
311 if (direction != PCMDIR_PLAY)
283
284 KASSERT(d != NULL && ch != NULL && (devunit == -1 ||
285 !(devunit & ~(SND_U_MASK | SND_D_MASK | SND_C_MASK))) &&
286 (direction == PCMDIR_PLAY || direction == PCMDIR_REC),
287 ("%s(): invalid d=%p ch=%p direction=%d pid=%d devunit=%d",
288 __func__, d, ch, direction, pid, devunit));
289 PCM_BUSYASSERT(d);
290
291 /* Double check again. */
292 if (devunit != -1) {
293 switch (snd_unit2d(devunit)) {
294 case SND_DEV_DSPHW_PLAY:
295 case SND_DEV_DSPHW_VPLAY:
296 if (direction != PCMDIR_PLAY)
312 return (EOPNOTSUPP);
297 return (ENOTSUP);
313 break;
314 case SND_DEV_DSPHW_REC:
315 case SND_DEV_DSPHW_VREC:
316 if (direction != PCMDIR_REC)
298 break;
299 case SND_DEV_DSPHW_REC:
300 case SND_DEV_DSPHW_VREC:
301 if (direction != PCMDIR_REC)
317 return (EOPNOTSUPP);
302 return (ENOTSUP);
318 break;
319 default:
320 if (!(direction == PCMDIR_PLAY ||
321 direction == PCMDIR_REC))
303 break;
304 default:
305 if (!(direction == PCMDIR_PLAY ||
306 direction == PCMDIR_REC))
322 return (EOPNOTSUPP);
307 return (ENOTSUP);
323 break;
324 }
325 }
326
308 break;
309 }
310 }
311
312 *ch = NULL;
313 vchan_num = 0;
314 vchancount = (direction == PCMDIR_PLAY) ? d->pvchancount :
315 d->rvchancount;
316
327retry_chnalloc:
317retry_chnalloc:
328 err = EOPNOTSUPP;
318 err = ENOTSUP;
329 /* scan for a free channel */
330 CHN_FOREACH(c, d, channels.pcm) {
331 CHN_LOCK(c);
319 /* scan for a free channel */
320 CHN_FOREACH(c, d, channels.pcm) {
321 CHN_LOCK(c);
322 if (devunit == -1 && c->direction == direction &&
323 (c->flags & CHN_F_VIRTUAL)) {
324 if (vchancount < snd_maxautovchans &&
325 vchan_num < CHN_CHAN(c)) {
326 CHN_UNLOCK(c);
327 goto vchan_alloc;
328 }
329 vchan_num++;
330 }
332 if (c->direction == direction && !(c->flags & CHN_F_BUSY) &&
333 (devunit == -1 || devunit == -2 || c->unit == devunit)) {
334 c->flags |= CHN_F_BUSY;
335 c->pid = pid;
331 if (c->direction == direction && !(c->flags & CHN_F_BUSY) &&
332 (devunit == -1 || devunit == -2 || c->unit == devunit)) {
333 c->flags |= CHN_F_BUSY;
334 c->pid = pid;
335 strlcpy(c->comm, (comm != NULL) ? comm :
336 CHN_COMM_UNKNOWN, sizeof(c->comm));
336 *ch = c;
337 return (0);
338 } else if (c->unit == devunit) {
339 if (c->direction != direction)
337 *ch = c;
338 return (0);
339 } else if (c->unit == devunit) {
340 if (c->direction != direction)
340 err = EOPNOTSUPP;
341 err = ENOTSUP;
341 else if (c->flags & CHN_F_BUSY)
342 err = EBUSY;
343 else
344 err = EINVAL;
345 CHN_UNLOCK(c);
346 return (err);
347 } else if ((devunit == -1 || devunit == -2) &&
348 c->direction == direction && (c->flags & CHN_F_BUSY))
349 err = EBUSY;
350 CHN_UNLOCK(c);
351 }
352
353 if (devunit == -2)
354 return (err);
355
342 else if (c->flags & CHN_F_BUSY)
343 err = EBUSY;
344 else
345 err = EINVAL;
346 CHN_UNLOCK(c);
347 return (err);
348 } else if ((devunit == -1 || devunit == -2) &&
349 c->direction == direction && (c->flags & CHN_F_BUSY))
350 err = EBUSY;
351 CHN_UNLOCK(c);
352 }
353
354 if (devunit == -2)
355 return (err);
356
357vchan_alloc:
356 /* no channel available */
357 if (devunit == -1 || snd_unit2d(devunit) == SND_DEV_DSPHW_VPLAY ||
358 snd_unit2d(devunit) == SND_DEV_DSPHW_VREC) {
358 /* no channel available */
359 if (devunit == -1 || snd_unit2d(devunit) == SND_DEV_DSPHW_VPLAY ||
360 snd_unit2d(devunit) == SND_DEV_DSPHW_VREC) {
359 if (direction == PCMDIR_PLAY)
360 vchancount = d->pvchancount;
361 else
362 vchancount = d->rvchancount;
363 if (!(vchancount > 0 && vchancount < snd_maxautovchans) &&
364 (devunit == -1 || snd_unit2c(devunit) < snd_maxautovchans))
365 return (err);
366 err = pcm_setvchans(d, direction, vchancount + 1,
367 (devunit == -1) ? -1 : snd_unit2c(devunit));
368 if (err == 0) {
369 if (devunit == -1)
370 devunit = -2;

--- 8 unchanged lines hidden (view full) ---

379int
380pcm_chnrelease(struct pcm_channel *c)
381{
382 PCM_BUSYASSERT(c->parentsnddev);
383 CHN_LOCKASSERT(c);
384
385 c->flags &= ~CHN_F_BUSY;
386 c->pid = -1;
361 if (!(vchancount > 0 && vchancount < snd_maxautovchans) &&
362 (devunit == -1 || snd_unit2c(devunit) < snd_maxautovchans))
363 return (err);
364 err = pcm_setvchans(d, direction, vchancount + 1,
365 (devunit == -1) ? -1 : snd_unit2c(devunit));
366 if (err == 0) {
367 if (devunit == -1)
368 devunit = -2;

--- 8 unchanged lines hidden (view full) ---

377int
378pcm_chnrelease(struct pcm_channel *c)
379{
380 PCM_BUSYASSERT(c->parentsnddev);
381 CHN_LOCKASSERT(c);
382
383 c->flags &= ~CHN_F_BUSY;
384 c->pid = -1;
385 strlcpy(c->comm, CHN_COMM_UNUSED, sizeof(c->comm));
387 CHN_UNLOCK(c);
388
389 return (0);
390}
391
392int
393pcm_chnref(struct pcm_channel *c, int ref)
394{
395 PCM_BUSYASSERT(c->parentsnddev);
396 CHN_LOCKASSERT(c);
397
398 c->refcount += ref;
399
400 return (c->refcount);
401}
402
403int
404pcm_inprog(struct snddev_info *d, int delta)
405{
386 CHN_UNLOCK(c);
387
388 return (0);
389}
390
391int
392pcm_chnref(struct pcm_channel *c, int ref)
393{
394 PCM_BUSYASSERT(c->parentsnddev);
395 CHN_LOCKASSERT(c);
396
397 c->refcount += ref;
398
399 return (c->refcount);
400}
401
402int
403pcm_inprog(struct snddev_info *d, int delta)
404{
406 snd_mtxassert(d->lock);
405 PCM_LOCKASSERT(d);
407
408 d->inprog += delta;
409
410 return (d->inprog);
411}
412
413static void
414pcm_setmaxautovchans(struct snddev_info *d, int num)

--- 11 unchanged lines hidden (view full) ---

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
431 pcm_clonereset(d);
432}
433
406
407 d->inprog += delta;
408
409 return (d->inprog);
410}
411
412static void
413pcm_setmaxautovchans(struct snddev_info *d, int num)

--- 11 unchanged lines hidden (view full) ---

425 if (num >= 0 && d->rvchancount > num)
426 (void)pcm_setvchans(d, PCMDIR_REC, num, -1);
427 else if (num > 0 && d->rvchancount == 0)
428 (void)pcm_setvchans(d, PCMDIR_REC, 1, -1);
429
430 pcm_clonereset(d);
431}
432
434#ifdef USING_DEVFS
435static int
436sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS)
437{
438 struct snddev_info *d;
439 int error, unit;
440
441 unit = snd_unit;
442 error = sysctl_handle_int(oidp, &unit, 0, req);
443 if (error == 0 && req->newptr != NULL) {
444 d = devclass_get_softc(pcm_devclass, unit);
445 if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm))
446 return EINVAL;
447 snd_unit = unit;
448 }
449 return (error);
450}
451/* XXX: do we need a way to let the user change the default unit? */
452SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, CTLTYPE_INT | CTLFLAG_RW,
453 0, sizeof(int), sysctl_hw_snd_default_unit, "I", "default sound device");
433static int
434sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS)
435{
436 struct snddev_info *d;
437 int error, unit;
438
439 unit = snd_unit;
440 error = sysctl_handle_int(oidp, &unit, 0, req);
441 if (error == 0 && req->newptr != NULL) {
442 d = devclass_get_softc(pcm_devclass, unit);
443 if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm))
444 return EINVAL;
445 snd_unit = unit;
446 }
447 return (error);
448}
449/* XXX: do we need a way to let the user change the default unit? */
450SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, CTLTYPE_INT | CTLFLAG_RW,
451 0, sizeof(int), sysctl_hw_snd_default_unit, "I", "default sound device");
454#endif
455
456static int
457sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
458{
459 struct snddev_info *d;
460 int i, v, error;
461
462 v = snd_maxautovchans;

--- 23 unchanged lines hidden (view full) ---

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
493 PCM_BUSYASSERT(d);
452
453static int
454sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
455{
456 struct snddev_info *d;
457 int i, v, error;
458
459 v = snd_maxautovchans;

--- 23 unchanged lines hidden (view full) ---

483pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo)
484{
485 struct pcm_channel *ch;
486 int direction, err, rpnum, *pnum, max;
487 int udc, device, chan;
488 char *dirs, *devname, buf[CHN_NAMELEN];
489
490 PCM_BUSYASSERT(d);
494 snd_mtxassert(d->lock);
491 PCM_LOCKASSERT(d);
495 KASSERT(num >= -1, ("invalid num=%d", num));
496
497
498 switch (dir) {
499 case PCMDIR_PLAY:
500 dirs = "play";
501 direction = PCMDIR_PLAY;
502 pnum = &d->playcount;

--- 62 unchanged lines hidden (view full) ---

565 devname = dsp_unit2name(buf, sizeof(buf), udc);
566
567 if (devname == NULL) {
568 device_printf(d->dev,
569 "Failed to query device name udc=0x%08x\n", udc);
570 return (NULL);
571 }
572
492 KASSERT(num >= -1, ("invalid num=%d", num));
493
494
495 switch (dir) {
496 case PCMDIR_PLAY:
497 dirs = "play";
498 direction = PCMDIR_PLAY;
499 pnum = &d->playcount;

--- 62 unchanged lines hidden (view full) ---

562 devname = dsp_unit2name(buf, sizeof(buf), udc);
563
564 if (devname == NULL) {
565 device_printf(d->dev,
566 "Failed to query device name udc=0x%08x\n", udc);
567 return (NULL);
568 }
569
573 pcm_unlock(d);
570 PCM_UNLOCK(d);
574 ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO);
575 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO);
576 ch->unit = udc;
577 ch->pid = -1;
571 ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO);
572 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO);
573 ch->unit = udc;
574 ch->pid = -1;
575 strlcpy(ch->comm, CHN_COMM_UNUSED, sizeof(ch->comm));
578 ch->parentsnddev = d;
579 ch->parentchannel = parent;
580 ch->dev = d->dev;
581 ch->trigger = PCMTRIG_STOP;
582 snprintf(ch->name, sizeof(ch->name), "%s:%s:%s",
583 device_get_nameunit(ch->dev), dirs, devname);
584
585 err = chn_init(ch, devinfo, dir, direction);
576 ch->parentsnddev = d;
577 ch->parentchannel = parent;
578 ch->dev = d->dev;
579 ch->trigger = PCMTRIG_STOP;
580 snprintf(ch->name, sizeof(ch->name), "%s:%s:%s",
581 device_get_nameunit(ch->dev), dirs, devname);
582
583 err = chn_init(ch, devinfo, dir, direction);
586 pcm_lock(d);
584 PCM_LOCK(d);
587 if (err) {
588 device_printf(d->dev, "chn_init(%s) failed: err = %d\n",
589 ch->name, err);
590 kobj_delete(ch->methods, M_DEVBUF);
591 free(ch, M_DEVBUF);
592 return (NULL);
593 }
594

--- 20 unchanged lines hidden (view full) ---

615 free(ch, M_DEVBUF);
616
617 return (0);
618}
619
620int
621pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
622{
585 if (err) {
586 device_printf(d->dev, "chn_init(%s) failed: err = %d\n",
587 ch->name, err);
588 kobj_delete(ch->methods, M_DEVBUF);
589 free(ch, M_DEVBUF);
590 return (NULL);
591 }
592

--- 20 unchanged lines hidden (view full) ---

613 free(ch, M_DEVBUF);
614
615 return (0);
616}
617
618int
619pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
620{
623 struct pcm_channel *tmp, *after;
624 int num;
625
626 PCM_BUSYASSERT(d);
621 PCM_BUSYASSERT(d);
627 snd_mtxassert(d->lock);
622 PCM_LOCKASSERT(d);
628 KASSERT(ch != NULL && (ch->direction == PCMDIR_PLAY ||
629 ch->direction == PCMDIR_REC), ("Invalid pcm channel"));
630
623 KASSERT(ch != NULL && (ch->direction == PCMDIR_PLAY ||
624 ch->direction == PCMDIR_REC), ("Invalid pcm channel"));
625
631 after = NULL;
632 tmp = NULL;
633 num = 0;
626 CHN_INSERT_SORT_ASCEND(d, ch, channels.pcm);
634
627
635 /*
636 * Look for possible device collision.
637 */
638 CHN_FOREACH(tmp, d, channels.pcm) {
639 if (tmp->unit == ch->unit) {
640 device_printf(d->dev, "%s(): Device collision "
641 "old=%p new=%p devunit=0x%08x\n",
642 __func__, tmp, ch, ch->unit);
643 return (ENODEV);
644 }
645 if (CHN_DEV(tmp) < CHN_DEV(ch)) {
646 if (num == 0)
647 after = tmp;
648 continue;
649 } else if (CHN_DEV(tmp) > CHN_DEV(ch))
650 break;
651 num++;
652 if (CHN_CHAN(tmp) < CHN_CHAN(ch))
653 after = tmp;
654 else if (CHN_CHAN(tmp) > CHN_CHAN(ch))
655 break;
656 }
657
658 if (after != NULL) {
659 CHN_INSERT_AFTER(after, ch, channels.pcm);
660 } else {
661 CHN_INSERT_HEAD(d, ch, channels.pcm);
662 }
663
664 switch (CHN_DEV(ch)) {
665 case SND_DEV_DSPHW_PLAY:
666 d->playcount++;
667 break;
668 case SND_DEV_DSPHW_VPLAY:
669 d->pvchancount++;
670 break;
671 case SND_DEV_DSPHW_REC:

--- 12 unchanged lines hidden (view full) ---

684}
685
686int
687pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
688{
689 struct pcm_channel *tmp;
690
691 PCM_BUSYASSERT(d);
628 switch (CHN_DEV(ch)) {
629 case SND_DEV_DSPHW_PLAY:
630 d->playcount++;
631 break;
632 case SND_DEV_DSPHW_VPLAY:
633 d->pvchancount++;
634 break;
635 case SND_DEV_DSPHW_REC:

--- 12 unchanged lines hidden (view full) ---

648}
649
650int
651pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
652{
653 struct pcm_channel *tmp;
654
655 PCM_BUSYASSERT(d);
692 snd_mtxassert(d->lock);
656 PCM_LOCKASSERT(d);
693
694 tmp = NULL;
695
696 CHN_FOREACH(tmp, d, channels.pcm) {
697 if (tmp == ch)
698 break;
699 }
700

--- 28 unchanged lines hidden (view full) ---

729pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
730{
731 struct snddev_info *d = device_get_softc(dev);
732 struct pcm_channel *ch;
733 int err;
734
735 PCM_BUSYASSERT(d);
736
657
658 tmp = NULL;
659
660 CHN_FOREACH(tmp, d, channels.pcm) {
661 if (tmp == ch)
662 break;
663 }
664

--- 28 unchanged lines hidden (view full) ---

693pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
694{
695 struct snddev_info *d = device_get_softc(dev);
696 struct pcm_channel *ch;
697 int err;
698
699 PCM_BUSYASSERT(d);
700
737 pcm_lock(d);
701 PCM_LOCK(d);
738 ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo);
739 if (!ch) {
740 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n",
741 cls->name, dir, devinfo);
702 ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo);
703 if (!ch) {
704 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n",
705 cls->name, dir, devinfo);
742 pcm_unlock(d);
706 PCM_UNLOCK(d);
743 return (ENODEV);
744 }
745
746 err = pcm_chn_add(d, ch);
707 return (ENODEV);
708 }
709
710 err = pcm_chn_add(d, ch);
747 pcm_unlock(d);
711 PCM_UNLOCK(d);
748 if (err) {
749 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n",
750 ch->name, err);
751 pcm_chn_destroy(ch);
752 }
753
754 return (err);
755}

--- 4 unchanged lines hidden (view full) ---

760 struct snddev_info *d = device_get_softc(dev);
761 struct pcm_channel *ch;
762 int error;
763
764 PCM_BUSYASSERT(d);
765
766 ch = CHN_FIRST(d, channels.pcm);
767
712 if (err) {
713 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n",
714 ch->name, err);
715 pcm_chn_destroy(ch);
716 }
717
718 return (err);
719}

--- 4 unchanged lines hidden (view full) ---

724 struct snddev_info *d = device_get_softc(dev);
725 struct pcm_channel *ch;
726 int error;
727
728 PCM_BUSYASSERT(d);
729
730 ch = CHN_FIRST(d, channels.pcm);
731
768 pcm_lock(d);
732 PCM_LOCK(d);
769 error = pcm_chn_remove(d, ch);
733 error = pcm_chn_remove(d, ch);
770 pcm_unlock(d);
734 PCM_UNLOCK(d);
771 if (error)
772 return (error);
773 return (pcm_chn_destroy(ch));
774}
775
776int
777pcm_setstatus(device_t dev, char *str)
778{

--- 9 unchanged lines hidden (view full) ---

788 d->flags |= SD_F_AUTOVCHAN;
789 vchan_initsys(dev);
790 }
791
792 pcm_setmaxautovchans(d, snd_maxautovchans);
793
794 strlcpy(d->status, str, SND_STATUSLEN);
795
735 if (error)
736 return (error);
737 return (pcm_chn_destroy(ch));
738}
739
740int
741pcm_setstatus(device_t dev, char *str)
742{

--- 9 unchanged lines hidden (view full) ---

752 d->flags |= SD_F_AUTOVCHAN;
753 vchan_initsys(dev);
754 }
755
756 pcm_setmaxautovchans(d, snd_maxautovchans);
757
758 strlcpy(d->status, str, SND_STATUSLEN);
759
796 pcm_lock(d);
760 PCM_LOCK(d);
797
798 /* Last stage, enable cloning. */
799 if (d->clones != NULL)
800 (void)snd_clone_enable(d->clones);
801
802 /* Done, we're ready.. */
803 d->flags |= SD_F_REGISTERED;
804
805 PCM_RELEASE(d);
806
761
762 /* Last stage, enable cloning. */
763 if (d->clones != NULL)
764 (void)snd_clone_enable(d->clones);
765
766 /* Done, we're ready.. */
767 d->flags |= SD_F_REGISTERED;
768
769 PCM_RELEASE(d);
770
807 pcm_unlock(d);
771 PCM_UNLOCK(d);
808
809 if (snd_unit < 0 || snd_unit_auto != 0)
810 snd_unit = device_get_unit(dev);
811
812 return (0);
813}
814
815uint32_t

--- 45 unchanged lines hidden (view full) ---

861 sz = deflt;
862 }
863
864 d->bufsz = sz;
865
866 return sz;
867}
868
772
773 if (snd_unit < 0 || snd_unit_auto != 0)
774 snd_unit = device_get_unit(dev);
775
776 return (0);
777}
778
779uint32_t

--- 45 unchanged lines hidden (view full) ---

825 sz = deflt;
826 }
827
828 d->bufsz = sz;
829
830 return sz;
831}
832
869#if defined(SND_DYNSYSCTL) && defined(SND_DEBUG)
870static int
833static int
834sysctl_dev_pcm_bitperfect(SYSCTL_HANDLER_ARGS)
835{
836 struct snddev_info *d;
837 int err, val;
838
839 d = oidp->oid_arg1;
840 if (!PCM_REGISTERED(d))
841 return (ENODEV);
842
843 PCM_LOCK(d);
844 PCM_WAIT(d);
845 val = (d->flags & SD_F_BITPERFECT) ? 1 : 0;
846 PCM_ACQUIRE(d);
847 PCM_UNLOCK(d);
848
849 err = sysctl_handle_int(oidp, &val, 0, req);
850
851 if (err == 0 && req->newptr != NULL) {
852 if (!(val == 0 || val == 1)) {
853 PCM_RELEASE_QUICK(d);
854 return (EINVAL);
855 }
856
857 PCM_LOCK(d);
858
859 d->flags &= ~SD_F_BITPERFECT;
860 d->flags |= (val != 0) ? SD_F_BITPERFECT : 0;
861
862 PCM_RELEASE(d);
863 PCM_UNLOCK(d);
864 } else
865 PCM_RELEASE_QUICK(d);
866
867 return (err);
868}
869
870#ifdef SND_DEBUG
871static int
871sysctl_dev_pcm_clone_flags(SYSCTL_HANDLER_ARGS)
872{
873 struct snddev_info *d;
874 uint32_t flags;
875 int err;
876
877 d = oidp->oid_arg1;
878 if (!PCM_REGISTERED(d) || d->clones == NULL)

--- 97 unchanged lines hidden (view full) ---

976 0, sizeof(int), sysctl_hw_snd_clone_gc, "I",
977 "global clone garbage collector");
978#endif
979
980int
981pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
982{
983 struct snddev_info *d;
872sysctl_dev_pcm_clone_flags(SYSCTL_HANDLER_ARGS)
873{
874 struct snddev_info *d;
875 uint32_t flags;
876 int err;
877
878 d = oidp->oid_arg1;
879 if (!PCM_REGISTERED(d) || d->clones == NULL)

--- 97 unchanged lines hidden (view full) ---

977 0, sizeof(int), sysctl_hw_snd_clone_gc, "I",
978 "global clone garbage collector");
979#endif
980
981int
982pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
983{
984 struct snddev_info *d;
985 int i;
984
985 if (pcm_veto_load) {
986 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load);
987
988 return EINVAL;
989 }
990
991 if (device_get_unit(dev) > PCMMAXUNIT) {

--- 13 unchanged lines hidden (view full) ---

1005#if 0
1006 /*
1007 * d->flags should be cleared by the allocator of the softc.
1008 * We cannot clear this field here because several devices set
1009 * this flag before calling pcm_register().
1010 */
1011 d->flags = 0;
1012#endif
986
987 if (pcm_veto_load) {
988 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load);
989
990 return EINVAL;
991 }
992
993 if (device_get_unit(dev) > PCMMAXUNIT) {

--- 13 unchanged lines hidden (view full) ---

1007#if 0
1008 /*
1009 * d->flags should be cleared by the allocator of the softc.
1010 * We cannot clear this field here because several devices set
1011 * this flag before calling pcm_register().
1012 */
1013 d->flags = 0;
1014#endif
1015 i = 0;
1016 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
1017 "vpc", &i) != 0 || i != 0)
1018 d->flags |= SD_F_VPC;
1019
1020 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
1021 "bitperfect", &i) == 0 && i != 0)
1022 d->flags |= SD_F_BITPERFECT;
1023
1013 d->devinfo = devinfo;
1014 d->devcount = 0;
1015 d->reccount = 0;
1016 d->playcount = 0;
1017 d->pvchancount = 0;
1018 d->rvchancount = 0;
1019 d->pvchanrate = 0;
1020 d->pvchanformat = 0;
1021 d->rvchanrate = 0;
1022 d->rvchanformat = 0;
1023 d->inprog = 0;
1024
1025 /*
1026 * Create clone manager, disabled by default. Cloning will be
1024 d->devinfo = devinfo;
1025 d->devcount = 0;
1026 d->reccount = 0;
1027 d->playcount = 0;
1028 d->pvchancount = 0;
1029 d->rvchancount = 0;
1030 d->pvchanrate = 0;
1031 d->pvchanformat = 0;
1032 d->rvchanrate = 0;
1033 d->rvchanformat = 0;
1034 d->inprog = 0;
1035
1036 /*
1037 * Create clone manager, disabled by default. Cloning will be
1027 * enabled during final stage of driver iniialization through
1038 * enabled during final stage of driver initialization through
1028 * pcm_setstatus().
1029 */
1030 d->clones = snd_clone_create(SND_U_MASK | SND_D_MASK, PCMMAXCLONE,
1031 SND_CLONE_DEADLINE_DEFAULT, SND_CLONE_WAITOK |
1032 SND_CLONE_GC_ENABLE | SND_CLONE_GC_UNREF |
1033 SND_CLONE_GC_LASTREF | SND_CLONE_GC_EXPIRED);
1034
1035 if (bootverbose != 0 || snd_verbose > 3) {
1036 device_printf(dev,
1037 "clone manager: deadline=%dms flags=0x%08x\n",
1038 snd_clone_getdeadline(d->clones),
1039 snd_clone_getflags(d->clones));
1040 }
1041
1042 CHN_INIT(d, channels.pcm);
1043 CHN_INIT(d, channels.pcm.busy);
1039 * pcm_setstatus().
1040 */
1041 d->clones = snd_clone_create(SND_U_MASK | SND_D_MASK, PCMMAXCLONE,
1042 SND_CLONE_DEADLINE_DEFAULT, SND_CLONE_WAITOK |
1043 SND_CLONE_GC_ENABLE | SND_CLONE_GC_UNREF |
1044 SND_CLONE_GC_LASTREF | SND_CLONE_GC_EXPIRED);
1045
1046 if (bootverbose != 0 || snd_verbose > 3) {
1047 device_printf(dev,
1048 "clone manager: deadline=%dms flags=0x%08x\n",
1049 snd_clone_getdeadline(d->clones),
1050 snd_clone_getflags(d->clones));
1051 }
1052
1053 CHN_INIT(d, channels.pcm);
1054 CHN_INIT(d, channels.pcm.busy);
1055 CHN_INIT(d, channels.pcm.opened);
1044
1045 /* XXX This is incorrect, but lets play along for now. */
1046 if ((numplay == 0 || numrec == 0) && numplay != numrec)
1047 d->flags |= SD_F_SIMPLEX;
1048
1056
1057 /* XXX This is incorrect, but lets play along for now. */
1058 if ((numplay == 0 || numrec == 0) && numplay != numrec)
1059 d->flags |= SD_F_SIMPLEX;
1060
1049 d->fakechan = fkchan_setup(dev);
1050 chn_init(d->fakechan, NULL, 0, 0);
1051
1052#ifdef SND_DYNSYSCTL
1053 sysctl_ctx_init(&d->play_sysctl_ctx);
1054 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx,
1055 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play",
1056 CTLFLAG_RD, 0, "playback channels node");
1057 sysctl_ctx_init(&d->rec_sysctl_ctx);
1058 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx,
1059 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec",
1060 CTLFLAG_RD, 0, "record channels node");
1061 /* XXX: an user should be able to set this with a control tool, the
1062 sysadmin then needs min+max sysctls for this */
1063 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
1064 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1065 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size");
1061 sysctl_ctx_init(&d->play_sysctl_ctx);
1062 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx,
1063 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play",
1064 CTLFLAG_RD, 0, "playback channels node");
1065 sysctl_ctx_init(&d->rec_sysctl_ctx);
1066 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx,
1067 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec",
1068 CTLFLAG_RD, 0, "record channels node");
1069 /* XXX: an user should be able to set this with a control tool, the
1070 sysadmin then needs min+max sysctls for this */
1071 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
1072 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1073 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size");
1074 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1075 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1076 "bitperfect", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d),
1077 sysctl_dev_pcm_bitperfect, "I",
1078 "bit-perfect playback/recording (0=disable, 1=enable)");
1066#ifdef SND_DEBUG
1067 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1068 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1069 "clone_flags", CTLTYPE_UINT | CTLFLAG_RW, d, sizeof(d),
1070 sysctl_dev_pcm_clone_flags, "IU",
1071 "clone flags");
1072 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1073 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1074 "clone_deadline", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d),
1075 sysctl_dev_pcm_clone_deadline, "I",
1076 "clone expiration deadline (ms)");
1077 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1078 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1079 "clone_gc", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d),
1080 sysctl_dev_pcm_clone_gc, "I",
1081 "clone garbage collector");
1082#endif
1079#ifdef SND_DEBUG
1080 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1081 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1082 "clone_flags", CTLTYPE_UINT | CTLFLAG_RW, d, sizeof(d),
1083 sysctl_dev_pcm_clone_flags, "IU",
1084 "clone flags");
1085 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1086 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1087 "clone_deadline", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d),
1088 sysctl_dev_pcm_clone_deadline, "I",
1089 "clone expiration deadline (ms)");
1090 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1091 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1092 "clone_gc", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d),
1093 sysctl_dev_pcm_clone_gc, "I",
1094 "clone garbage collector");
1095#endif
1083#endif
1084
1085 if (numplay > 0 || numrec > 0) {
1086 d->flags |= SD_F_AUTOVCHAN;
1087 vchan_initsys(dev);
1088 }
1089
1096
1097 if (numplay > 0 || numrec > 0) {
1098 d->flags |= SD_F_AUTOVCHAN;
1099 vchan_initsys(dev);
1100 }
1101
1102 if (d->flags & SD_F_EQ)
1103 feeder_eq_initsys(dev);
1104
1090 sndstat_register(dev, d->status, sndstat_prepare_pcm);
1091
1092 return 0;
1093}
1094
1095int
1096pcm_unregister(device_t dev)
1097{

--- 10 unchanged lines hidden (view full) ---

1108 return (0);
1109 }
1110
1111 if (sndstat_acquire(td) != 0) {
1112 device_printf(dev, "unregister: sndstat busy\n");
1113 return (EBUSY);
1114 }
1115
1105 sndstat_register(dev, d->status, sndstat_prepare_pcm);
1106
1107 return 0;
1108}
1109
1110int
1111pcm_unregister(device_t dev)
1112{

--- 10 unchanged lines hidden (view full) ---

1123 return (0);
1124 }
1125
1126 if (sndstat_acquire(td) != 0) {
1127 device_printf(dev, "unregister: sndstat busy\n");
1128 return (EBUSY);
1129 }
1130
1116 pcm_lock(d);
1131 PCM_LOCK(d);
1117 PCM_WAIT(d);
1118
1119 if (d->inprog != 0) {
1120 device_printf(dev, "unregister: operation in progress\n");
1132 PCM_WAIT(d);
1133
1134 if (d->inprog != 0) {
1135 device_printf(dev, "unregister: operation in progress\n");
1121 pcm_unlock(d);
1136 PCM_UNLOCK(d);
1122 sndstat_release(td);
1123 return (EBUSY);
1124 }
1125
1126 PCM_ACQUIRE(d);
1137 sndstat_release(td);
1138 return (EBUSY);
1139 }
1140
1141 PCM_ACQUIRE(d);
1127 pcm_unlock(d);
1142 PCM_UNLOCK(d);
1128
1129 CHN_FOREACH(ch, d, channels.pcm) {
1130 CHN_LOCK(ch);
1131 if (ch->refcount > 0) {
1132 device_printf(dev,
1133 "unregister: channel %s busy (pid %d)\n",
1134 ch->name, ch->pid);
1135 CHN_UNLOCK(ch);

--- 6 unchanged lines hidden (view full) ---

1142
1143 if (d->clones != NULL) {
1144 if (snd_clone_busy(d->clones) != 0) {
1145 device_printf(dev, "unregister: clone busy\n");
1146 PCM_RELEASE_QUICK(d);
1147 sndstat_release(td);
1148 return (EBUSY);
1149 } else {
1143
1144 CHN_FOREACH(ch, d, channels.pcm) {
1145 CHN_LOCK(ch);
1146 if (ch->refcount > 0) {
1147 device_printf(dev,
1148 "unregister: channel %s busy (pid %d)\n",
1149 ch->name, ch->pid);
1150 CHN_UNLOCK(ch);

--- 6 unchanged lines hidden (view full) ---

1157
1158 if (d->clones != NULL) {
1159 if (snd_clone_busy(d->clones) != 0) {
1160 device_printf(dev, "unregister: clone busy\n");
1161 PCM_RELEASE_QUICK(d);
1162 sndstat_release(td);
1163 return (EBUSY);
1164 } else {
1150 pcm_lock(d);
1165 PCM_LOCK(d);
1151 (void)snd_clone_disable(d->clones);
1166 (void)snd_clone_disable(d->clones);
1152 pcm_unlock(d);
1167 PCM_UNLOCK(d);
1153 }
1154 }
1155
1156 if (mixer_uninit(dev) == EBUSY) {
1157 device_printf(dev, "unregister: mixer busy\n");
1168 }
1169 }
1170
1171 if (mixer_uninit(dev) == EBUSY) {
1172 device_printf(dev, "unregister: mixer busy\n");
1158 pcm_lock(d);
1173 PCM_LOCK(d);
1159 if (d->clones != NULL)
1160 (void)snd_clone_enable(d->clones);
1161 PCM_RELEASE(d);
1174 if (d->clones != NULL)
1175 (void)snd_clone_enable(d->clones);
1176 PCM_RELEASE(d);
1162 pcm_unlock(d);
1177 PCM_UNLOCK(d);
1163 sndstat_release(td);
1164 return (EBUSY);
1165 }
1166
1178 sndstat_release(td);
1179 return (EBUSY);
1180 }
1181
1167 pcm_lock(d);
1182 PCM_LOCK(d);
1168 d->flags |= SD_F_DYING;
1169 d->flags &= ~SD_F_REGISTERED;
1183 d->flags |= SD_F_DYING;
1184 d->flags &= ~SD_F_REGISTERED;
1170 pcm_unlock(d);
1185 PCM_UNLOCK(d);
1171
1172 /*
1173 * No lock being held, so this thing can be flushed without
1174 * stucking into devdrn oblivion.
1175 */
1176 if (d->clones != NULL) {
1177 snd_clone_destroy(d->clones);
1178 d->clones = NULL;
1179 }
1180
1186
1187 /*
1188 * No lock being held, so this thing can be flushed without
1189 * stucking into devdrn oblivion.
1190 */
1191 if (d->clones != NULL) {
1192 snd_clone_destroy(d->clones);
1193 d->clones = NULL;
1194 }
1195
1181#ifdef SND_DYNSYSCTL
1182 if (d->play_sysctl_tree != NULL) {
1183 sysctl_ctx_free(&d->play_sysctl_ctx);
1184 d->play_sysctl_tree = NULL;
1185 }
1186 if (d->rec_sysctl_tree != NULL) {
1187 sysctl_ctx_free(&d->rec_sysctl_ctx);
1188 d->rec_sysctl_tree = NULL;
1189 }
1196 if (d->play_sysctl_tree != NULL) {
1197 sysctl_ctx_free(&d->play_sysctl_ctx);
1198 d->play_sysctl_tree = NULL;
1199 }
1200 if (d->rec_sysctl_tree != NULL) {
1201 sysctl_ctx_free(&d->rec_sysctl_ctx);
1202 d->rec_sysctl_tree = NULL;
1203 }
1190#endif
1191
1192 while (!CHN_EMPTY(d, channels.pcm))
1193 pcm_killchan(dev);
1194
1204
1205 while (!CHN_EMPTY(d, channels.pcm))
1206 pcm_killchan(dev);
1207
1195 chn_kill(d->fakechan);
1196 fkchan_kill(d->fakechan);
1197
1198 dsp_cdevinfo_flush(d);
1199
1208 dsp_cdevinfo_flush(d);
1209
1200 pcm_lock(d);
1210 PCM_LOCK(d);
1201 PCM_RELEASE(d);
1202 cv_destroy(&d->cv);
1211 PCM_RELEASE(d);
1212 cv_destroy(&d->cv);
1203 pcm_unlock(d);
1213 PCM_UNLOCK(d);
1204 snd_mtxfree(d->lock);
1205 sndstat_unregister(dev);
1206 sndstat_release(td);
1207
1208 if (snd_unit == device_get_unit(dev)) {
1209 /*
1210 * Reassign default unit to the next available dev, but
1211 * first, reset snd_unit to something ridiculous.

--- 11 unchanged lines hidden (view full) ---

1223 }
1224 }
1225
1226 return (0);
1227}
1228
1229/************************************************************************/
1230
1214 snd_mtxfree(d->lock);
1215 sndstat_unregister(dev);
1216 sndstat_release(td);
1217
1218 if (snd_unit == device_get_unit(dev)) {
1219 /*
1220 * Reassign default unit to the next available dev, but
1221 * first, reset snd_unit to something ridiculous.

--- 11 unchanged lines hidden (view full) ---

1233 }
1234 }
1235
1236 return (0);
1237}
1238
1239/************************************************************************/
1240
1231static int
1232sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose)
1233{
1234 struct snddev_info *d;
1235 struct pcm_channel *c;
1236 struct pcm_feeder *f;
1237
1238 if (verbose < 1)
1239 return 0;
1240
1241 d = device_get_softc(dev);
1242 if (!d)
1243 return ENXIO;
1244
1245 PCM_BUSYASSERT(d);
1246
1247 if (CHN_EMPTY(d, channels.pcm)) {
1248 sbuf_printf(s, " (mixer only)");
1249 return 0;
1250 }
1251
1252 sbuf_printf(s, " (%dp:%dv/%dr:%dv channels%s%s)",
1253 d->playcount, d->pvchancount,
1254 d->reccount, d->rvchancount,
1255 (d->flags & SD_F_SIMPLEX)? "" : " duplex",
1256#ifdef USING_DEVFS
1257 (device_get_unit(dev) == snd_unit)? " default" : ""
1258#else
1259 ""
1260#endif
1261 );
1262
1263 if (verbose <= 1)
1264 return 0;
1265
1266 CHN_FOREACH(c, d, channels.pcm) {
1267
1268 KASSERT(c->bufhard != NULL && c->bufsoft != NULL,
1269 ("hosed pcm channel setup"));
1270
1271 sbuf_printf(s, "\n\t");
1272
1273 /* it would be better to indent child channels */
1274 sbuf_printf(s, "%s[%s]: ", c->parentchannel? c->parentchannel->name : "", c->name);
1275 sbuf_printf(s, "spd %d", c->speed);
1276 if (c->speed != sndbuf_getspd(c->bufhard))
1277 sbuf_printf(s, "/%d", sndbuf_getspd(c->bufhard));
1278 sbuf_printf(s, ", fmt 0x%08x", c->format);
1279 if (c->format != sndbuf_getfmt(c->bufhard))
1280 sbuf_printf(s, "/0x%08x", sndbuf_getfmt(c->bufhard));
1281 sbuf_printf(s, ", flags 0x%08x, 0x%08x", c->flags, c->feederflags);
1282 if (c->pid != -1)
1283 sbuf_printf(s, ", pid %d", c->pid);
1284 sbuf_printf(s, "\n\t");
1285
1286 sbuf_printf(s, "interrupts %d, ", c->interrupts);
1287 if (c->direction == PCMDIR_REC)
1288 sbuf_printf(s, "overruns %d, feed %u, hfree %d, sfree %d [b:%d/%d/%d|bs:%d/%d/%d]",
1289 c->xruns, c->feedcount, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft),
1290 sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard),
1291 sndbuf_getblkcnt(c->bufhard),
1292 sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft),
1293 sndbuf_getblkcnt(c->bufsoft));
1294 else
1295 sbuf_printf(s, "underruns %d, feed %u, ready %d [b:%d/%d/%d|bs:%d/%d/%d]",
1296 c->xruns, c->feedcount, sndbuf_getready(c->bufsoft),
1297 sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard),
1298 sndbuf_getblkcnt(c->bufhard),
1299 sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft),
1300 sndbuf_getblkcnt(c->bufsoft));
1301 sbuf_printf(s, "\n\t");
1302
1303 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "hardware" : "userland");
1304 sbuf_printf(s, " -> ");
1305 f = c->feeder;
1306 while (f->source != NULL)
1307 f = f->source;
1308 while (f != NULL) {
1309 sbuf_printf(s, "%s", f->class->name);
1310 if (f->desc->type == FEEDER_FMT)
1311 sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out);
1312 if (f->desc->type == FEEDER_RATE)
1313 sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST));
1314 if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER ||
1315 f->desc->type == FEEDER_VOLUME)
1316 sbuf_printf(s, "(0x%08x)", f->desc->out);
1317 sbuf_printf(s, " -> ");
1318 f = f->parent;
1319 }
1320 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "userland" : "hardware");
1321 }
1322
1323 return 0;
1324}
1325
1326/************************************************************************/
1327
1328#ifdef SND_DYNSYSCTL
1329int
1330sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
1331{
1332 struct snddev_info *d;
1333 int direction, vchancount;
1334 int err, cnt;
1335
1336 d = devclass_get_softc(pcm_devclass, VCHAN_SYSCTL_UNIT(oidp->oid_arg1));
1337 if (!PCM_REGISTERED(d) || !(d->flags & SD_F_AUTOVCHAN))
1338 return (EINVAL);
1339
1340 pcm_lock(d);
1341 PCM_WAIT(d);
1342
1343 switch (VCHAN_SYSCTL_DIR(oidp->oid_arg1)) {
1344 case VCHAN_PLAY:
1345 direction = PCMDIR_PLAY;
1346 vchancount = d->pvchancount;
1347 cnt = d->playcount;
1348 break;
1349 case VCHAN_REC:
1350 direction = PCMDIR_REC;
1351 vchancount = d->rvchancount;
1352 cnt = d->reccount;
1353 break;
1354 default:
1355 pcm_unlock(d);
1356 return (EINVAL);
1357 break;
1358 }
1359
1360 if (cnt < 1) {
1361 pcm_unlock(d);
1362 return (ENODEV);
1363 }
1364
1365 PCM_ACQUIRE(d);
1366 pcm_unlock(d);
1367
1368 cnt = vchancount;
1369 err = sysctl_handle_int(oidp, &cnt, 0, req);
1370
1371 if (err == 0 && req->newptr != NULL && vchancount != cnt) {
1372 if (cnt < 0)
1373 cnt = 0;
1374 if (cnt > SND_MAXVCHANS)
1375 cnt = SND_MAXVCHANS;
1376 err = pcm_setvchans(d, direction, cnt, -1);
1377 }
1378
1379 PCM_RELEASE_QUICK(d);
1380
1381 return err;
1382}
1383#endif
1384
1385/************************************************************************/
1386
1387/**
1388 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl.
1389 *
1390 * @param si Pointer to oss_sysinfo struct where information about the
1391 * sound subsystem will be written/copied.
1392 *
1393 * This routine returns information about the sound system, such as the
1394 * current OSS version, number of audio, MIDI, and mixer drivers, etc.

--- 38 unchanged lines hidden (view full) ---

1433 i < devclass_get_maxunit(pcm_devclass); i++) {
1434 d = devclass_get_softc(pcm_devclass, i);
1435 if (!PCM_REGISTERED(d))
1436 continue;
1437
1438 /* XXX Need Giant magic entry ??? */
1439
1440 /* See note in function's docblock */
1241/**
1242 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl.
1243 *
1244 * @param si Pointer to oss_sysinfo struct where information about the
1245 * sound subsystem will be written/copied.
1246 *
1247 * This routine returns information about the sound system, such as the
1248 * current OSS version, number of audio, MIDI, and mixer drivers, etc.

--- 38 unchanged lines hidden (view full) ---

1287 i < devclass_get_maxunit(pcm_devclass); i++) {
1288 d = devclass_get_softc(pcm_devclass, i);
1289 if (!PCM_REGISTERED(d))
1290 continue;
1291
1292 /* XXX Need Giant magic entry ??? */
1293
1294 /* See note in function's docblock */
1441 mtx_assert(d->lock, MA_NOTOWNED);
1442 pcm_lock(d);
1295 PCM_UNLOCKASSERT(d);
1296 PCM_LOCK(d);
1443
1444 si->numaudios += d->devcount;
1445 ++ncards;
1446
1447 CHN_FOREACH(c, d, channels.pcm) {
1297
1298 si->numaudios += d->devcount;
1299 ++ncards;
1300
1301 CHN_FOREACH(c, d, channels.pcm) {
1448 mtx_assert(c->lock, MA_NOTOWNED);
1302 CHN_UNLOCKASSERT(c);
1449 CHN_LOCK(c);
1450 if (c->flags & CHN_F_BUSY)
1451 si->openedaudio[j / intnbits] |=
1452 (1 << (j % intnbits));
1453 CHN_UNLOCK(c);
1454 j++;
1455 }
1456
1303 CHN_LOCK(c);
1304 if (c->flags & CHN_F_BUSY)
1305 si->openedaudio[j / intnbits] |=
1306 (1 << (j % intnbits));
1307 CHN_UNLOCK(c);
1308 j++;
1309 }
1310
1457 pcm_unlock(d);
1311 PCM_UNLOCK(d);
1458 }
1459 si->numaudioengines = si->numaudios;
1460
1461 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */
1462 /**
1463 * @todo Collect num{midis,timers}.
1464 *
1465 * Need access to sound/midi/midi.c::midistat_lock in order

--- 39 unchanged lines hidden (view full) ---

1505 i < devclass_get_maxunit(pcm_devclass); i++) {
1506 d = devclass_get_softc(pcm_devclass, i);
1507 if (!PCM_REGISTERED(d))
1508 continue;
1509
1510 if (ncards++ != si->card)
1511 continue;
1512
1312 }
1313 si->numaudioengines = si->numaudios;
1314
1315 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */
1316 /**
1317 * @todo Collect num{midis,timers}.
1318 *
1319 * Need access to sound/midi/midi.c::midistat_lock in order

--- 39 unchanged lines hidden (view full) ---

1359 i < devclass_get_maxunit(pcm_devclass); i++) {
1360 d = devclass_get_softc(pcm_devclass, i);
1361 if (!PCM_REGISTERED(d))
1362 continue;
1363
1364 if (ncards++ != si->card)
1365 continue;
1366
1513 mtx_assert(d->lock, MA_NOTOWNED);
1514 pcm_lock(d);
1367 PCM_UNLOCKASSERT(d);
1368 PCM_LOCK(d);
1515
1516 strlcpy(si->shortname, device_get_nameunit(d->dev),
1517 sizeof(si->shortname));
1518 strlcpy(si->longname, device_get_desc(d->dev),
1519 sizeof(si->longname));
1520 strlcpy(si->hw_info, d->status, sizeof(si->hw_info));
1521 si->intr_count = si->ack_count = 0;
1369
1370 strlcpy(si->shortname, device_get_nameunit(d->dev),
1371 sizeof(si->shortname));
1372 strlcpy(si->longname, device_get_desc(d->dev),
1373 sizeof(si->longname));
1374 strlcpy(si->hw_info, d->status, sizeof(si->hw_info));
1375 si->intr_count = si->ack_count = 0;
1522 pcm_unlock(d);
1376
1377 PCM_UNLOCK(d);
1378
1523 return (0);
1524 }
1525 return (ENXIO);
1526}
1527
1528/************************************************************************/
1529
1530static int

--- 15 unchanged lines hidden (view full) ---

1546 if (ret != 0)
1547 break;
1548 if (pcmsg_unrhdr != NULL) {
1549 delete_unrhdr(pcmsg_unrhdr);
1550 pcmsg_unrhdr = NULL;
1551 }
1552 break;
1553 default:
1379 return (0);
1380 }
1381 return (ENXIO);
1382}
1383
1384/************************************************************************/
1385
1386static int

--- 15 unchanged lines hidden (view full) ---

1402 if (ret != 0)
1403 break;
1404 if (pcmsg_unrhdr != NULL) {
1405 delete_unrhdr(pcmsg_unrhdr);
1406 pcmsg_unrhdr = NULL;
1407 }
1408 break;
1409 default:
1554 ret = EOPNOTSUPP;
1410 ret = ENOTSUP;
1555 }
1556
1557 return ret;
1558#endif
1559}
1560
1561DEV_MODULE(sound, sound_modevent, NULL);
1562MODULE_VERSION(sound, SOUND_MODVER);
1411 }
1412
1413 return ret;
1414#endif
1415}
1416
1417DEV_MODULE(sound, sound_modevent, NULL);
1418MODULE_VERSION(sound, SOUND_MODVER);