1 /*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 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. 25 * 26 * $FreeBSD$ 27 */ 28 29 struct pcmchan_caps { 30 u_int32_t minspeed, maxspeed; 31 u_int32_t *fmtlist; 32 u_int32_t caps; 33 }; 34 35 /* Forward declarations */ 36 struct pcm_channel; 37 struct pcmchan_syncgroup; 38 struct pcmchan_syncmember; 39 40 extern struct mtx snd_pcm_syncgroups_mtx; 41 extern SLIST_HEAD(pcm_synclist, pcmchan_syncgroup) snd_pcm_syncgroups; 42 43 #define PCM_SG_LOCK() mtx_lock(&snd_pcm_syncgroups_mtx) 44 #define PCM_SG_TRYLOCK() mtx_trylock(&snd_pcm_syncgroups_mtx) 45 #define PCM_SG_UNLOCK() mtx_unlock(&snd_pcm_syncgroups_mtx) 46 #define PCM_SG_LOCKASSERT(arg) mtx_assert(&snd_pcm_syncgroups_mtx, arg) 47 48 /** 49 * @brief Specifies an audio device sync group 50 */ 51 struct pcmchan_syncgroup { 52 SLIST_ENTRY(pcmchan_syncgroup) link; 53 SLIST_HEAD(, pcmchan_syncmember) members; 54 int id; /**< Group identifier; set to address of group. */ 55 }; 56 57 /** 58 * @brief Specifies a container for members of a sync group 59 */ 60 struct pcmchan_syncmember { 61 SLIST_ENTRY(pcmchan_syncmember) link; 62 struct pcmchan_syncgroup *parent; /**< group head */ 63 struct pcm_channel *ch; 64 }; 65 66 #define CHN_NAMELEN 32 67 struct pcm_channel { 68 kobj_t methods; 69 70 pid_t pid; 71 int refcount; 72 struct pcm_feeder *feeder; 73 u_int32_t align; 74 75 int volume; 76 int latency; 77 u_int32_t speed; 78 u_int32_t format; 79 u_int32_t flags; 80 u_int32_t feederflags; 81 u_int32_t blocks; 82 83 int direction; 84 unsigned int interrupts, xruns, feedcount; 85 unsigned int timeout; 86 struct snd_dbuf *bufhard, *bufsoft; 87 struct snddev_info *parentsnddev; 88 struct pcm_channel *parentchannel; 89 void *devinfo; 90 device_t dev; 91 int unit; 92 char name[CHN_NAMELEN]; 93 struct mtx *lock; 94 int trigger; 95 /** 96 * For interrupt manipulations. 97 */ 98 struct cv intr_cv; 99 /** 100 * Increment,decrement this around operations that temporarily yield 101 * lock. 102 */ 103 unsigned int inprog; 104 /** 105 * Special channel operations should examine @c inprog after acquiring 106 * lock. If zero, operations may continue. Else, thread should 107 * wait on this cv for previous operation to finish. 108 */ 109 struct cv cv; 110 /** 111 * Low water mark for select()/poll(). 112 * 113 * This is initialized to the channel's fragment size, and will be 114 * overwritten if a new fragment size is set. Users may alter this 115 * value directly with the @c SNDCTL_DSP_LOW_WATER ioctl. 116 */ 117 unsigned int lw; 118 /** 119 * If part of a sync group, this will point to the syncmember 120 * container. 121 */ 122 struct pcmchan_syncmember *sm; 123 #ifdef OSSV4_EXPERIMENT 124 u_int16_t lpeak, rpeak; /**< Peak value from 0-32767. */ 125 #endif 126 127 struct { 128 SLIST_HEAD(, pcm_channel) head; 129 SLIST_ENTRY(pcm_channel) link; 130 struct { 131 SLIST_HEAD(, pcm_channel) head; 132 SLIST_ENTRY(pcm_channel) link; 133 } busy; 134 } children; 135 136 struct { 137 struct { 138 SLIST_ENTRY(pcm_channel) link; 139 struct { 140 SLIST_ENTRY(pcm_channel) link; 141 } busy; 142 } pcm; 143 } channels; 144 145 void *data1, *data2; 146 }; 147 148 #define CHN_HEAD(x, y) &(x)->y.head 149 #define CHN_INIT(x, y) SLIST_INIT(CHN_HEAD(x, y)) 150 #define CHN_LINK(y) y.link 151 #define CHN_EMPTY(x, y) SLIST_EMPTY(CHN_HEAD(x, y)) 152 #define CHN_FIRST(x, y) SLIST_FIRST(CHN_HEAD(x, y)) 153 154 #define CHN_FOREACH(x, y, z) \ 155 SLIST_FOREACH(x, CHN_HEAD(y, z), CHN_LINK(z)) 156 157 #define CHN_FOREACH_SAFE(w, x, y, z) \ 158 SLIST_FOREACH_SAFE(w, CHN_HEAD(x, z), CHN_LINK(z), y) 159 160 #define CHN_INSERT_HEAD(x, y, z) \ 161 SLIST_INSERT_HEAD(CHN_HEAD(x, z), y, CHN_LINK(z)) 162 163 #define CHN_INSERT_AFTER(x, y, z) \ 164 SLIST_INSERT_AFTER(x, y, CHN_LINK(z)) 165 166 #define CHN_REMOVE(x, y, z) \ 167 SLIST_REMOVE(CHN_HEAD(x, z), y, pcm_channel, CHN_LINK(z)) 168 169 #define CHN_INSERT_HEAD_SAFE(x, y, z) do { \ 170 struct pcm_channel *t = NULL; \ 171 CHN_FOREACH(t, x, z) { \ 172 if (t == y) \ 173 break; \ 174 } \ 175 if (t != y) { \ 176 CHN_INSERT_HEAD(x, y, z); \ 177 } \ 178 } while(0) 179 180 #define CHN_INSERT_AFTER_SAFE(w, x, y, z) do { \ 181 struct pcm_channel *t = NULL; \ 182 CHN_FOREACH(t, w, z) { \ 183 if (t == y) \ 184 break; \ 185 } \ 186 if (t != y) { \ 187 CHN_INSERT_AFTER(x, y, z); \ 188 } \ 189 } while(0) 190 191 #define CHN_REMOVE_SAFE(x, y, z) do { \ 192 struct pcm_channel *t = NULL; \ 193 CHN_FOREACH(t, x, z) { \ 194 if (t == y) \ 195 break; \ 196 } \ 197 if (t == y) { \ 198 CHN_REMOVE(x, y, z); \ 199 } \ 200 } while(0) 201 202 #define CHN_UNIT(x) (snd_unit2u((x)->unit)) 203 #define CHN_DEV(x) (snd_unit2d((x)->unit)) 204 #define CHN_CHAN(x) (snd_unit2c((x)->unit)) 205 206 #define CHN_BUF_PARENT(x, y) \ 207 (((x) != NULL && (x)->parentchannel != NULL && \ 208 (x)->parentchannel->bufhard != NULL) ? \ 209 (x)->parentchannel->bufhard : (y)) 210 211 #define CHN_BROADCAST(x) do { \ 212 if ((x)->cv_waiters != 0) \ 213 cv_broadcastpri(x, PRIBIO); \ 214 } while(0) 215 216 #include "channel_if.h" 217 218 int chn_reinit(struct pcm_channel *c); 219 int chn_write(struct pcm_channel *c, struct uio *buf); 220 int chn_read(struct pcm_channel *c, struct uio *buf); 221 u_int32_t chn_start(struct pcm_channel *c, int force); 222 int chn_sync(struct pcm_channel *c, int threshold); 223 int chn_flush(struct pcm_channel *c); 224 int chn_poll(struct pcm_channel *c, int ev, struct thread *td); 225 226 int chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction); 227 int chn_kill(struct pcm_channel *c); 228 int chn_setdir(struct pcm_channel *c, int dir); 229 int chn_reset(struct pcm_channel *c, u_int32_t fmt); 230 int chn_setvolume(struct pcm_channel *c, int left, int right); 231 int chn_setspeed(struct pcm_channel *c, int speed); 232 int chn_setformat(struct pcm_channel *c, u_int32_t fmt); 233 int chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz); 234 int chn_setlatency(struct pcm_channel *c, int latency); 235 int chn_trigger(struct pcm_channel *c, int go); 236 int chn_getptr(struct pcm_channel *c); 237 struct pcmchan_caps *chn_getcaps(struct pcm_channel *c); 238 u_int32_t chn_getformats(struct pcm_channel *c); 239 240 void chn_resetbuf(struct pcm_channel *c); 241 void chn_intr(struct pcm_channel *c); 242 int chn_wrfeed(struct pcm_channel *c); 243 int chn_rdfeed(struct pcm_channel *c); 244 int chn_abort(struct pcm_channel *c); 245 246 void chn_wrupdate(struct pcm_channel *c); 247 void chn_rdupdate(struct pcm_channel *c); 248 249 int chn_notify(struct pcm_channel *c, u_int32_t flags); 250 void chn_lock(struct pcm_channel *c); 251 void chn_unlock(struct pcm_channel *c); 252 253 int chn_getrates(struct pcm_channel *c, int **rates); 254 int chn_syncdestroy(struct pcm_channel *c); 255 256 #ifdef OSSV4_EXPERIMENT 257 int chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak); 258 #endif 259 260 #ifdef USING_MUTEX 261 #define CHN_LOCK(c) mtx_lock((struct mtx *)((c)->lock)) 262 #define CHN_UNLOCK(c) mtx_unlock((struct mtx *)((c)->lock)) 263 #define CHN_TRYLOCK(c) mtx_trylock((struct mtx *)((c)->lock)) 264 #define CHN_LOCKASSERT(c) mtx_assert((struct mtx *)((c)->lock), MA_OWNED) 265 #else 266 #define CHN_LOCK(c) 267 #define CHN_UNLOCK(c) 268 #define CHN_TRYLOCK(c) 269 #define CHN_LOCKASSERT(c) 270 #endif 271 272 int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist); 273 274 #define AFMTSTR_NONE 0 /* "s16le" */ 275 #define AFMTSTR_SIMPLE 1 /* "s16le:s" */ 276 #define AFMTSTR_NUM 2 /* "s16le:2" */ 277 #define AFMTSTR_FULL 3 /* "s16le:stereo" */ 278 279 #define AFMTSTR_MAXSZ 13 /* include null terminator */ 280 281 #define AFMTSTR_MONO_RETURN 0 282 #define AFMTSTR_STEREO_RETURN 1 283 284 struct afmtstr_table { 285 char *fmtstr; 286 u_int32_t format; 287 }; 288 289 int afmtstr_swap_sign(char *); 290 int afmtstr_swap_endian(char *); 291 u_int32_t afmtstr2afmt(struct afmtstr_table *, const char *, int); 292 u_int32_t afmt2afmtstr(struct afmtstr_table *, u_int32_t, char *, size_t, int, int); 293 294 extern int chn_latency; 295 extern int chn_latency_profile; 296 extern int report_soft_formats; 297 298 #define PCMDIR_FAKE 0 299 #define PCMDIR_PLAY 1 300 #define PCMDIR_PLAY_VIRTUAL 2 301 #define PCMDIR_REC -1 302 #define PCMDIR_REC_VIRTUAL -2 303 304 #define PCMTRIG_START 1 305 #define PCMTRIG_EMLDMAWR 2 306 #define PCMTRIG_EMLDMARD 3 307 #define PCMTRIG_STOP 0 308 #define PCMTRIG_ABORT -1 309 310 #define PCMTRIG_COMMON(x) ((x) == PCMTRIG_START || \ 311 (x) == PCMTRIG_STOP || \ 312 (x) == PCMTRIG_ABORT) 313 314 #define CHN_F_CLOSING 0x00000004 /* a pending close */ 315 #define CHN_F_ABORTING 0x00000008 /* a pending abort */ 316 #define CHN_F_RUNNING 0x00000010 /* dma is running */ 317 #define CHN_F_TRIGGERED 0x00000020 318 #define CHN_F_NOTRIGGER 0x00000040 319 #define CHN_F_SLEEPING 0x00000080 320 321 #define CHN_F_BUSY 0x00001000 /* has been opened */ 322 #define CHN_F_HAS_SIZE 0x00002000 /* user set block size */ 323 #define CHN_F_NBIO 0x00004000 /* do non-blocking i/o */ 324 #define CHN_F_MAPPED 0x00010000 /* has been mmap()ed */ 325 #define CHN_F_DEAD 0x00020000 326 #define CHN_F_BADSETTING 0x00040000 327 #define CHN_F_SETBLOCKSIZE 0x00080000 328 #define CHN_F_HAS_VCHAN 0x00100000 329 330 #define CHN_F_VIRTUAL 0x10000000 /* not backed by hardware */ 331 332 #define CHN_F_RESET (CHN_F_BUSY | CHN_F_DEAD | \ 333 CHN_F_HAS_VCHAN | CHN_F_VIRTUAL) 334 335 #define CHN_F_MMAP_INVALID (CHN_F_DEAD | CHN_F_RUNNING) 336 337 338 339 #define CHN_N_RATE 0x00000001 340 #define CHN_N_FORMAT 0x00000002 341 #define CHN_N_VOLUME 0x00000004 342 #define CHN_N_BLOCKSIZE 0x00000008 343 #define CHN_N_TRIGGER 0x00000010 344 345 #define CHN_LATENCY_MIN 0 346 #define CHN_LATENCY_MAX 10 347 #define CHN_LATENCY_DEFAULT 5 348 #define CHN_POLICY_MIN CHN_LATENCY_MIN 349 #define CHN_POLICY_MAX CHN_LATENCY_MAX 350 #define CHN_POLICY_DEFAULT CHN_LATENCY_DEFAULT 351 352 #define CHN_LATENCY_PROFILE_MIN 0 353 #define CHN_LATENCY_PROFILE_MAX 1 354 #define CHN_LATENCY_PROFILE_DEFAULT CHN_LATENCY_PROFILE_MAX 355 356 #define CHN_STARTED(c) ((c)->flags & CHN_F_TRIGGERED) 357 #define CHN_STOPPED(c) (!CHN_STARTED(c)) 358 #define CHN_DIRSTR(c) (((c)->direction == PCMDIR_PLAY) ? \ 359 "PCMDIR_PLAY" : "PCMDIR_REC") 360 361 #define CHN_TIMEOUT 5 362 #define CHN_TIMEOUT_MIN 1 363 #define CHN_TIMEOUT_MAX 10 364 365 /* 366 * This should be large enough to hold all pcm data between 367 * tsleeps in chn_{read,write} at the highest sample rate. 368 * (which is usually 48kHz * 16bit * stereo = 192000 bytes/sec) 369 */ 370 #define CHN_2NDBUFBLKSIZE (2 * 1024) 371 /* The total number of blocks per secondary bufhard. */ 372 #define CHN_2NDBUFBLKNUM (32) 373 /* The size of a whole secondary bufhard. */ 374 #define CHN_2NDBUFMAXSIZE (131072) 375 376 #define CHANNEL_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj)) 377