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