| Commit | Line | Data |
|---|---|---|
| 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 | 36 | SND_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 | ||
| 45 | static d_open_t sndstat_open; | |
| 46 | static d_close_t sndstat_close; | |
| 47 | static d_read_t sndstat_read; | |
| 48 | ||
| 558a398b | 49 | static 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 | ||
| 57 | struct 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 |
| 66 | static struct lock sndstat_lock; | |
| 67 | #endif | |
| 984263bc | 68 | static struct sbuf sndstat_sbuf; |
| 984263bc MD |
69 | static int sndstat_isopen = 0; |
| 70 | static int sndstat_bufptr; | |
| 71 | static int sndstat_maxunit = -1; | |
| 72 | static int sndstat_files = 0; | |
| 73 | ||
| 74 | static SLIST_HEAD(, sndstat_entry) sndstat_devlist = SLIST_HEAD_INITIALIZER(none); | |
| 75 | ||
| 76 | static int sndstat_verbose = 1; | |
| 77 | #ifdef USING_MUTEX | |
| 78 | TUNABLE_INT("hw.snd.verbose", &sndstat_verbose); | |
| 79 | #else | |
| 80 | TUNABLE_INT_DECL("hw.snd.verbose", 1, sndstat_verbose); | |
| 81 | #endif | |
| 82 | ||
| 83 | static int sndstat_prepare(struct sbuf *s); | |
| 84 | ||
| 85 | static int | |
| 86 | sysctl_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 | } | |
| 102 | SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT | CTLFLAG_RW, | |
| 103 | 0, sizeof(int), sysctl_hw_sndverbose, "I", ""); | |
| 104 | ||
| 105 | static int | |
| fef8985e | 106 | sndstat_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; |
| 123 | out: | |
| 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 | ||
| 132 | static int | |
| fef8985e | 133 | sndstat_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 | ||
| 147 | static int | |
| fef8985e | 148 | sndstat_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 | } | |
| e54488bb MD |
158 | l = (int)szmin(buf->uio_resid, |
| 159 | sbuf_len(&sndstat_sbuf) - sndstat_bufptr); | |
| 160 | if (l > 0) { | |
| 161 | err = uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, | |
| 162 | l, buf); | |
| 163 | } else { | |
| 164 | err = 0; | |
| 165 | } | |
| 984263bc MD |
166 | sndstat_bufptr += l; |
| 167 | ||
| 558a398b | 168 | lockmgr(&sndstat_lock, LK_RELEASE); |
| 984263bc MD |
169 | return err; |
| 170 | } | |
| 171 | ||
| 172 | /************************************************************************/ | |
| 173 | ||
| 174 | static struct sndstat_entry * | |
| 175 | sndstat_find(int type, int unit) | |
| 176 | { | |
| 177 | struct sndstat_entry *ent; | |
| 178 | ||
| 179 | SLIST_FOREACH(ent, &sndstat_devlist, link) { | |
| 180 | if (ent->type == type && ent->unit == unit) | |
| 181 | return ent; | |
| 182 | } | |
| 183 | ||
| 184 | return NULL; | |
| 185 | } | |
| 186 | ||
| 187 | int | |
| 558a398b SS |
188 | sndstat_acquire(void) |
| 189 | { | |
| 190 | lockmgr(&sndstat_lock, LK_EXCLUSIVE); | |
| 191 | if (sndstat_isopen) { | |
| 192 | lockmgr(&sndstat_lock, LK_RELEASE); | |
| 193 | return EBUSY; | |
| 194 | } | |
| 195 | sndstat_isopen = 1; | |
| 196 | lockmgr(&sndstat_lock, LK_RELEASE); | |
| 197 | return 0; | |
| 198 | } | |
| 199 | ||
| 200 | int | |
| 201 | sndstat_release(void) | |
| 202 | { | |
| 203 | lockmgr(&sndstat_lock, LK_EXCLUSIVE); | |
| 204 | if (!sndstat_isopen) { | |
| 205 | lockmgr(&sndstat_lock, LK_RELEASE); | |
| 206 | return EBADF; | |
| 207 | } | |
| 208 | sndstat_isopen = 0; | |
| 209 | lockmgr(&sndstat_lock, LK_RELEASE); | |
| 210 | return 0; | |
| 211 | } | |
| 212 | ||
| 213 | int | |
| 984263bc MD |
214 | sndstat_register(device_t dev, char *str, sndstat_handler handler) |
| 215 | { | |
| 984263bc MD |
216 | struct sndstat_entry *ent; |
| 217 | const char *devtype; | |
| 218 | int type, unit; | |
| 219 | ||
| 220 | if (dev) { | |
| 221 | unit = device_get_unit(dev); | |
| 222 | devtype = device_get_name(dev); | |
| 223 | if (!strcmp(devtype, "pcm")) | |
| 224 | type = SS_TYPE_PCM; | |
| 225 | else if (!strcmp(devtype, "midi")) | |
| 226 | type = SS_TYPE_MIDI; | |
| 227 | else if (!strcmp(devtype, "sequencer")) | |
| 228 | type = SS_TYPE_SEQUENCER; | |
| 229 | else | |
| 230 | return EINVAL; | |
| 231 | } else { | |
| 232 | type = SS_TYPE_MODULE; | |
| 233 | unit = -1; | |
| 234 | } | |
| 235 | ||
| efda3bd0 | 236 | ent = kmalloc(sizeof *ent, M_DEVBUF, M_ZERO | M_WAITOK); |
| 984263bc MD |
237 | |
| 238 | ent->dev = dev; | |
| 239 | ent->str = str; | |
| 240 | ent->type = type; | |
| 241 | ent->unit = unit; | |
| 242 | ent->handler = handler; | |
| 243 | ||
| 558a398b | 244 | lockmgr(&sndstat_lock, LK_EXCLUSIVE); |
| 984263bc MD |
245 | SLIST_INSERT_HEAD(&sndstat_devlist, ent, link); |
| 246 | if (type == SS_TYPE_MODULE) | |
| 247 | sndstat_files++; | |
| 248 | sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit; | |
| 558a398b | 249 | lockmgr(&sndstat_lock, LK_RELEASE); |
| 984263bc MD |
250 | |
| 251 | return 0; | |
| 252 | } | |
| 253 | ||
| 254 | int | |
| 255 | sndstat_registerfile(char *str) | |
| 256 | { | |
| 257 | return sndstat_register(NULL, str, NULL); | |
| 258 | } | |
| 259 | ||
| 260 | int | |
| 261 | sndstat_unregister(device_t dev) | |
| 262 | { | |
| 984263bc MD |
263 | struct sndstat_entry *ent; |
| 264 | ||
| 558a398b | 265 | lockmgr(&sndstat_lock, LK_EXCLUSIVE); |
| 984263bc MD |
266 | SLIST_FOREACH(ent, &sndstat_devlist, link) { |
| 267 | if (ent->dev == dev) { | |
| 268 | SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link); | |
| 558a398b | 269 | lockmgr(&sndstat_lock, LK_RELEASE); |
| efda3bd0 | 270 | kfree(ent, M_DEVBUF); |
| 984263bc MD |
271 | |
| 272 | return 0; | |
| 273 | } | |
| 274 | } | |
| 558a398b | 275 | lockmgr(&sndstat_lock, LK_RELEASE); |
| 984263bc MD |
276 | |
| 277 | return ENXIO; | |
| 278 | } | |
| 279 | ||
| 280 | int | |
| 281 | sndstat_unregisterfile(char *str) | |
| 282 | { | |
| 984263bc MD |
283 | struct sndstat_entry *ent; |
| 284 | ||
| 558a398b | 285 | lockmgr(&sndstat_lock, LK_EXCLUSIVE); |
| 984263bc MD |
286 | SLIST_FOREACH(ent, &sndstat_devlist, link) { |
| 287 | if (ent->dev == NULL && ent->str == str) { | |
| 288 | SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link); | |
| 984263bc | 289 | sndstat_files--; |
| 558a398b SS |
290 | lockmgr(&sndstat_lock, LK_RELEASE); |
| 291 | kfree(ent, M_DEVBUF); | |
| 984263bc MD |
292 | |
| 293 | return 0; | |
| 294 | } | |
| 295 | } | |
| 558a398b | 296 | lockmgr(&sndstat_lock, LK_RELEASE); |
| 984263bc MD |
297 | |
| 298 | return ENXIO; | |
| 299 | } | |
| 300 | ||
| 301 | /************************************************************************/ | |
| 302 | ||
| 303 | static int | |
| 304 | sndstat_prepare(struct sbuf *s) | |
| 305 | { | |
| 306 | struct sndstat_entry *ent; | |
| 307 | int i, j; | |
| 308 | ||
| 309 | sbuf_printf(s, "FreeBSD Audio Driver (newpcm)\n"); | |
| 310 | if (SLIST_EMPTY(&sndstat_devlist)) { | |
| 311 | sbuf_printf(s, "No devices installed.\n"); | |
| 312 | sbuf_finish(s); | |
| 313 | return sbuf_len(s); | |
| 314 | } | |
| 315 | ||
| 316 | sbuf_printf(s, "Installed devices:\n"); | |
| 317 | ||
| 318 | for (i = 0; i <= sndstat_maxunit; i++) { | |
| 319 | for (j = SS_TYPE_FIRST; j <= SS_TYPE_LAST; j++) { | |
| 320 | ent = sndstat_find(j, i); | |
| 321 | if (!ent) | |
| 322 | continue; | |
| 323 | sbuf_printf(s, "%s:", device_get_nameunit(ent->dev)); | |
| 324 | sbuf_printf(s, " <%s>", device_get_desc(ent->dev)); | |
| 325 | sbuf_printf(s, " %s", ent->str); | |
| 326 | if (ent->handler) | |
| 327 | ent->handler(s, ent->dev, sndstat_verbose); | |
| 328 | else | |
| 329 | sbuf_printf(s, " [no handler]"); | |
| 330 | sbuf_printf(s, "\n"); | |
| 331 | } | |
| 332 | } | |
| 333 | ||
| 334 | if (sndstat_verbose >= 3 && sndstat_files > 0) { | |
| 335 | sbuf_printf(s, "\nFile Versions:\n"); | |
| 336 | ||
| 337 | SLIST_FOREACH(ent, &sndstat_devlist, link) { | |
| 338 | if (ent->dev == NULL && ent->str != NULL) | |
| 339 | sbuf_printf(s, "%s\n", ent->str); | |
| 340 | } | |
| 341 | } | |
| 342 | ||
| 343 | sbuf_finish(s); | |
| 344 | return sbuf_len(s); | |
| 345 | } | |
| 346 | ||
| 347 | static int | |
| 348 | sndstat_init(void) | |
| 349 | { | |
| 558a398b SS |
350 | lockinit(&sndstat_lock, "sndstat", 0, 0); |
| 351 | if (make_dev(&sndstat_cdevsw, SND_DEV_STATUS, | |
| 3e82b46c | 352 | UID_ROOT, GID_WHEEL, 0444, "sndstat") == NULL) { |
| 558a398b | 353 | return ENXIO; |
| 3e82b46c | 354 | } |
| 558a398b | 355 | return 0; |
| 984263bc MD |
356 | } |
| 357 | ||
| 358 | static int | |
| 359 | sndstat_uninit(void) | |
| 360 | { | |
| 558a398b | 361 | lockmgr(&sndstat_lock, LK_EXCLUSIVE); |
| 984263bc | 362 | if (sndstat_isopen) { |
| 558a398b | 363 | lockmgr(&sndstat_lock, LK_RELEASE); |
| 984263bc MD |
364 | return EBUSY; |
| 365 | } | |
| 984263bc | 366 | |
| cd29885a MD |
367 | //dev_ops_remove(&sndstat_cdevsw, -1, SND_DEV_STATUS); |
| 368 | dev_ops_remove_all(&sndstat_cdevsw); | |
| 558a398b SS |
369 | lockmgr(&sndstat_lock, LK_RELEASE); |
| 370 | return 0; | |
| 984263bc MD |
371 | } |
| 372 | ||
| 373 | static void | |
| 374 | sndstat_sysinit(void *p) | |
| 375 | { | |
| 376 | sndstat_init(); | |
| 377 | } | |
| 378 | ||
| 379 | static void | |
| 380 | sndstat_sysuninit(void *p) | |
| 381 | { | |
| 558a398b SS |
382 | int error; |
| 383 | ||
| 384 | error = sndstat_uninit(); | |
| 385 | KASSERT(error == 0, ("%s: error = %d", __func__, error)); | |
| 984263bc MD |
386 | } |
| 387 | ||
| 388 | SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL); | |
| 389 | SYSUNINIT(sndstat_sysuninit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysuninit, NULL); | |
| 390 | ||
| 391 |