1170159Sariff/*-
2170159Sariff * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
3170159Sariff * All rights reserved.
4170159Sariff *
5170159Sariff * Redistribution and use in source and binary forms, with or without
6170159Sariff * modification, are permitted provided that the following conditions
7170159Sariff * are met:
8170159Sariff * 1. Redistributions of source code must retain the above copyright
9170159Sariff *    notice, this list of conditions and the following disclaimer.
10170159Sariff * 2. Redistributions in binary form must reproduce the above copyright
11170159Sariff *    notice, this list of conditions and the following disclaimer in the
12170159Sariff *    documentation and/or other materials provided with the distribution.
13170159Sariff *
14170159Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15170159Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16170159Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17170159Sariff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18170159Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19170159Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20170159Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21170159Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22170159Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23170159Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24170159Sariff * SUCH DAMAGE.
25170159Sariff *
26170159Sariff * $FreeBSD$
27170159Sariff */
28170159Sariff
29170159Sariff#include <sys/param.h>
30170159Sariff#include <sys/systm.h>
31170159Sariff#include <sys/conf.h>
32170159Sariff#include <sys/kernel.h>
33170159Sariff#include <sys/malloc.h>
34170159Sariff#include <sys/proc.h>
35170159Sariff
36193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
37193640Sariff#include "opt_snd.h"
38193640Sariff#endif
39193640Sariff
40170159Sariff#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
41170159Sariff#include <dev/sound/pcm/sound.h>
42170159Sariff#endif
43170159Sariff
44170159Sariff#include <dev/sound/clone.h>
45170159Sariff
46170159Sariff/*
47170159Sariff * So here we go again, another clonedevs manager. Unlike default clonedevs,
48170159Sariff * this clone manager is designed to withstand various abusive behavior
49170159Sariff * (such as 'while : ; do ls /dev/whatever ; done', etc.), reusable object
50170159Sariff * after reaching certain expiration threshold, aggressive garbage collector,
51170159Sariff * transparent device allocator and concurrency handling across multiple
52170159Sariff * thread/proc. Due to limited information given by dev_clone EVENTHANDLER,
53170159Sariff * we don't have much clues whether the caller wants a real open() or simply
54170159Sariff * making fun of us with things like stat(), mtime() etc. Assuming that:
55170159Sariff * 1) Time window between dev_clone EH <-> real open() should be small
56170159Sariff * enough and 2) mtime()/stat() etc. always looks like a half way / stalled
57170159Sariff * operation, we can decide whether a new cdev must be created, old
58170159Sariff * (expired) cdev can be reused or an existing cdev can be shared.
59170159Sariff *
60170159Sariff * Most of the operations and logics are generic enough and can be applied
61170159Sariff * on other places (such as if_tap, snp, etc).  Perhaps this can be
62170159Sariff * rearranged to complement clone_*(). However, due to this still being
63170159Sariff * specific to the sound driver (and as a proof of concept on how it can be
64170159Sariff * done), si_drv2 is used to keep the pointer of the clone list entry to
65170159Sariff * avoid expensive lookup.
66170159Sariff */
67170159Sariff
68170159Sariff/* clone entry */
69170159Sariffstruct snd_clone_entry {
70170159Sariff	TAILQ_ENTRY(snd_clone_entry) link;
71170159Sariff	struct snd_clone *parent;
72170159Sariff	struct cdev *devt;
73170159Sariff	struct timespec tsp;
74170159Sariff	uint32_t flags;
75170159Sariff	pid_t pid;
76170159Sariff	int unit;
77170159Sariff};
78170159Sariff
79170159Sariff/* clone manager */
80170159Sariffstruct snd_clone {
81170159Sariff	TAILQ_HEAD(link_head, snd_clone_entry) head;
82170159Sariff	struct timespec tsp;
83170159Sariff	int refcount;
84170159Sariff	int size;
85170159Sariff	int typemask;
86170159Sariff	int maxunit;
87170159Sariff	int deadline;
88170159Sariff	uint32_t flags;
89170159Sariff};
90170159Sariff
91170159Sariff#ifdef SND_DIAGNOSTIC
92170159Sariff#define SND_CLONE_ASSERT(x, y)		do {			\
93170159Sariff	if (!(x))						\
94170159Sariff		panic y;					\
95193640Sariff} while (0)
96170159Sariff#else
97193640Sariff#define SND_CLONE_ASSERT(...)		KASSERT(__VA_ARGS__)
98170159Sariff#endif
99170159Sariff
100170159Sariff/*
101170159Sariff * Shamelessly ripped off from vfs_subr.c
102170159Sariff * We need at least 1/HZ precision as default timestamping.
103170159Sariff */
104170159Sariffenum { SND_TSP_SEC, SND_TSP_HZ, SND_TSP_USEC, SND_TSP_NSEC };
105170159Sariff
106170159Sariffstatic int snd_timestamp_precision = SND_TSP_HZ;
107170159SariffTUNABLE_INT("hw.snd.timestamp_precision", &snd_timestamp_precision);
108170159Sariff
109170159Sariffvoid
110170159Sariffsnd_timestamp(struct timespec *tsp)
111170159Sariff{
112170159Sariff	struct timeval tv;
113170159Sariff
114170159Sariff	switch (snd_timestamp_precision) {
115170159Sariff	case SND_TSP_SEC:
116170159Sariff		tsp->tv_sec = time_second;
117170159Sariff		tsp->tv_nsec = 0;
118170159Sariff		break;
119170159Sariff	case SND_TSP_HZ:
120170159Sariff		getnanouptime(tsp);
121170159Sariff		break;
122170159Sariff	case SND_TSP_USEC:
123170159Sariff		microuptime(&tv);
124170159Sariff		TIMEVAL_TO_TIMESPEC(&tv, tsp);
125170159Sariff		break;
126170159Sariff	case SND_TSP_NSEC:
127170159Sariff		nanouptime(tsp);
128170159Sariff		break;
129170159Sariff	default:
130170159Sariff		snd_timestamp_precision = SND_TSP_HZ;
131170159Sariff		getnanouptime(tsp);
132170159Sariff		break;
133170159Sariff	}
134170159Sariff}
135170159Sariff
136170159Sariff#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
137170159Sariffstatic int
138170159Sariffsysctl_hw_snd_timestamp_precision(SYSCTL_HANDLER_ARGS)
139170159Sariff{
140170159Sariff	int err, val;
141170159Sariff
142170159Sariff	val = snd_timestamp_precision;
143170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
144170159Sariff	if (err == 0 && req->newptr != NULL) {
145170159Sariff		switch (val) {
146170159Sariff		case SND_TSP_SEC:
147170159Sariff		case SND_TSP_HZ:
148170159Sariff		case SND_TSP_USEC:
149170159Sariff		case SND_TSP_NSEC:
150170159Sariff			snd_timestamp_precision = val;
151170159Sariff			break;
152170159Sariff		default:
153170159Sariff			break;
154170159Sariff		}
155170159Sariff	}
156170159Sariff
157170159Sariff	return (err);
158170159Sariff}
159170159SariffSYSCTL_PROC(_hw_snd, OID_AUTO, timestamp_precision, CTLTYPE_INT | CTLFLAG_RW,
160170159Sariff    0, sizeof(int), sysctl_hw_snd_timestamp_precision, "I",
161170159Sariff    "timestamp precision (0=s 1=hz 2=us 3=ns)");
162170159Sariff#endif
163170159Sariff
164170159Sariff/*
165170719Sariff * snd_clone_create() : Return opaque allocated clone manager.
166170159Sariff */
167170159Sariffstruct snd_clone *
168170719Sariffsnd_clone_create(int typemask, int maxunit, int deadline, uint32_t flags)
169170159Sariff{
170170159Sariff	struct snd_clone *c;
171170159Sariff
172170159Sariff	SND_CLONE_ASSERT(!(typemask & ~SND_CLONE_MAXUNIT),
173170159Sariff	    ("invalid typemask: 0x%08x", typemask));
174170159Sariff	SND_CLONE_ASSERT(maxunit == -1 ||
175170159Sariff	    !(maxunit & ~(~typemask & SND_CLONE_MAXUNIT)),
176170159Sariff	    ("maxunit overflow: typemask=0x%08x maxunit=%d",
177170159Sariff	    typemask, maxunit));
178170159Sariff	SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
179170159Sariff	    ("invalid clone flags=0x%08x", flags));
180170159Sariff
181170159Sariff	c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO);
182170159Sariff	c->refcount = 0;
183170159Sariff	c->size = 0;
184170159Sariff	c->typemask = typemask;
185170159Sariff	c->maxunit = (maxunit == -1) ? (~typemask & SND_CLONE_MAXUNIT) :
186170159Sariff	    maxunit;
187170159Sariff	c->deadline = deadline;
188170159Sariff	c->flags = flags;
189170159Sariff	snd_timestamp(&c->tsp);
190170159Sariff	TAILQ_INIT(&c->head);
191170159Sariff
192170159Sariff	return (c);
193170159Sariff}
194170159Sariff
195170159Sariffint
196170159Sariffsnd_clone_busy(struct snd_clone *c)
197170159Sariff{
198170159Sariff	struct snd_clone_entry *ce;
199170159Sariff
200170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
201170159Sariff
202170159Sariff	if (c->size == 0)
203170159Sariff		return (0);
204170159Sariff
205170159Sariff	TAILQ_FOREACH(ce, &c->head, link) {
206170159Sariff		if ((ce->flags & SND_CLONE_BUSY) ||
207170159Sariff		    (ce->devt != NULL && ce->devt->si_threadcount != 0))
208170159Sariff			return (EBUSY);
209170159Sariff	}
210170159Sariff
211170159Sariff	return (0);
212170159Sariff}
213170159Sariff
214170159Sariff/*
215170159Sariff * snd_clone_enable()/disable() : Suspend/resume clone allocation through
216170159Sariff * snd_clone_alloc(). Everything else will not be affected by this.
217170159Sariff */
218170159Sariffint
219170159Sariffsnd_clone_enable(struct snd_clone *c)
220170159Sariff{
221170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
222170159Sariff
223170159Sariff	if (c->flags & SND_CLONE_ENABLE)
224170159Sariff		return (EINVAL);
225170159Sariff
226170159Sariff	c->flags |= SND_CLONE_ENABLE;
227170159Sariff
228170159Sariff	return (0);
229170159Sariff}
230170159Sariff
231170159Sariffint
232170159Sariffsnd_clone_disable(struct snd_clone *c)
233170159Sariff{
234170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
235170159Sariff
236170159Sariff	if (!(c->flags & SND_CLONE_ENABLE))
237170159Sariff		return (EINVAL);
238170159Sariff
239170159Sariff	c->flags &= ~SND_CLONE_ENABLE;
240170159Sariff
241170159Sariff	return (0);
242170159Sariff}
243170159Sariff
244170159Sariff/*
245170159Sariff * Getters / Setters. Not worth explaining :)
246170159Sariff */
247170159Sariffint
248170159Sariffsnd_clone_getsize(struct snd_clone *c)
249170159Sariff{
250170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
251170159Sariff
252170159Sariff	return (c->size);
253170159Sariff}
254170159Sariff
255170159Sariffint
256170159Sariffsnd_clone_getmaxunit(struct snd_clone *c)
257170159Sariff{
258170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
259170159Sariff
260170159Sariff	return (c->maxunit);
261170159Sariff}
262170159Sariff
263170159Sariffint
264170159Sariffsnd_clone_setmaxunit(struct snd_clone *c, int maxunit)
265170159Sariff{
266170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
267170159Sariff	SND_CLONE_ASSERT(maxunit == -1 ||
268170159Sariff	    !(maxunit & ~(~c->typemask & SND_CLONE_MAXUNIT)),
269170159Sariff	    ("maxunit overflow: typemask=0x%08x maxunit=%d",
270170159Sariff	    c->typemask, maxunit));
271170159Sariff
272170159Sariff	c->maxunit = (maxunit == -1) ? (~c->typemask & SND_CLONE_MAXUNIT) :
273170159Sariff	    maxunit;
274170159Sariff
275170159Sariff	return (c->maxunit);
276170159Sariff}
277170159Sariff
278170159Sariffint
279170159Sariffsnd_clone_getdeadline(struct snd_clone *c)
280170159Sariff{
281170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
282170159Sariff
283170159Sariff	return (c->deadline);
284170159Sariff}
285170159Sariff
286170159Sariffint
287170159Sariffsnd_clone_setdeadline(struct snd_clone *c, int deadline)
288170159Sariff{
289170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
290170159Sariff
291170159Sariff	c->deadline = deadline;
292170159Sariff
293170159Sariff	return (c->deadline);
294170159Sariff}
295170159Sariff
296170159Sariffint
297170159Sariffsnd_clone_gettime(struct snd_clone *c, struct timespec *tsp)
298170159Sariff{
299170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
300170159Sariff	SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
301170159Sariff
302170159Sariff	*tsp = c->tsp;
303170159Sariff
304170159Sariff	return (0);
305170159Sariff}
306170159Sariff
307170159Sariffuint32_t
308170159Sariffsnd_clone_getflags(struct snd_clone *c)
309170159Sariff{
310170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
311170159Sariff
312170159Sariff	return (c->flags);
313170159Sariff}
314170159Sariff
315170159Sariffuint32_t
316170159Sariffsnd_clone_setflags(struct snd_clone *c, uint32_t flags)
317170159Sariff{
318170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
319170159Sariff	SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
320170159Sariff	    ("invalid clone flags=0x%08x", flags));
321170159Sariff
322170159Sariff	c->flags = flags;
323170159Sariff
324170159Sariff	return (c->flags);
325170159Sariff}
326170159Sariff
327170159Sariffint
328170159Sariffsnd_clone_getdevtime(struct cdev *dev, struct timespec *tsp)
329170159Sariff{
330170159Sariff	struct snd_clone_entry *ce;
331170159Sariff
332170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
333170159Sariff	SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
334170159Sariff
335170159Sariff	ce = dev->si_drv2;
336170159Sariff	if (ce == NULL)
337170159Sariff		return (ENODEV);
338170159Sariff
339170159Sariff	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
340170159Sariff
341170159Sariff	*tsp = ce->tsp;
342170159Sariff
343170159Sariff	return (0);
344170159Sariff}
345170159Sariff
346170159Sariffuint32_t
347170159Sariffsnd_clone_getdevflags(struct cdev *dev)
348170159Sariff{
349170159Sariff	struct snd_clone_entry *ce;
350170159Sariff
351170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
352170159Sariff
353170159Sariff	ce = dev->si_drv2;
354170159Sariff	if (ce == NULL)
355170159Sariff		return (0xffffffff);
356170159Sariff
357170159Sariff	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
358170159Sariff
359170159Sariff	return (ce->flags);
360170159Sariff}
361170159Sariff
362170159Sariffuint32_t
363170159Sariffsnd_clone_setdevflags(struct cdev *dev, uint32_t flags)
364170159Sariff{
365170159Sariff	struct snd_clone_entry *ce;
366170159Sariff
367170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
368170159Sariff	SND_CLONE_ASSERT(!(flags & ~SND_CLONE_DEVMASK),
369170159Sariff	    ("invalid clone dev flags=0x%08x", flags));
370170159Sariff
371170159Sariff	ce = dev->si_drv2;
372170159Sariff	if (ce == NULL)
373170159Sariff		return (0xffffffff);
374170159Sariff
375170159Sariff	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
376170159Sariff
377170159Sariff	ce->flags = flags;
378170159Sariff
379170159Sariff	return (ce->flags);
380170159Sariff}
381170159Sariff
382170159Sariff/* Elapsed time conversion to ms */
383170159Sariff#define SND_CLONE_ELAPSED(x, y)						\
384170159Sariff	((((x)->tv_sec - (y)->tv_sec) * 1000) +				\
385170159Sariff	(((y)->tv_nsec > (x)->tv_nsec) ?				\
386170159Sariff	(((1000000000L + (x)->tv_nsec -					\
387170159Sariff	(y)->tv_nsec) / 1000000) - 1000) :				\
388170159Sariff	(((x)->tv_nsec - (y)->tv_nsec) / 1000000)))
389170159Sariff
390170159Sariff#define SND_CLONE_EXPIRED(x, y, z)					\
391170159Sariff	((x)->deadline < 1 ||						\
392170159Sariff	((y)->tv_sec - (z)->tv_sec) > ((x)->deadline / 1000) ||		\
393170159Sariff	SND_CLONE_ELAPSED(y, z) > (x)->deadline)
394170159Sariff
395170159Sariff/*
396170159Sariff * snd_clone_gc() : Garbage collector for stalled, expired objects. Refer to
397170159Sariff * clone.h for explanations on GC settings.
398170159Sariff */
399170159Sariffint
400170159Sariffsnd_clone_gc(struct snd_clone *c)
401170159Sariff{
402170159Sariff	struct snd_clone_entry *ce, *tce;
403170159Sariff	struct timespec now;
404170159Sariff	int pruned;
405170159Sariff
406170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
407170159Sariff
408170159Sariff	if (!(c->flags & SND_CLONE_GC_ENABLE) || c->size == 0)
409170159Sariff		return (0);
410170159Sariff
411170159Sariff	snd_timestamp(&now);
412170159Sariff
413170159Sariff	/*
414170159Sariff	 * Bail out if the last clone handler was invoked below the deadline
415170159Sariff	 * threshold.
416170159Sariff	 */
417170159Sariff	if ((c->flags & SND_CLONE_GC_EXPIRED) &&
418170159Sariff	    !SND_CLONE_EXPIRED(c, &now, &c->tsp))
419170159Sariff		return (0);
420170159Sariff
421170159Sariff	pruned = 0;
422170159Sariff
423170159Sariff	/*
424170159Sariff	 * Visit each object in reverse order. If the object is still being
425170159Sariff	 * referenced by a valid open(), skip it. Look for expired objects
426170159Sariff	 * and either revoke its clone invocation status or mercilessly
427170159Sariff	 * throw it away.
428170159Sariff	 */
429170159Sariff	TAILQ_FOREACH_REVERSE_SAFE(ce, &c->head, link_head, link, tce) {
430170159Sariff		if (!(ce->flags & SND_CLONE_BUSY) &&
431170159Sariff		    (!(ce->flags & SND_CLONE_INVOKE) ||
432170159Sariff		    SND_CLONE_EXPIRED(c, &now, &ce->tsp))) {
433170159Sariff			if ((c->flags & SND_CLONE_GC_REVOKE) ||
434170159Sariff			    ce->devt->si_threadcount != 0) {
435170159Sariff				ce->flags &= ~SND_CLONE_INVOKE;
436170159Sariff				ce->pid = -1;
437170159Sariff			} else {
438170159Sariff				TAILQ_REMOVE(&c->head, ce, link);
439170159Sariff				destroy_dev(ce->devt);
440170159Sariff				free(ce, M_DEVBUF);
441170159Sariff				c->size--;
442170159Sariff			}
443170159Sariff			pruned++;
444170159Sariff		}
445170159Sariff	}
446170159Sariff
447170159Sariff	/* return total pruned objects */
448170159Sariff	return (pruned);
449170159Sariff}
450170159Sariff
451170159Sariffvoid
452170159Sariffsnd_clone_destroy(struct snd_clone *c)
453170159Sariff{
454170719Sariff	struct snd_clone_entry *ce, *tmp;
455170159Sariff
456170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
457170159Sariff
458170719Sariff	ce = TAILQ_FIRST(&c->head);
459170719Sariff	while (ce != NULL) {
460170719Sariff		tmp = TAILQ_NEXT(ce, link);
461170159Sariff		if (ce->devt != NULL)
462170159Sariff			destroy_dev(ce->devt);
463170159Sariff		free(ce, M_DEVBUF);
464170719Sariff		ce = tmp;
465170159Sariff	}
466170159Sariff
467170159Sariff	free(c, M_DEVBUF);
468170159Sariff}
469170159Sariff
470170159Sariff/*
471170159Sariff * snd_clone_acquire() : The vital part of concurrency management. Must be
472170159Sariff * called somewhere at the beginning of open() handler. ENODEV is not really
473170159Sariff * fatal since it just tell the caller that this is not cloned stuff.
474170159Sariff * EBUSY is *real*, don't forget that!
475170159Sariff */
476170159Sariffint
477170159Sariffsnd_clone_acquire(struct cdev *dev)
478170159Sariff{
479170159Sariff	struct snd_clone_entry *ce;
480170159Sariff
481170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
482170159Sariff
483170159Sariff	ce = dev->si_drv2;
484170159Sariff	if (ce == NULL)
485170159Sariff		return (ENODEV);
486170159Sariff
487170159Sariff	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
488170159Sariff
489170159Sariff	ce->flags &= ~SND_CLONE_INVOKE;
490170159Sariff
491170159Sariff	if (ce->flags & SND_CLONE_BUSY)
492170159Sariff		return (EBUSY);
493170159Sariff
494170159Sariff	ce->flags |= SND_CLONE_BUSY;
495170159Sariff
496170159Sariff	return (0);
497170159Sariff}
498170159Sariff
499170159Sariff/*
500170159Sariff * snd_clone_release() : Release busy status. Must be called somewhere at
501170159Sariff * the end of close() handler, or somewhere after fail open().
502170159Sariff */
503170159Sariffint
504170159Sariffsnd_clone_release(struct cdev *dev)
505170159Sariff{
506170159Sariff	struct snd_clone_entry *ce;
507170159Sariff
508170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
509170159Sariff
510170159Sariff	ce = dev->si_drv2;
511170159Sariff	if (ce == NULL)
512170159Sariff		return (ENODEV);
513170159Sariff
514170159Sariff	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
515170159Sariff
516170159Sariff	ce->flags &= ~SND_CLONE_INVOKE;
517170159Sariff
518170159Sariff	if (!(ce->flags & SND_CLONE_BUSY))
519170159Sariff		return (EBADF);
520170159Sariff
521170159Sariff	ce->flags &= ~SND_CLONE_BUSY;
522170159Sariff	ce->pid = -1;
523170159Sariff
524170159Sariff	return (0);
525170159Sariff}
526170159Sariff
527170159Sariff/*
528170159Sariff * snd_clone_ref/unref() : Garbage collector reference counter. To make
529170159Sariff * garbage collector run automatically, the sequence must be something like
530170159Sariff * this (both in open() and close() handlers):
531170159Sariff *
532170159Sariff *  open() - 1) snd_clone_acquire()
533170159Sariff *           2) .... check check ... if failed, snd_clone_release()
534170159Sariff *           3) Success. Call snd_clone_ref()
535170159Sariff *
536170159Sariff * close() - 1) .... check check check ....
537170159Sariff *           2) Success. snd_clone_release()
538170159Sariff *           3) snd_clone_unref() . Garbage collector will run at this point
539170159Sariff *              if this is the last referenced object.
540170159Sariff */
541170159Sariffint
542170159Sariffsnd_clone_ref(struct cdev *dev)
543170159Sariff{
544170159Sariff	struct snd_clone_entry *ce;
545170159Sariff	struct snd_clone *c;
546170159Sariff
547170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
548170159Sariff
549170159Sariff	ce = dev->si_drv2;
550170159Sariff	if (ce == NULL)
551170159Sariff		return (0);
552170159Sariff
553170159Sariff	c = ce->parent;
554170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
555170159Sariff	SND_CLONE_ASSERT(c->refcount >= 0, ("refcount < 0"));
556170159Sariff
557170159Sariff	return (++c->refcount);
558170159Sariff}
559170159Sariff
560170159Sariffint
561170159Sariffsnd_clone_unref(struct cdev *dev)
562170159Sariff{
563170159Sariff	struct snd_clone_entry *ce;
564170159Sariff	struct snd_clone *c;
565170159Sariff
566170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
567170159Sariff
568170159Sariff	ce = dev->si_drv2;
569170159Sariff	if (ce == NULL)
570170159Sariff		return (0);
571170159Sariff
572170159Sariff	c = ce->parent;
573170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
574170159Sariff	SND_CLONE_ASSERT(c->refcount > 0, ("refcount <= 0"));
575170159Sariff
576170159Sariff	c->refcount--;
577170159Sariff
578170159Sariff	/*
579170159Sariff	 * Run automatic garbage collector, if needed.
580170159Sariff	 */
581170159Sariff	if ((c->flags & SND_CLONE_GC_UNREF) &&
582170159Sariff	    (!(c->flags & SND_CLONE_GC_LASTREF) ||
583170159Sariff	    (c->refcount == 0 && (c->flags & SND_CLONE_GC_LASTREF))))
584170159Sariff		(void)snd_clone_gc(c);
585170159Sariff
586170159Sariff	return (c->refcount);
587170159Sariff}
588170159Sariff
589170159Sariffvoid
590170159Sariffsnd_clone_register(struct snd_clone_entry *ce, struct cdev *dev)
591170159Sariff{
592170159Sariff	SND_CLONE_ASSERT(ce != NULL, ("NULL snd_clone_entry"));
593170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
594170159Sariff	SND_CLONE_ASSERT(dev->si_drv2 == NULL, ("dev->si_drv2 not NULL"));
595170159Sariff	SND_CLONE_ASSERT((ce->flags & SND_CLONE_ALLOC) == SND_CLONE_ALLOC,
596170159Sariff	    ("invalid clone alloc flags=0x%08x", ce->flags));
597170159Sariff	SND_CLONE_ASSERT(ce->devt == NULL, ("ce->devt not NULL"));
598170159Sariff	SND_CLONE_ASSERT(ce->unit == dev2unit(dev),
599170159Sariff	    ("invalid unit ce->unit=0x%08x dev2unit=0x%08x",
600170159Sariff	    ce->unit, dev2unit(dev)));
601170159Sariff
602170159Sariff	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
603170159Sariff
604170159Sariff	dev->si_drv2 = ce;
605170159Sariff	ce->devt = dev;
606170159Sariff	ce->flags &= ~SND_CLONE_ALLOC;
607170159Sariff	ce->flags |= SND_CLONE_INVOKE;
608170159Sariff}
609170159Sariff
610170159Sariffstruct snd_clone_entry *
611170159Sariffsnd_clone_alloc(struct snd_clone *c, struct cdev **dev, int *unit, int tmask)
612170159Sariff{
613170159Sariff	struct snd_clone_entry *ce, *after, *bce, *cce, *nce, *tce;
614170159Sariff	struct timespec now;
615170159Sariff	int cunit, allocunit;
616170159Sariff	pid_t curpid;
617170159Sariff
618170159Sariff	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
619170159Sariff	SND_CLONE_ASSERT(dev != NULL, ("NULL dev pointer"));
620170159Sariff	SND_CLONE_ASSERT((c->typemask & tmask) == tmask,
621170159Sariff	    ("invalid tmask: typemask=0x%08x tmask=0x%08x",
622170159Sariff	    c->typemask, tmask));
623170159Sariff	SND_CLONE_ASSERT(unit != NULL, ("NULL unit pointer"));
624170159Sariff	SND_CLONE_ASSERT(*unit == -1 || !(*unit & (c->typemask | tmask)),
625170159Sariff	    ("typemask collision: typemask=0x%08x tmask=0x%08x *unit=%d",
626170159Sariff	    c->typemask, tmask, *unit));
627170159Sariff
628170159Sariff	if (!(c->flags & SND_CLONE_ENABLE) ||
629170159Sariff	    (*unit != -1 && *unit > c->maxunit))
630170159Sariff		return (NULL);
631170159Sariff
632170159Sariff	ce = NULL;
633170159Sariff	after = NULL;
634170159Sariff	bce = NULL;	/* "b"usy candidate */
635170159Sariff	cce = NULL;	/* "c"urthread/proc candidate */
636170159Sariff	nce = NULL;	/* "n"ull, totally unbusy candidate */
637170159Sariff	tce = NULL;	/* Last "t"ry candidate */
638170159Sariff	cunit = 0;
639170159Sariff	allocunit = (*unit == -1) ? 0 : *unit;
640170159Sariff	curpid = curthread->td_proc->p_pid;
641170159Sariff
642170159Sariff	snd_timestamp(&now);
643170159Sariff
644170159Sariff	TAILQ_FOREACH(ce, &c->head, link) {
645170159Sariff		/*
646170159Sariff		 * Sort incrementally according to device type.
647170159Sariff		 */
648170159Sariff		if (tmask > (ce->unit & c->typemask)) {
649170159Sariff			if (cunit == 0)
650170159Sariff				after = ce;
651170159Sariff			continue;
652170159Sariff		} else if (tmask < (ce->unit & c->typemask))
653170159Sariff			break;
654170159Sariff
655170159Sariff		/*
656170159Sariff		 * Shoot.. this is where the grumpiness begin. Just
657170159Sariff		 * return immediately.
658170159Sariff		 */
659170159Sariff		if (*unit != -1 && *unit == (ce->unit & ~tmask))
660170159Sariff			goto snd_clone_alloc_out;
661170159Sariff
662170159Sariff		cunit++;
663170159Sariff		/*
664170159Sariff		 * Simmilar device type. Sort incrementally according
665170159Sariff		 * to allocation unit. While here, look for free slot
666170159Sariff		 * and possible collision for new / future allocation.
667170159Sariff		 */
668170159Sariff		if (*unit == -1 && (ce->unit & ~tmask) == allocunit)
669170159Sariff			allocunit++;
670170159Sariff		if ((ce->unit & ~tmask) < allocunit)
671170159Sariff			after = ce;
672170159Sariff		/*
673170159Sariff		 * Clone logic:
674170159Sariff		 *   1. Look for non busy, but keep track of the best
675170159Sariff		 *      possible busy cdev.
676170159Sariff		 *   2. Look for the best (oldest referenced) entry that is
677170159Sariff		 *      in a same process / thread.
678170159Sariff		 *   3. Look for the best (oldest referenced), absolute free
679170159Sariff		 *      entry.
680170159Sariff		 *   4. Lastly, look for the best (oldest referenced)
681170159Sariff		 *      any entries that doesn't fit with anything above.
682170159Sariff		 */
683170159Sariff		if (ce->flags & SND_CLONE_BUSY) {
684170159Sariff			if (ce->devt != NULL && (bce == NULL ||
685170159Sariff			    timespeccmp(&ce->tsp, &bce->tsp, <)))
686170159Sariff				bce = ce;
687170159Sariff			continue;
688170159Sariff		}
689170159Sariff		if (ce->pid == curpid &&
690170159Sariff		    (cce == NULL || timespeccmp(&ce->tsp, &cce->tsp, <)))
691170159Sariff			cce = ce;
692170159Sariff		else if (!(ce->flags & SND_CLONE_INVOKE) &&
693170159Sariff		    (nce == NULL || timespeccmp(&ce->tsp, &nce->tsp, <)))
694170159Sariff			nce = ce;
695170159Sariff		else if (tce == NULL || timespeccmp(&ce->tsp, &tce->tsp, <))
696170159Sariff			tce = ce;
697170159Sariff	}
698170159Sariff	if (*unit != -1)
699170159Sariff		goto snd_clone_alloc_new;
700170159Sariff	else if (cce != NULL) {
701170159Sariff		/* Same proc entry found, go for it */
702170159Sariff		ce = cce;
703170159Sariff		goto snd_clone_alloc_out;
704170159Sariff	} else if (nce != NULL) {
705170159Sariff		/*
706170159Sariff		 * Next, try absolute free entry. If the calculated
707170159Sariff		 * allocunit is smaller, create new entry instead.
708170159Sariff		 */
709170159Sariff		if (allocunit < (nce->unit & ~tmask))
710170159Sariff			goto snd_clone_alloc_new;
711170159Sariff		ce = nce;
712170159Sariff		goto snd_clone_alloc_out;
713170159Sariff	} else if (allocunit > c->maxunit) {
714170159Sariff		/*
715170159Sariff		 * Maximum allowable unit reached. Try returning any
716170159Sariff		 * available cdev and hope for the best. If the lookup is
717170159Sariff		 * done for things like stat(), mtime() etc. , things should
718170159Sariff		 * be ok. Otherwise, open() handler should do further checks
719170159Sariff		 * and decide whether to return correct error code or not.
720170159Sariff		 */
721170159Sariff		if (tce != NULL) {
722170159Sariff			ce = tce;
723170159Sariff			goto snd_clone_alloc_out;
724170159Sariff		} else if (bce != NULL) {
725170159Sariff			ce = bce;
726170159Sariff			goto snd_clone_alloc_out;
727170159Sariff		}
728170159Sariff		return (NULL);
729170159Sariff	}
730170159Sariff
731170159Sariffsnd_clone_alloc_new:
732170159Sariff	/*
733170159Sariff	 * No free entries found, and we still haven't reached maximum
734170159Sariff	 * allowable units. Allocate, setup a minimal unique entry with busy
735170719Sariff	 * status so nobody will monkey on this new entry. Unit magic is set
736170719Sariff	 * right here to avoid collision with other contesting handler.
737170719Sariff	 * The caller must be carefull here to maintain its own
738170719Sariff	 * synchronization, as long as it will not conflict with malloc(9)
739170719Sariff	 * operations.
740170719Sariff	 *
741170719Sariff	 * That said, go figure.
742170159Sariff	 */
743170719Sariff	ce = malloc(sizeof(*ce), M_DEVBUF,
744170719Sariff	    ((c->flags & SND_CLONE_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO);
745170159Sariff	if (ce == NULL) {
746170159Sariff		if (*unit != -1)
747170159Sariff			return (NULL);
748170159Sariff		/*
749170159Sariff		 * We're being dense, ignorance is bliss,
750170159Sariff		 * Super Regulatory Measure (TM).. TRY AGAIN!
751170159Sariff		 */
752170159Sariff		if (nce != NULL) {
753170159Sariff			ce = nce;
754170159Sariff			goto snd_clone_alloc_out;
755170159Sariff		} else if (tce != NULL) {
756170159Sariff			ce = tce;
757170159Sariff			goto snd_clone_alloc_out;
758170159Sariff		} else if (bce != NULL) {
759170159Sariff			ce = bce;
760170159Sariff			goto snd_clone_alloc_out;
761170159Sariff		}
762170159Sariff		return (NULL);
763170159Sariff	}
764170159Sariff	/* Setup new entry */
765170159Sariff	ce->parent = c;
766170159Sariff	ce->unit = tmask | allocunit;
767170159Sariff	ce->pid = curpid;
768170159Sariff	ce->tsp = now;
769170159Sariff	ce->flags |= SND_CLONE_ALLOC;
770170159Sariff	if (after != NULL) {
771170159Sariff		TAILQ_INSERT_AFTER(&c->head, after, ce, link);
772170159Sariff	} else {
773170159Sariff		TAILQ_INSERT_HEAD(&c->head, ce, link);
774170159Sariff	}
775170159Sariff	c->size++;
776170159Sariff	c->tsp = now;
777170159Sariff	/*
778170159Sariff	 * Save new allocation unit for caller which will be used
779170159Sariff	 * by make_dev().
780170159Sariff	 */
781170159Sariff	*unit = allocunit;
782170159Sariff
783170159Sariff	return (ce);
784170159Sariff
785170159Sariffsnd_clone_alloc_out:
786170159Sariff	/*
787170159Sariff	 * Set, mark, timestamp the entry if this is a truly free entry.
788170159Sariff	 * Leave busy entry alone.
789170159Sariff	 */
790170159Sariff	if (!(ce->flags & SND_CLONE_BUSY)) {
791170159Sariff		ce->pid = curpid;
792170159Sariff		ce->tsp = now;
793170159Sariff		ce->flags |= SND_CLONE_INVOKE;
794170159Sariff	}
795170159Sariff	c->tsp = now;
796170159Sariff	*dev = ce->devt;
797170159Sariff
798170159Sariff	return (NULL);
799170159Sariff}
800