19 * CDDL HEADER END |
19 * CDDL HEADER END |
20 */ |
20 */ |
21 /* |
21 /* |
22 * Copyright (C) 4Front Technologies 1996-2008. |
22 * Copyright (C) 4Front Technologies 1996-2008. |
23 * |
23 * |
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. |
24 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. |
25 * Use is subject to license terms. |
25 * Use is subject to license terms. |
26 */ |
26 */ |
27 |
27 |
28 #include <sys/types.h> |
28 #include <sys/types.h> |
29 #include <sys/sysmacros.h> |
29 #include <sys/sysmacros.h> |
107 auclnt_get_rate(audio_stream_t *sp) |
107 auclnt_get_rate(audio_stream_t *sp) |
108 { |
108 { |
109 return (sp->s_user_parms->p_rate); |
109 return (sp->s_user_parms->p_rate); |
110 } |
110 } |
111 |
111 |
112 unsigned |
112 uint_t |
113 auclnt_get_fragsz(audio_stream_t *sp) |
113 auclnt_get_fragsz(audio_stream_t *sp) |
114 { |
114 { |
115 return (sp->s_fragbytes); |
115 return (sp->s_fragbytes); |
116 } |
116 } |
117 |
117 |
118 unsigned |
118 uint_t |
119 auclnt_get_framesz(audio_stream_t *sp) |
119 auclnt_get_framesz(audio_stream_t *sp) |
120 { |
120 { |
121 return (sp->s_framesz); |
121 return (sp->s_framesz); |
122 } |
122 } |
123 |
123 |
124 unsigned |
124 uint_t |
125 auclnt_get_nfrags(audio_stream_t *sp) |
125 auclnt_get_nfrags(audio_stream_t *sp) |
126 { |
126 { |
127 return (sp->s_nfrags); |
127 return (sp->s_nfrags); |
128 } |
128 } |
129 |
129 |
130 unsigned |
130 uint_t |
131 auclnt_get_nframes(audio_stream_t *sp) |
131 auclnt_get_nframes(audio_stream_t *sp) |
132 { |
132 { |
133 return (sp->s_nframes); |
133 return (sp->s_nframes); |
134 } |
134 } |
135 |
135 |
136 void |
136 void |
137 auclnt_set_latency(audio_stream_t *sp, unsigned frags, unsigned bytes) |
137 auclnt_set_latency(audio_stream_t *sp, uint_t frags, uint_t bytes) |
138 { |
138 { |
139 mutex_enter(&sp->s_lock); |
139 mutex_enter(&sp->s_lock); |
140 sp->s_hintfrags = (uint16_t)frags; |
140 sp->s_hintfrags = (uint16_t)frags; |
141 sp->s_hintsz = bytes; |
141 sp->s_hintsz = bytes; |
142 mutex_exit(&sp->s_lock); |
142 mutex_exit(&sp->s_lock); |
176 auclnt_output_stream(audio_client_t *c) |
176 auclnt_output_stream(audio_client_t *c) |
177 { |
177 { |
178 return (&c->c_ostream); |
178 return (&c->c_ostream); |
179 } |
179 } |
180 |
180 |
181 unsigned |
181 uint_t |
182 auclnt_get_count(audio_stream_t *sp) |
182 auclnt_get_count(audio_stream_t *sp) |
183 { |
183 { |
184 unsigned count; |
184 uint_t count; |
185 |
185 |
186 mutex_enter(&sp->s_lock); |
186 mutex_enter(&sp->s_lock); |
187 ASSERT((sp->s_head - sp->s_tail) <= sp->s_nframes); |
187 ASSERT((sp->s_head - sp->s_tail) <= sp->s_nframes); |
188 count = (unsigned)(sp->s_head - sp->s_tail); |
188 count = (uint_t)(sp->s_head - sp->s_tail); |
189 mutex_exit(&sp->s_lock); |
189 mutex_exit(&sp->s_lock); |
190 |
190 |
191 return (count); |
191 return (count); |
192 } |
192 } |
193 |
193 |
194 unsigned |
194 uint_t |
195 auclnt_consume(audio_stream_t *sp, unsigned n) |
195 auclnt_consume(audio_stream_t *sp, uint_t n) |
196 { |
196 { |
197 mutex_enter(&sp->s_lock); |
197 mutex_enter(&sp->s_lock); |
198 |
198 |
199 ASSERT(sp == &sp->s_client->c_istream); |
199 ASSERT(sp == &sp->s_client->c_istream); |
200 n = max(n, sp->s_head - sp->s_tail); |
200 n = max(n, sp->s_head - sp->s_tail); |
231 ASSERT(sp->s_hidx < nframes); |
231 ASSERT(sp->s_hidx < nframes); |
232 |
232 |
233 cnt = n = min(n, sp->s_head - sp->s_tail); |
233 cnt = n = min(n, sp->s_head - sp->s_tail); |
234 data = sp->s_data + (sp->s_tidx * framesz); |
234 data = sp->s_data + (sp->s_tidx * framesz); |
235 do { |
235 do { |
236 unsigned nf, nb; |
236 uint_t nf, nb; |
237 |
237 |
238 nf = min(nframes - sp->s_tidx, n); |
238 nf = min(nframes - sp->s_tidx, n); |
239 nb = nf * framesz; |
239 nb = nf * framesz; |
240 |
240 |
241 bcopy(data, dst, nb); |
241 bcopy(data, dst, nb); |
257 mutex_exit(&sp->s_lock); |
257 mutex_exit(&sp->s_lock); |
258 |
258 |
259 return (cnt); |
259 return (cnt); |
260 } |
260 } |
261 |
261 |
262 unsigned |
262 uint_t |
263 auclnt_produce(audio_stream_t *sp, unsigned n) |
263 auclnt_produce(audio_stream_t *sp, uint_t n) |
264 { |
264 { |
265 mutex_enter(&sp->s_lock); |
265 mutex_enter(&sp->s_lock); |
266 |
266 |
267 ASSERT(sp == &sp->s_client->c_ostream); |
267 ASSERT(sp == &sp->s_client->c_ostream); |
268 n = max(n, sp->s_nframes - (sp->s_head - sp->s_tail)); |
268 n = max(n, sp->s_nframes - (sp->s_head - sp->s_tail)); |
299 ASSERT(sp->s_hidx < nframes); |
299 ASSERT(sp->s_hidx < nframes); |
300 |
300 |
301 cnt = n = min(n, nframes - (sp->s_head - sp->s_tail)); |
301 cnt = n = min(n, nframes - (sp->s_head - sp->s_tail)); |
302 data = sp->s_data + (sp->s_hidx * framesz); |
302 data = sp->s_data + (sp->s_hidx * framesz); |
303 do { |
303 do { |
304 unsigned nf, nb; |
304 uint_t nf, nb; |
305 |
305 |
306 nf = min(nframes - sp->s_hidx, n); |
306 nf = min(nframes - sp->s_hidx, n); |
307 nb = nf * framesz; |
307 nb = nf * framesz; |
308 |
308 |
309 bcopy(src, data, nb); |
309 bcopy(src, data, nb); |
346 mutex_exit(&sp->s_lock); |
348 mutex_exit(&sp->s_lock); |
347 auclnt_start(sp); |
349 auclnt_start(sp); |
348 mutex_enter(&sp->s_lock); |
350 mutex_enter(&sp->s_lock); |
349 } |
351 } |
350 |
352 |
|
353 |
|
354 framesz = sp->s_framesz; |
|
355 |
351 ASSERT(sp->s_head >= sp->s_tail); |
356 ASSERT(sp->s_head >= sp->s_tail); |
352 ASSERT(sp->s_tidx < sp->s_nframes); |
357 ASSERT(sp->s_tidx < sp->s_nframes); |
353 ASSERT(sp->s_hidx < sp->s_nframes); |
358 |
354 |
359 while (uio->uio_resid >= framesz) { |
355 while (uio->uio_resid >= sp->s_framesz) { |
|
356 |
360 |
357 while ((cnt = (sp->s_head - sp->s_tail)) == 0) { |
361 while ((cnt = (sp->s_head - sp->s_tail)) == 0) { |
358 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) { |
362 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) { |
359 mutex_exit(&sp->s_lock); |
363 mutex_exit(&sp->s_lock); |
360 return (eagain); |
364 return (eagain); |
363 mutex_exit(&sp->s_lock); |
367 mutex_exit(&sp->s_lock); |
364 return (EINTR); |
368 return (EINTR); |
365 } |
369 } |
366 } |
370 } |
367 |
371 |
368 cnt = min(cnt, sp->s_nframes - sp->s_tidx); |
372 tidx = sp->s_tidx; |
369 cnt = min(cnt, (uio->uio_resid / sp->s_framesz)); |
373 cnt = min(cnt, sp->s_nframes - tidx); |
370 |
374 cnt = min(cnt, (uio->uio_resid / framesz)); |
371 rv = uiomove(sp->s_data + (sp->s_tidx * sp->s_framesz), |
375 |
372 cnt * sp->s_framesz, UIO_READ, uio); |
376 mutex_exit(&sp->s_lock); |
|
377 rv = uiomove(sp->s_data + (tidx * framesz), |
|
378 cnt * framesz, UIO_READ, uio); |
|
379 |
373 uio->uio_loffset = loff; |
380 uio->uio_loffset = loff; |
374 eagain = 0; |
381 eagain = 0; |
375 |
382 |
376 if (rv != 0) { |
383 if (rv != 0) { |
377 mutex_exit(&sp->s_lock); |
|
378 return (rv); |
384 return (rv); |
379 } |
385 } |
380 |
386 |
|
387 mutex_enter(&sp->s_lock); |
381 sp->s_tail += cnt; |
388 sp->s_tail += cnt; |
382 sp->s_tidx += cnt; |
389 sp->s_tidx += cnt; |
383 if (sp->s_tidx == sp->s_nframes) { |
390 if (sp->s_tidx == sp->s_nframes) { |
384 sp->s_tidx = 0; |
391 sp->s_tidx = 0; |
385 } |
392 } |
398 |
405 |
399 int |
406 int |
400 auclnt_write(audio_client_t *c, struct uio *uio) |
407 auclnt_write(audio_client_t *c, struct uio *uio) |
401 { |
408 { |
402 audio_stream_t *sp = &c->c_ostream; |
409 audio_stream_t *sp = &c->c_ostream; |
403 unsigned cnt; |
410 uint_t cnt; |
404 int rv = 0; |
411 int rv = 0; |
405 offset_t loff; |
412 offset_t loff; |
406 int eagain; |
413 int eagain; |
|
414 uint_t framesz; |
|
415 uint_t hidx; |
407 |
416 |
408 loff = uio->uio_loffset; |
417 loff = uio->uio_loffset; |
409 eagain = EAGAIN; |
418 eagain = EAGAIN; |
410 |
419 |
411 mutex_enter(&sp->s_lock); |
420 mutex_enter(&sp->s_lock); |
412 |
421 |
|
422 framesz = sp->s_framesz; |
|
423 |
413 ASSERT(sp->s_head >= sp->s_tail); |
424 ASSERT(sp->s_head >= sp->s_tail); |
414 ASSERT(sp->s_tidx < sp->s_nframes); |
|
415 ASSERT(sp->s_hidx < sp->s_nframes); |
425 ASSERT(sp->s_hidx < sp->s_nframes); |
416 |
426 |
417 while (uio->uio_resid >= sp->s_framesz) { |
427 while (uio->uio_resid >= framesz) { |
418 |
428 |
419 while ((cnt = sp->s_nframes - (sp->s_head - sp->s_tail)) == 0) { |
429 while ((cnt = sp->s_nframes - (sp->s_head - sp->s_tail)) == 0) { |
420 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) { |
430 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) { |
421 mutex_exit(&sp->s_lock); |
431 mutex_exit(&sp->s_lock); |
422 return (eagain); |
432 return (eagain); |
425 mutex_exit(&sp->s_lock); |
435 mutex_exit(&sp->s_lock); |
426 return (EINTR); |
436 return (EINTR); |
427 } |
437 } |
428 } |
438 } |
429 |
439 |
430 cnt = min(cnt, sp->s_nframes - sp->s_hidx); |
440 hidx = sp->s_hidx; |
431 cnt = min(cnt, (uio->uio_resid / sp->s_framesz)); |
441 cnt = min(cnt, sp->s_nframes - hidx); |
432 |
442 cnt = min(cnt, (uio->uio_resid / framesz)); |
433 rv = uiomove(sp->s_data + (sp->s_hidx * sp->s_framesz), |
443 |
434 cnt * sp->s_framesz, UIO_WRITE, uio); |
444 /* |
|
445 * We have to drop the stream lock, because the |
|
446 * uiomove might require doing a page in, which could |
|
447 * get blocked behind the PIL of the audio processing |
|
448 * thread which also grabs the s_lock. (Hence, there |
|
449 * is a risk of deadlock due to priority inversion.) |
|
450 */ |
|
451 mutex_exit(&sp->s_lock); |
|
452 |
|
453 rv = uiomove(sp->s_data + (hidx * framesz), |
|
454 cnt * framesz, UIO_WRITE, uio); |
|
455 |
435 uio->uio_loffset = loff; |
456 uio->uio_loffset = loff; |
436 eagain = 0; |
457 eagain = 0; |
437 |
458 |
438 if (rv != 0) { |
459 if (rv != 0) { |
439 mutex_exit(&sp->s_lock); |
|
440 return (rv); |
460 return (rv); |
441 } |
461 } |
|
462 |
|
463 mutex_enter(&sp->s_lock); |
442 |
464 |
443 sp->s_head += cnt; |
465 sp->s_head += cnt; |
444 sp->s_hidx += cnt; |
466 sp->s_hidx += cnt; |
445 if (sp->s_hidx == sp->s_nframes) { |
467 if (sp->s_hidx == sp->s_nframes) { |
446 sp->s_hidx = 0; |
468 sp->s_hidx = 0; |
507 { |
529 { |
508 pollwakeup(&c->c_pollhead, events); |
530 pollwakeup(&c->c_pollhead, events); |
509 } |
531 } |
510 |
532 |
511 void |
533 void |
512 auclnt_get_output_qlen(audio_client_t *c, unsigned *slen, unsigned *flen) |
534 auclnt_get_output_qlen(audio_client_t *c, uint_t *slen, uint_t *flen) |
513 { |
535 { |
514 audio_stream_t *sp = &c->c_ostream; |
536 audio_stream_t *sp = &c->c_ostream; |
515 audio_engine_t *e = sp->s_engine; |
537 audio_engine_t *e = sp->s_engine; |
516 uint64_t el, sl; |
538 uint64_t el, sl; |
517 unsigned cnt, er, sr; |
539 uint_t cnt, er, sr; |
518 |
540 |
519 if (e == NULL) { |
541 if (e == NULL) { |
520 /* if no output engine, can't do it! */ |
542 /* if no output engine, can't do it! */ |
521 *slen = 0; |
543 *slen = 0; |
522 *flen = 0; |
544 *flen = 0; |
531 el = (e->e_head - e->e_tail); |
553 el = (e->e_head - e->e_tail); |
532 } |
554 } |
533 er = e->e_rate; |
555 er = e->e_rate; |
534 sl = sp->s_cnv_cnt; |
556 sl = sp->s_cnv_cnt; |
535 sr = sp->s_user_parms->p_rate; |
557 sr = sp->s_user_parms->p_rate; |
536 cnt = (unsigned)(sp->s_head - sp->s_tail); |
558 cnt = (uint_t)(sp->s_head - sp->s_tail); |
537 mutex_exit(&sp->s_lock); |
559 mutex_exit(&sp->s_lock); |
538 mutex_exit(&e->e_lock); |
560 mutex_exit(&e->e_lock); |
539 |
561 |
540 /* engine frames converted to stream rate, plus stream frames */ |
562 /* engine frames converted to stream rate, plus stream frames */ |
541 *slen = cnt; |
563 *slen = cnt; |
542 *flen = ((unsigned)(((el * sr) / er) + sl)); |
564 *flen = ((uint_t)(((el * sr) / er) + sl)); |
543 } |
565 } |
544 |
566 |
545 int |
567 int |
546 auclnt_set_format(audio_stream_t *sp, int fmt) |
568 auclnt_set_format(audio_stream_t *sp, int fmt) |
547 { |
569 { |
1195 } |
1217 } |
1196 rw_exit(&auimpl_client_lock); |
1218 rw_exit(&auimpl_client_lock); |
1197 return (c); |
1219 return (c); |
1198 } |
1220 } |
1199 |
1221 |
|
1222 int |
|
1223 auclnt_serialize(audio_client_t *c) |
|
1224 { |
|
1225 mutex_enter(&c->c_lock); |
|
1226 while (c->c_serialize) { |
|
1227 if (cv_wait_sig(&c->c_cv, &c->c_lock) == 0) { |
|
1228 mutex_exit(&c->c_lock); |
|
1229 return (EINTR); |
|
1230 } |
|
1231 } |
|
1232 c->c_serialize = B_TRUE; |
|
1233 mutex_exit(&c->c_lock); |
|
1234 return (0); |
|
1235 } |
|
1236 |
|
1237 void |
|
1238 auclnt_unserialize(audio_client_t *c) |
|
1239 { |
|
1240 mutex_enter(&c->c_lock); |
|
1241 ASSERT(c->c_serialize); |
|
1242 c->c_serialize = B_FALSE; |
|
1243 cv_broadcast(&c->c_cv); |
|
1244 mutex_exit(&c->c_lock); |
|
1245 } |
|
1246 |
|
1247 void |
|
1248 auclnt_hold(audio_client_t *c) |
|
1249 { |
|
1250 mutex_enter(&c->c_lock); |
|
1251 c->c_refcnt++; |
|
1252 mutex_exit(&c->c_lock); |
|
1253 } |
|
1254 |
1200 void |
1255 void |
1201 auclnt_release(audio_client_t *c) |
1256 auclnt_release(audio_client_t *c) |
1202 { |
1257 { |
1203 mutex_enter(&c->c_lock); |
1258 mutex_enter(&c->c_lock); |
1204 ASSERT(c->c_refcnt > 0); |
1259 ASSERT(c->c_refcnt > 0); |
1410 auclnt_get_dev_version(audio_dev_t *dev) |
1465 auclnt_get_dev_version(audio_dev_t *dev) |
1411 { |
1466 { |
1412 return (dev->d_vers); |
1467 return (dev->d_vers); |
1413 } |
1468 } |
1414 |
1469 |
1415 unsigned |
1470 uint_t |
1416 auclnt_get_dev_capab(audio_dev_t *dev) |
1471 auclnt_get_dev_capab(audio_dev_t *dev) |
1417 { |
1472 { |
1418 uint32_t flags; |
1473 uint32_t flags; |
1419 unsigned caps = 0; |
1474 uint_t caps = 0; |
1420 |
1475 |
1421 flags = dev->d_flags; |
1476 flags = dev->d_flags; |
1422 |
1477 |
1423 if (flags & DEV_OUTPUT_CAP) |
1478 if (flags & DEV_OUTPUT_CAP) |
1424 caps |= AUDIO_CLIENT_CAP_PLAY; |
1479 caps |= AUDIO_CLIENT_CAP_PLAY; |
1575 int (*walker)(audio_ctrl_t *, void *), |
1630 int (*walker)(audio_ctrl_t *, void *), |
1576 void *arg) |
1631 void *arg) |
1577 { |
1632 { |
1578 audio_ctrl_t *ctrl; |
1633 audio_ctrl_t *ctrl; |
1579 |
1634 |
1580 rw_enter(&d->d_ctrl_lock, RW_READER); |
1635 mutex_enter(&d->d_ctrl_lock); |
1581 for (ctrl = list_head(&d->d_controls); ctrl; |
1636 for (ctrl = list_head(&d->d_controls); ctrl; |
1582 ctrl = list_next(&d->d_controls, ctrl)) { |
1637 ctrl = list_next(&d->d_controls, ctrl)) { |
1583 if (walker(ctrl, arg) == AUDIO_WALK_STOP) |
1638 if (walker(ctrl, arg) == AUDIO_WALK_STOP) |
1584 break; |
1639 break; |
1585 } |
1640 } |
1586 rw_exit(&d->d_ctrl_lock); |
1641 mutex_exit(&d->d_ctrl_lock); |
1587 } |
1642 } |
1588 |
1643 |
1589 /* |
1644 /* |
1590 * This will search all controls attached to an |
1645 * This will search all controls attached to an |
1591 * audio device for a control with the desired name. |
1646 * audio device for a control with the desired name. |
1602 audio_ctrl_t *ctrl; |
1657 audio_ctrl_t *ctrl; |
1603 |
1658 |
1604 /* Verify argument */ |
1659 /* Verify argument */ |
1605 ASSERT(d); |
1660 ASSERT(d); |
1606 |
1661 |
1607 rw_enter(&d->d_ctrl_lock, RW_READER); |
1662 mutex_enter(&d->d_ctrl_lock); |
1608 for (ctrl = list_head(&d->d_controls); ctrl; |
1663 for (ctrl = list_head(&d->d_controls); ctrl; |
1609 ctrl = list_next(&d->d_controls, ctrl)) { |
1664 ctrl = list_next(&d->d_controls, ctrl)) { |
1610 if (strcmp(ctrl->ctrl_name, name) == 0) { |
1665 if (strcmp(ctrl->ctrl_name, name) == 0) { |
1611 rw_exit(&d->d_ctrl_lock); |
1666 mutex_exit(&d->d_ctrl_lock); |
1612 return (ctrl); |
1667 return (ctrl); |
1613 } |
1668 } |
1614 } |
1669 } |
1615 rw_exit(&d->d_ctrl_lock); |
1670 mutex_exit(&d->d_ctrl_lock); |
1616 return (NULL); |
1671 return (NULL); |
1617 } |
1672 } |
1618 |
1673 |
1619 /* |
1674 /* |
1620 * Given a known control, get its attributes. |
1675 * Given a known control, get its attributes. |