1/** 2 * \file control/hcontrol.c 3 * \brief HCTL Interface - High Level CTL 4 * \author Jaroslav Kysela <perex@perex.cz> 5 * \author Abramo Bagnara <abramo@alsa-project.org> 6 * \date 2000 7 * 8 * HCTL interface is designed to access preloaded and sorted primitive controls. 9 * Callbacks may be used for event handling. 10 * See \ref hcontrol page for more details. 11 */ 12/* 13 * Control Interface - high level API 14 * Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz> 15 * Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org> 16 * 17 * 18 * This library is free software; you can redistribute it and/or modify 19 * it under the terms of the GNU Lesser General Public License as 20 * published by the Free Software Foundation; either version 2.1 of 21 * the License, or (at your option) any later version. 22 * 23 * This program is distributed in the hope that it will be useful, 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * GNU Lesser General Public License for more details. 27 * 28 * You should have received a copy of the GNU Lesser General Public 29 * License along with this library; if not, write to the Free Software 30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 31 * 32 */ 33 34/*! \page hcontrol High level control interface 35 36<P> High level control interface is designed to access preloaded and sorted primitive controls. 37 38\section hcontrol_general_overview General overview 39 40<P> High level control interface caches the accesses to primitive controls 41to reduce overhead accessing the real controls in kernel drivers. 42 43*/ 44 45#include <stdio.h> 46#include <stdlib.h> 47#include <unistd.h> 48#include <string.h> 49#include <fcntl.h> 50#include <sys/ioctl.h> 51#include "control_local.h" 52#ifdef HAVE_LIBPTHREAD 53#include <pthread.h> 54#endif 55 56#ifndef DOC_HIDDEN 57#define NOT_FOUND 1000000000 58#endif 59 60static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, 61 const snd_hctl_elem_t *c2); 62 63/** 64 * \brief Opens an HCTL 65 * \param hctlp Returned HCTL handle 66 * \param name ASCII identifier of the underlying CTL handle 67 * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) 68 * \return 0 on success otherwise a negative error code 69 */ 70int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode) 71{ 72 snd_ctl_t *ctl; 73 int err; 74 75 if ((err = snd_ctl_open(&ctl, name, mode)) < 0) 76 return err; 77 err = snd_hctl_open_ctl(hctlp, ctl); 78 if (err < 0) 79 snd_ctl_close(ctl); 80 return err; 81} 82 83/** 84 * \brief Opens an HCTL 85 * \param hctlp Returned HCTL handle 86 * \param ctl underlying CTL handle 87 * \return 0 on success otherwise a negative error code 88 */ 89int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl) 90{ 91 snd_hctl_t *hctl; 92 93 assert(hctlp); 94 *hctlp = NULL; 95 if ((hctl = (snd_hctl_t *)calloc(1, sizeof(snd_hctl_t))) == NULL) 96 return -ENOMEM; 97 INIT_LIST_HEAD(&hctl->elems); 98 hctl->ctl = ctl; 99 *hctlp = hctl; 100 return 0; 101} 102 103/** 104 * \brief close HCTL handle 105 * \param hctl HCTL handle 106 * \return 0 on success otherwise a negative error code 107 * 108 * Closes the specified HCTL handle and frees all associated 109 * resources. 110 */ 111int snd_hctl_close(snd_hctl_t *hctl) 112{ 113 int err; 114 115 assert(hctl); 116 err = snd_ctl_close(hctl->ctl); 117 snd_hctl_free(hctl); 118 free(hctl); 119 return err; 120} 121 122/** 123 * \brief get identifier of HCTL handle 124 * \param hctl HCTL handle 125 * \return ascii identifier of HCTL handle 126 * 127 * Returns the ASCII identifier of given HCTL handle. It's the same 128 * identifier specified in snd_hctl_open(). 129 */ 130const char *snd_hctl_name(snd_hctl_t *hctl) 131{ 132 assert(hctl); 133 return snd_ctl_name(hctl->ctl); 134} 135 136/** 137 * \brief set nonblock mode 138 * \param hctl HCTL handle 139 * \param nonblock 0 = block, 1 = nonblock mode 140 * \return 0 on success otherwise a negative error code 141 */ 142int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock) 143{ 144 assert(hctl); 145 return snd_ctl_nonblock(hctl->ctl, nonblock); 146} 147 148/** 149 * \brief set async mode 150 * \param hctl HCTL handle 151 * \param sig Signal to raise: < 0 disable, 0 default (SIGIO) 152 * \param pid Process ID to signal: 0 current 153 * \return 0 on success otherwise a negative error code 154 * 155 * A signal is raised when a change happens. 156 */ 157int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid) 158{ 159 assert(hctl); 160 return snd_ctl_async(hctl->ctl, sig, pid); 161} 162 163/** 164 * \brief get count of poll descriptors for HCTL handle 165 * \param hctl HCTL handle 166 * \return count of poll descriptors 167 */ 168int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl) 169{ 170 assert(hctl); 171 return snd_ctl_poll_descriptors_count(hctl->ctl); 172} 173 174/** 175 * \brief get poll descriptors 176 * \param hctl HCTL handle 177 * \param pfds array of poll descriptors 178 * \param space space in the poll descriptor array 179 * \return count of filled descriptors 180 */ 181int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space) 182{ 183 assert(hctl); 184 return snd_ctl_poll_descriptors(hctl->ctl, pfds, space); 185} 186 187/** 188 * \brief get returned events from poll descriptors 189 * \param hctl HCTL handle 190 * \param pfds array of poll descriptors 191 * \param nfds count of poll descriptors 192 * \param revents returned events 193 * \return zero if success, otherwise a negative error code 194 */ 195int snd_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 196{ 197 assert(hctl); 198 return snd_ctl_poll_descriptors_revents(hctl->ctl, pfds, nfds, revents); 199} 200 201static int snd_hctl_throw_event(snd_hctl_t *hctl, unsigned int mask, 202 snd_hctl_elem_t *elem) 203{ 204 if (hctl->callback) 205 return hctl->callback(hctl, mask, elem); 206 return 0; 207} 208 209static int snd_hctl_elem_throw_event(snd_hctl_elem_t *elem, 210 unsigned int mask) 211{ 212 if (elem->callback) 213 return elem->callback(elem, mask); 214 return 0; 215} 216 217static int snd_hctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef) 218{ 219 int res; 220 221 for (res = 0; *names; names++, res += coef) { 222 if (!strncmp(*name, *names, strlen(*names))) { 223 *name += strlen(*names); 224 if (**name == ' ') 225 (*name)++; 226 return res+1; 227 } 228 } 229 return NOT_FOUND; 230} 231 232static int get_compare_weight(const snd_ctl_elem_id_t *id) 233{ 234 static const char *const names[] = { 235 "Master", 236 "Hardware Master", 237 "Headphone", 238 "Tone Control", 239 "3D Control", 240 "PCM", 241 "Front", 242 "Surround", 243 "Center", 244 "LFE", 245 "Synth", 246 "FM", 247 "Wave", 248 "Music", 249 "DSP", 250 "Line", 251 "CD", 252 "Mic", 253 "Phone", 254 "Video", 255 "Zoom Video", 256 "PC Speaker", 257 "Aux", 258 "Mono", 259 "ADC", 260 "Capture Source", 261 "Capture", 262 "Playback", 263 "Loopback", 264 "Analog Loopback", 265 "Digital Loopback", 266 "I2S", 267 "IEC958", 268 NULL 269 }; 270 static const char *const names1[] = { 271 "Switch", 272 "Volume", 273 "Playback", 274 "Capture", 275 "Bypass", 276 "Mono", 277 "Front", 278 "Rear", 279 "Pan", 280 "Output", 281 "-", 282 NULL 283 }; 284 static const char *const names2[] = { 285 "Switch", 286 "Volume", 287 "Bypass", 288 "Depth", 289 "Wide", 290 "Space", 291 "Level", 292 "Center", 293 NULL 294 }; 295 const char *name = (char *)id->name, *name1; 296 int res, res1; 297 298 if ((res = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND) 299 return NOT_FOUND; 300 if (*name == '\0') 301 return res; 302 for (name1 = name; *name1 != '\0'; name1++); 303 for (name1--; name1 != name && *name1 != ' '; name1--); 304 while (name1 != name && *name1 == ' ') 305 name1--; 306 if (name1 != name) { 307 for (; name1 != name && *name1 != ' '; name1--); 308 name = name1; 309 if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND) 310 return res; 311 res += res1; 312 } else { 313 name = name1; 314 } 315 if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND) 316 return res; 317 return res + res1; 318} 319 320static int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, int *dir) 321{ 322 unsigned int l, u; 323 snd_hctl_elem_t el; 324 int c = 0; 325 int idx = -1; 326 assert(hctl && id); 327 assert(hctl->compare); 328 el.id = *id; 329 el.compare_weight = get_compare_weight(id); 330 l = 0; 331 u = hctl->count; 332 while (l < u) { 333 idx = (l + u) / 2; 334 c = hctl->compare(&el, hctl->pelems[idx]); 335 if (c < 0) 336 u = idx; 337 else if (c > 0) 338 l = idx + 1; 339 else 340 break; 341 } 342 *dir = c; 343 return idx; 344} 345 346static int snd_hctl_elem_add(snd_hctl_t *hctl, snd_hctl_elem_t *elem) 347{ 348 int dir; 349 int idx; 350 elem->compare_weight = get_compare_weight(&elem->id); 351 if (hctl->count == hctl->alloc) { 352 snd_hctl_elem_t **h; 353 hctl->alloc += 32; 354 h = realloc(hctl->pelems, sizeof(*h) * hctl->alloc); 355 if (!h) { 356 hctl->alloc -= 32; 357 return -ENOMEM; 358 } 359 hctl->pelems = h; 360 } 361 if (hctl->count == 0) { 362 list_add_tail(&elem->list, &hctl->elems); 363 hctl->pelems[0] = elem; 364 } else { 365 idx = _snd_hctl_find_elem(hctl, &elem->id, &dir); 366 assert(dir != 0); 367 if (dir > 0) { 368 list_add(&elem->list, &hctl->pelems[idx]->list); 369 idx++; 370 } else { 371 list_add_tail(&elem->list, &hctl->pelems[idx]->list); 372 } 373 memmove(hctl->pelems + idx + 1, 374 hctl->pelems + idx, 375 (hctl->count - idx) * sizeof(snd_hctl_elem_t *)); 376 hctl->pelems[idx] = elem; 377 } 378 hctl->count++; 379 return snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, elem); 380} 381 382static void snd_hctl_elem_remove(snd_hctl_t *hctl, unsigned int idx) 383{ 384 snd_hctl_elem_t *elem = hctl->pelems[idx]; 385 unsigned int m; 386 snd_hctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE); 387 list_del(&elem->list); 388 free(elem); 389 hctl->count--; 390 m = hctl->count - idx; 391 if (m > 0) 392 memmove(hctl->pelems + idx, 393 hctl->pelems + idx + 1, 394 m * sizeof(snd_hctl_elem_t *)); 395} 396 397/** 398 * \brief free HCTL loaded elements 399 * \param hctl HCTL handle 400 * \return 0 on success otherwise a negative error code 401 */ 402int snd_hctl_free(snd_hctl_t *hctl) 403{ 404 while (hctl->count > 0) 405 snd_hctl_elem_remove(hctl, hctl->count - 1); 406 free(hctl->pelems); 407 hctl->pelems = 0; 408 hctl->alloc = 0; 409 INIT_LIST_HEAD(&hctl->elems); 410 return 0; 411} 412 413static snd_hctl_t *compare_hctl; 414static int hctl_compare(const void *a, const void *b) { 415 return compare_hctl->compare(*(const snd_hctl_elem_t * const *) a, 416 *(const snd_hctl_elem_t * const *) b); 417} 418 419static void snd_hctl_sort(snd_hctl_t *hctl) 420{ 421 unsigned int k; 422#ifdef HAVE_LIBPTHREAD 423 static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER; 424#endif 425 426 assert(hctl); 427 assert(hctl->compare); 428 INIT_LIST_HEAD(&hctl->elems); 429 430#ifdef HAVE_LIBPTHREAD 431 pthread_mutex_lock(&sync_lock); 432#endif 433 compare_hctl = hctl; 434 qsort(hctl->pelems, hctl->count, sizeof(*hctl->pelems), hctl_compare); 435#ifdef HAVE_LIBPTHREAD 436 pthread_mutex_unlock(&sync_lock); 437#endif 438 for (k = 0; k < hctl->count; k++) 439 list_add_tail(&hctl->pelems[k]->list, &hctl->elems); 440} 441 442/** 443 * \brief Change HCTL compare function and reorder elements 444 * \param hctl HCTL handle 445 * \param compare Element compare function 446 * \return 0 on success otherwise a negative error code 447 */ 448int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare) 449{ 450 assert(hctl); 451 hctl->compare = compare == NULL ? snd_hctl_compare_default : compare; 452 snd_hctl_sort(hctl); 453 return 0; 454} 455 456/** 457 * \brief A "don't care" fast compare functions that may be used with #snd_hctl_set_compare 458 * \param c1 First HCTL element 459 * \param c2 Second HCTL element 460 * \return -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2 461 */ 462int snd_hctl_compare_fast(const snd_hctl_elem_t *c1, 463 const snd_hctl_elem_t *c2) 464{ 465 return c1->id.numid - c2->id.numid; 466} 467 468static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, 469 const snd_hctl_elem_t *c2) 470{ 471 int res, d; 472 473 d = c1->id.iface - c2->id.iface; 474 if (d != 0) 475 return d; 476 if (c1->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER) { 477 d = c1->compare_weight - c2->compare_weight; 478 if (d != 0) 479 return d; 480 } 481 d = c1->id.device - c2->id.device; 482 if (d != 0) 483 return d; 484 d = c1->id.subdevice - c2->id.subdevice; 485 if (d != 0) 486 return d; 487 res = strcmp((const char *)c1->id.name, (const char *)c2->id.name); 488 if (res != 0) 489 return res; 490 return c1->id.index - c2->id.index; 491} 492 493/** 494 * \brief get first element for an HCTL 495 * \param hctl HCTL handle 496 * \return pointer to first element 497 */ 498snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl) 499{ 500 assert(hctl); 501 if (list_empty(&hctl->elems)) 502 return NULL; 503 return list_entry(hctl->elems.next, snd_hctl_elem_t, list); 504} 505 506/** 507 * \brief get last element for an HCTL 508 * \param hctl HCTL handle 509 * \return pointer to last element 510 */ 511snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl) 512{ 513 assert(hctl); 514 if (list_empty(&hctl->elems)) 515 return NULL; 516 return list_entry(hctl->elems.prev, snd_hctl_elem_t, list); 517} 518 519/** 520 * \brief get next HCTL element 521 * \param elem HCTL element 522 * \return pointer to next element 523 */ 524snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem) 525{ 526 assert(elem); 527 if (elem->list.next == &elem->hctl->elems) 528 return NULL; 529 return list_entry(elem->list.next, snd_hctl_elem_t, list); 530} 531 532/** 533 * \brief get previous HCTL element 534 * \param elem HCTL element 535 * \return pointer to previous element 536 */ 537snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem) 538{ 539 assert(elem); 540 if (elem->list.prev == &elem->hctl->elems) 541 return NULL; 542 return list_entry(elem->list.prev, snd_hctl_elem_t, list); 543} 544 545/** 546 * \brief Search an HCTL element 547 * \param hctl HCTL handle 548 * \param id Element identifier 549 * \return pointer to found HCTL element or NULL if it does not exists 550 */ 551snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id) 552{ 553 int dir; 554 int res = _snd_hctl_find_elem(hctl, id, &dir); 555 if (res < 0 || dir != 0) 556 return NULL; 557 return hctl->pelems[res]; 558} 559 560/** 561 * \brief Load an HCTL with all elements and sort them 562 * \param hctl HCTL handle 563 * \return 0 on success otherwise a negative error code 564 */ 565int snd_hctl_load(snd_hctl_t *hctl) 566{ 567 snd_ctl_elem_list_t list; 568 int err = 0; 569 unsigned int idx; 570 571 assert(hctl); 572 assert(hctl->ctl); 573 assert(hctl->count == 0); 574 assert(list_empty(&hctl->elems)); 575 memset(&list, 0, sizeof(list)); 576 if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) 577 goto _end; 578 while (list.count != list.used) { 579 err = snd_ctl_elem_list_alloc_space(&list, list.count); 580 if (err < 0) 581 goto _end; 582 if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) 583 goto _end; 584 } 585 if (hctl->alloc < list.count) { 586 hctl->alloc = list.count; 587 free(hctl->pelems); 588 hctl->pelems = malloc(hctl->alloc * sizeof(*hctl->pelems)); 589 if (!hctl->pelems) { 590 err = -ENOMEM; 591 goto _end; 592 } 593 } 594 for (idx = 0; idx < list.count; idx++) { 595 snd_hctl_elem_t *elem; 596 elem = calloc(1, sizeof(snd_hctl_elem_t)); 597 if (elem == NULL) { 598 snd_hctl_free(hctl); 599 err = -ENOMEM; 600 goto _end; 601 } 602 elem->id = list.pids[idx]; 603 elem->hctl = hctl; 604 elem->compare_weight = get_compare_weight(&elem->id); 605 hctl->pelems[idx] = elem; 606 list_add_tail(&elem->list, &hctl->elems); 607 hctl->count++; 608 } 609 if (!hctl->compare) 610 hctl->compare = snd_hctl_compare_default; 611 snd_hctl_sort(hctl); 612 for (idx = 0; idx < hctl->count; idx++) { 613 int res = snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, 614 hctl->pelems[idx]); 615 if (res < 0) 616 return res; 617 } 618 err = snd_ctl_subscribe_events(hctl->ctl, 1); 619 _end: 620 free(list.pids); 621 return err; 622} 623 624/** 625 * \brief Set callback function for an HCTL 626 * \param hctl HCTL handle 627 * \param callback callback function 628 */ 629void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback) 630{ 631 assert(hctl); 632 hctl->callback = callback; 633} 634 635/** 636 * \brief Set callback private value for an HCTL 637 * \param hctl HCTL handle 638 * \param callback_private callback private value 639 */ 640void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private) 641{ 642 assert(hctl); 643 hctl->callback_private = callback_private; 644} 645 646/** 647 * \brief Get callback private value for an HCTL 648 * \param hctl HCTL handle 649 * \return callback private value 650 */ 651void *snd_hctl_get_callback_private(snd_hctl_t *hctl) 652{ 653 assert(hctl); 654 return hctl->callback_private; 655} 656 657/** 658 * \brief Get number of loaded elements for an HCTL 659 * \param hctl HCTL handle 660 * \return elements count 661 */ 662unsigned int snd_hctl_get_count(snd_hctl_t *hctl) 663{ 664 return hctl->count; 665} 666 667/** 668 * \brief Wait for a HCTL to become ready (i.e. at least one event pending) 669 * \param hctl HCTL handle 670 * \param timeout maximum time in milliseconds to wait 671 * \return a positive value on success otherwise a negative error code 672 * \retval 0 timeout occurred 673 * \retval 1 an event is pending 674 */ 675int snd_hctl_wait(snd_hctl_t *hctl, int timeout) 676{ 677 struct pollfd *pfd; 678 unsigned short *revents; 679 int i, npfds, pollio, err, err_poll; 680 681 npfds = snd_hctl_poll_descriptors_count(hctl); 682 if (npfds <= 0 || npfds >= 16) { 683 SNDERR("Invalid poll_fds %d\n", npfds); 684 return -EIO; 685 } 686 pfd = alloca(sizeof(*pfd) * npfds); 687 revents = alloca(sizeof(*revents) * npfds); 688 err = snd_hctl_poll_descriptors(hctl, pfd, npfds); 689 if (err < 0) 690 return err; 691 if (err != npfds) { 692 SNDMSG("invalid poll descriptors %d\n", err); 693 return -EIO; 694 } 695 do { 696 pollio = 0; 697 err_poll = poll(pfd, npfds, timeout); 698 if (err_poll < 0) { 699 if (errno == EINTR) 700 continue; 701 return -errno; 702 } 703 if (! err_poll) 704 break; 705 err = snd_hctl_poll_descriptors_revents(hctl, pfd, npfds, revents); 706 if (err < 0) 707 return err; 708 for (i = 0; i < npfds; i++) { 709 if (revents[i] & (POLLERR | POLLNVAL)) 710 return -EIO; 711 if ((revents[i] & (POLLIN | POLLOUT)) == 0) 712 continue; 713 pollio++; 714 } 715 } while (! pollio); 716 return err_poll > 0 ? 1 : 0; 717} 718 719/** 720 * \brief Get a ctl handle associated to the given hctl handle 721 * \param hctl HCTL handle 722 * \return a ctl handle otherwise NULL 723 */ 724snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl) 725{ 726 return hctl->ctl; 727} 728 729static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event) 730{ 731 snd_hctl_elem_t *elem; 732 int res; 733 734 assert(hctl); 735 assert(hctl->ctl); 736 switch (event->type) { 737 case SND_CTL_EVENT_ELEM: 738 break; 739 default: 740 return 0; 741 } 742 if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE) { 743 int dir; 744 res = _snd_hctl_find_elem(hctl, &event->data.elem.id, &dir); 745 assert(res >= 0 && dir == 0); 746 if (res < 0 || dir != 0) 747 return -ENOENT; 748 snd_hctl_elem_remove(hctl, (unsigned int) res); 749 return 0; 750 } 751 if (event->data.elem.mask & SNDRV_CTL_EVENT_MASK_ADD) { 752 elem = calloc(1, sizeof(snd_hctl_elem_t)); 753 if (elem == NULL) 754 return -ENOMEM; 755 elem->id = event->data.elem.id; 756 elem->hctl = hctl; 757 res = snd_hctl_elem_add(hctl, elem); 758 if (res < 0) 759 return res; 760 } 761 if (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | 762 SNDRV_CTL_EVENT_MASK_INFO)) { 763 elem = snd_hctl_find_elem(hctl, &event->data.elem.id); 764 if (!elem) 765 return -ENOENT; 766 res = snd_hctl_elem_throw_event(elem, event->data.elem.mask & 767 (SNDRV_CTL_EVENT_MASK_VALUE | 768 SNDRV_CTL_EVENT_MASK_INFO)); 769 if (res < 0) 770 return res; 771 } 772 return 0; 773} 774 775/** 776 * \brief Handle pending HCTL events invoking callbacks 777 * \param hctl HCTL handle 778 * \return 0 otherwise a negative error code on failure 779 */ 780int snd_hctl_handle_events(snd_hctl_t *hctl) 781{ 782 snd_ctl_event_t event; 783 int res; 784 unsigned int count = 0; 785 786 assert(hctl); 787 assert(hctl->ctl); 788 while ((res = snd_ctl_read(hctl->ctl, &event)) != 0 && 789 res != -EAGAIN) { 790 if (res < 0) 791 return res; 792 res = snd_hctl_handle_event(hctl, &event); 793 if (res < 0) 794 return res; 795 count++; 796 } 797 return count; 798} 799 800/** 801 * \brief Get information for an HCTL element 802 * \param elem HCTL element 803 * \param info HCTL element information 804 * \return 0 otherwise a negative error code on failure 805 */ 806int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info) 807{ 808 assert(elem); 809 assert(elem->hctl); 810 assert(info); 811 info->id = elem->id; 812 return snd_ctl_elem_info(elem->hctl->ctl, info); 813} 814 815/** 816 * \brief Get value for an HCTL element 817 * \param elem HCTL element 818 * \param value HCTL element value 819 * \return 0 otherwise a negative error code on failure 820 */ 821int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) 822{ 823 assert(elem); 824 assert(elem->hctl); 825 assert(value); 826 value->id = elem->id; 827 return snd_ctl_elem_read(elem->hctl->ctl, value); 828} 829 830/** 831 * \brief Set value for an HCTL element 832 * \param elem HCTL element 833 * \param value HCTL element value 834 * \retval 0 on success 835 * \retval >1 on success when value was changed 836 * \retval <0 a negative error code on failure 837 */ 838int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) 839{ 840 assert(elem); 841 assert(elem->hctl); 842 assert(value); 843 value->id = elem->id; 844 return snd_ctl_elem_write(elem->hctl->ctl, value); 845} 846 847/** 848 * \brief Get TLV value for an HCTL element 849 * \param elem HCTL element 850 * \param tlv TLV array for value 851 * \param tlv_size size of TLV array in bytes 852 * \return 0 otherwise a negative error code on failure 853 */ 854int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size) 855{ 856 assert(elem); 857 assert(tlv); 858 assert(tlv_size >= 12); 859 return snd_ctl_elem_tlv_read(elem->hctl->ctl, &elem->id, tlv, tlv_size); 860} 861 862/** 863 * \brief Set TLV value for an HCTL element 864 * \param elem HCTL element 865 * \param tlv TLV array for value 866 * \retval 0 on success 867 * \retval >1 on success when value was changed 868 * \retval <0 a negative error code on failure 869 */ 870int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv) 871{ 872 assert(elem); 873 assert(tlv); 874 assert(tlv[1] >= 4); 875 return snd_ctl_elem_tlv_write(elem->hctl->ctl, &elem->id, tlv); 876} 877 878/** 879 * \brief Set TLV value for an HCTL element 880 * \param elem HCTL element 881 * \param tlv TLV array for value 882 * \retval 0 on success 883 * \retval >1 on success when value was changed 884 * \retval <0 a negative error code on failure 885 */ 886int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv) 887{ 888 assert(elem); 889 assert(tlv); 890 assert(tlv[1] >= 4); 891 return snd_ctl_elem_tlv_command(elem->hctl->ctl, &elem->id, tlv); 892} 893 894/** 895 * \brief Get HCTL handle for an HCTL element 896 * \param elem HCTL element 897 * \return HCTL handle 898 */ 899snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem) 900{ 901 assert(elem); 902 return elem->hctl; 903} 904 905/** 906 * \brief Get CTL element identifier of a CTL element id/value 907 * \param obj CTL element id/value 908 * \param ptr Pointer to returned CTL element identifier 909 */ 910void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr) 911{ 912 assert(obj && ptr); 913 *ptr = obj->id; 914} 915 916/** 917 * \brief Get element numeric identifier of a CTL element id/value 918 * \param obj CTL element id/value 919 * \return element numeric identifier 920 */ 921unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj) 922{ 923 assert(obj); 924 return obj->id.numid; 925} 926 927/** 928 * \brief Get interface part of CTL element identifier of a CTL element id/value 929 * \param obj CTL element id/value 930 * \return interface part of element identifier 931 */ 932snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj) 933{ 934 assert(obj); 935 return obj->id.iface; 936} 937 938/** 939 * \brief Get device part of CTL element identifier of a CTL element id/value 940 * \param obj CTL element id/value 941 * \return device part of element identifier 942 */ 943unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj) 944{ 945 assert(obj); 946 return obj->id.device; 947} 948 949/** 950 * \brief Get subdevice part of CTL element identifier of a CTL element id/value 951 * \param obj CTL element id/value 952 * \return subdevice part of element identifier 953 */ 954unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj) 955{ 956 assert(obj); 957 return obj->id.subdevice; 958} 959 960/** 961 * \brief Get name part of CTL element identifier of a CTL element id/value 962 * \param obj CTL element id/value 963 * \return name part of element identifier 964 */ 965const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj) 966{ 967 assert(obj); 968 return (const char *)obj->id.name; 969} 970 971/** 972 * \brief Get index part of CTL element identifier of a CTL element id/value 973 * \param obj CTL element id/value 974 * \return index part of element identifier 975 */ 976unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj) 977{ 978 assert(obj); 979 return obj->id.index; 980} 981 982/** 983 * \brief Set callback function for an HCTL element 984 * \param obj HCTL element 985 * \param val callback function 986 */ 987void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val) 988{ 989 assert(obj); 990 obj->callback = val; 991} 992 993/** 994 * \brief Set callback private value for an HCTL element 995 * \param obj HCTL element 996 * \param val callback private value 997 */ 998void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val) 999{ 1000 assert(obj); 1001 obj->callback_private = val; 1002} 1003 1004/** 1005 * \brief Get callback private value for an HCTL element 1006 * \param obj HCTL element 1007 * \return callback private value 1008 */ 1009void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj) 1010{ 1011 assert(obj); 1012 return obj->callback_private; 1013} 1014 1015