DEVFS - remove dev_ops_add(), dev_ops_get(), and get_dev()
[dragonfly.git] / sys / dev / sound / pcm / sndstat.c
CommitLineData
558a398b
SS
1/*-
2 * Copyright (c) 2001 Cameron Grant <cg@freebsd.org>
984263bc
MD
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
1de703da 25 *
558a398b 26 * $FreeBSD: src/sys/dev/sound/pcm/sndstat.c,v 1.20.2.2 2005/12/30 19:55:54 netchild Exp $
978400d3 27 * $DragonFly: src/sys/dev/sound/pcm/sndstat.c,v 1.13 2008/01/06 16:55:51 swildner Exp $
984263bc
MD
28 */
29
30#include <dev/sound/pcm/sound.h>
31#include <dev/sound/pcm/vchan.h>
558a398b
SS
32#ifdef USING_MUTEX
33#include <sys/lock.h>
34#endif
984263bc 35
978400d3 36SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/sndstat.c,v 1.13 2008/01/06 16:55:51 swildner Exp $");
984263bc
MD
37
38#define SS_TYPE_MODULE 0
39#define SS_TYPE_FIRST 1
40#define SS_TYPE_PCM 1
41#define SS_TYPE_MIDI 2
42#define SS_TYPE_SEQUENCER 3
43#define SS_TYPE_LAST 3
44
45static d_open_t sndstat_open;
46static d_close_t sndstat_close;
47static d_read_t sndstat_read;
48
558a398b 49static struct dev_ops sndstat_cdevsw = {
fef8985e 50 { "sndstat", SND_CDEV_MAJOR, 0 },
558a398b 51 /* .d_flags = D_NEEDGIANT, */
fef8985e
MD
52 .d_open = sndstat_open,
53 .d_close = sndstat_close,
54 .d_read = sndstat_read,
984263bc
MD
55};
56
57struct sndstat_entry {
58 SLIST_ENTRY(sndstat_entry) link;
59 device_t dev;
60 char *str;
61 sndstat_handler handler;
62 int type, unit;
63};
64
558a398b
SS
65#ifdef USING_MUTEX
66static struct lock sndstat_lock;
67#endif
984263bc 68static struct sbuf sndstat_sbuf;
984263bc
MD
69static int sndstat_isopen = 0;
70static int sndstat_bufptr;
71static int sndstat_maxunit = -1;
72static int sndstat_files = 0;
73
74static SLIST_HEAD(, sndstat_entry) sndstat_devlist = SLIST_HEAD_INITIALIZER(none);
75
76static int sndstat_verbose = 1;
77#ifdef USING_MUTEX
78TUNABLE_INT("hw.snd.verbose", &sndstat_verbose);
79#else
80TUNABLE_INT_DECL("hw.snd.verbose", 1, sndstat_verbose);
81#endif
82
83static int sndstat_prepare(struct sbuf *s);
84
85static int
86sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
87{
984263bc
MD
88 int error, verbose;
89
90 verbose = sndstat_verbose;
91 error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req);
92 if (error == 0 && req->newptr != NULL) {
558a398b 93 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
984263bc
MD
94 if (verbose < 0 || verbose > 3)
95 error = EINVAL;
96 else
97 sndstat_verbose = verbose;
558a398b 98 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
99 }
100 return error;
101}
102SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT | CTLFLAG_RW,
103 0, sizeof(int), sysctl_hw_sndverbose, "I", "");
104
105static int
fef8985e 106sndstat_open(struct dev_open_args *ap)
984263bc 107{
558a398b 108 int error;
984263bc 109
558a398b 110 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
984263bc 111 if (sndstat_isopen) {
558a398b 112 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
113 return EBUSY;
114 }
558a398b
SS
115 sndstat_isopen = 1;
116 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc 117 if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) {
558a398b
SS
118 error = ENXIO;
119 goto out;
984263bc
MD
120 }
121 sndstat_bufptr = 0;
558a398b
SS
122 error = (sndstat_prepare(&sndstat_sbuf) > 0) ? 0 : ENOMEM;
123out:
124 if (error) {
125 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
126 sndstat_isopen = 0;
127 lockmgr(&sndstat_lock, LK_RELEASE);
128 }
129 return (error);
984263bc
MD
130}
131
132static int
fef8985e 133sndstat_close(struct dev_close_args *ap)
984263bc 134{
558a398b 135 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
984263bc 136 if (!sndstat_isopen) {
558a398b 137 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
138 return EBADF;
139 }
140 sbuf_delete(&sndstat_sbuf);
141 sndstat_isopen = 0;
142
558a398b 143 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
144 return 0;
145}
146
147static int
fef8985e 148sndstat_read(struct dev_read_args *ap)
984263bc 149{
558a398b 150 struct uio *buf = ap->a_uio;
984263bc
MD
151 int l, err;
152
558a398b 153 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
984263bc 154 if (!sndstat_isopen) {
558a398b 155 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
156 return EBADF;
157 }
558a398b
SS
158 l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
159 err = (l > 0)? uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, l, buf) : 0;
984263bc
MD
160 sndstat_bufptr += l;
161
558a398b 162 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
163 return err;
164}
165
166/************************************************************************/
167
168static struct sndstat_entry *
169sndstat_find(int type, int unit)
170{
171 struct sndstat_entry *ent;
172
173 SLIST_FOREACH(ent, &sndstat_devlist, link) {
174 if (ent->type == type && ent->unit == unit)
175 return ent;
176 }
177
178 return NULL;
179}
180
181int
558a398b
SS
182sndstat_acquire(void)
183{
184 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
185 if (sndstat_isopen) {
186 lockmgr(&sndstat_lock, LK_RELEASE);
187 return EBUSY;
188 }
189 sndstat_isopen = 1;
190 lockmgr(&sndstat_lock, LK_RELEASE);
191 return 0;
192}
193
194int
195sndstat_release(void)
196{
197 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
198 if (!sndstat_isopen) {
199 lockmgr(&sndstat_lock, LK_RELEASE);
200 return EBADF;
201 }
202 sndstat_isopen = 0;
203 lockmgr(&sndstat_lock, LK_RELEASE);
204 return 0;
205}
206
207int
984263bc
MD
208sndstat_register(device_t dev, char *str, sndstat_handler handler)
209{
984263bc
MD
210 struct sndstat_entry *ent;
211 const char *devtype;
212 int type, unit;
213
214 if (dev) {
215 unit = device_get_unit(dev);
216 devtype = device_get_name(dev);
217 if (!strcmp(devtype, "pcm"))
218 type = SS_TYPE_PCM;
219 else if (!strcmp(devtype, "midi"))
220 type = SS_TYPE_MIDI;
221 else if (!strcmp(devtype, "sequencer"))
222 type = SS_TYPE_SEQUENCER;
223 else
224 return EINVAL;
225 } else {
226 type = SS_TYPE_MODULE;
227 unit = -1;
228 }
229
efda3bd0 230 ent = kmalloc(sizeof *ent, M_DEVBUF, M_ZERO | M_WAITOK);
984263bc
MD
231
232 ent->dev = dev;
233 ent->str = str;
234 ent->type = type;
235 ent->unit = unit;
236 ent->handler = handler;
237
558a398b 238 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
984263bc
MD
239 SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
240 if (type == SS_TYPE_MODULE)
241 sndstat_files++;
242 sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
558a398b 243 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
244
245 return 0;
246}
247
248int
249sndstat_registerfile(char *str)
250{
251 return sndstat_register(NULL, str, NULL);
252}
253
254int
255sndstat_unregister(device_t dev)
256{
984263bc
MD
257 struct sndstat_entry *ent;
258
558a398b 259 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
984263bc
MD
260 SLIST_FOREACH(ent, &sndstat_devlist, link) {
261 if (ent->dev == dev) {
262 SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
558a398b 263 lockmgr(&sndstat_lock, LK_RELEASE);
efda3bd0 264 kfree(ent, M_DEVBUF);
984263bc
MD
265
266 return 0;
267 }
268 }
558a398b 269 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
270
271 return ENXIO;
272}
273
274int
275sndstat_unregisterfile(char *str)
276{
984263bc
MD
277 struct sndstat_entry *ent;
278
558a398b 279 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
984263bc
MD
280 SLIST_FOREACH(ent, &sndstat_devlist, link) {
281 if (ent->dev == NULL && ent->str == str) {
282 SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
984263bc 283 sndstat_files--;
558a398b
SS
284 lockmgr(&sndstat_lock, LK_RELEASE);
285 kfree(ent, M_DEVBUF);
984263bc
MD
286
287 return 0;
288 }
289 }
558a398b 290 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
291
292 return ENXIO;
293}
294
295/************************************************************************/
296
297static int
298sndstat_prepare(struct sbuf *s)
299{
300 struct sndstat_entry *ent;
301 int i, j;
302
303 sbuf_printf(s, "FreeBSD Audio Driver (newpcm)\n");
304 if (SLIST_EMPTY(&sndstat_devlist)) {
305 sbuf_printf(s, "No devices installed.\n");
306 sbuf_finish(s);
307 return sbuf_len(s);
308 }
309
310 sbuf_printf(s, "Installed devices:\n");
311
312 for (i = 0; i <= sndstat_maxunit; i++) {
313 for (j = SS_TYPE_FIRST; j <= SS_TYPE_LAST; j++) {
314 ent = sndstat_find(j, i);
315 if (!ent)
316 continue;
317 sbuf_printf(s, "%s:", device_get_nameunit(ent->dev));
318 sbuf_printf(s, " <%s>", device_get_desc(ent->dev));
319 sbuf_printf(s, " %s", ent->str);
320 if (ent->handler)
321 ent->handler(s, ent->dev, sndstat_verbose);
322 else
323 sbuf_printf(s, " [no handler]");
324 sbuf_printf(s, "\n");
325 }
326 }
327
328 if (sndstat_verbose >= 3 && sndstat_files > 0) {
329 sbuf_printf(s, "\nFile Versions:\n");
330
331 SLIST_FOREACH(ent, &sndstat_devlist, link) {
332 if (ent->dev == NULL && ent->str != NULL)
333 sbuf_printf(s, "%s\n", ent->str);
334 }
335 }
336
337 sbuf_finish(s);
338 return sbuf_len(s);
339}
340
341static int
342sndstat_init(void)
343{
558a398b
SS
344 lockinit(&sndstat_lock, "sndstat", 0, 0);
345 if (make_dev(&sndstat_cdevsw, SND_DEV_STATUS,
3e82b46c 346 UID_ROOT, GID_WHEEL, 0444, "sndstat") == NULL) {
558a398b 347 return ENXIO;
3e82b46c 348 }
558a398b 349 return 0;
984263bc
MD
350}
351
352static int
353sndstat_uninit(void)
354{
558a398b 355 lockmgr(&sndstat_lock, LK_EXCLUSIVE);
984263bc 356 if (sndstat_isopen) {
558a398b 357 lockmgr(&sndstat_lock, LK_RELEASE);
984263bc
MD
358 return EBUSY;
359 }
984263bc 360
cd29885a
MD
361 //dev_ops_remove(&sndstat_cdevsw, -1, SND_DEV_STATUS);
362 dev_ops_remove_all(&sndstat_cdevsw);
558a398b
SS
363 lockmgr(&sndstat_lock, LK_RELEASE);
364 return 0;
984263bc
MD
365}
366
367static void
368sndstat_sysinit(void *p)
369{
370 sndstat_init();
371}
372
373static void
374sndstat_sysuninit(void *p)
375{
558a398b
SS
376 int error;
377
378 error = sndstat_uninit();
379 KASSERT(error == 0, ("%s: error = %d", __func__, error));
984263bc
MD
380}
381
382SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL);
383SYSUNINIT(sndstat_sysuninit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysuninit, NULL);
384
385