1/* 2 * user-control-element-set.c - a program to test in-kernel implementation of 3 * user-defined control element set. 4 * 5 * Copyright (c) 2015-2016 Takashi Sakamoto 6 * 7 * Licensed under the terms of the GNU General Public License, version 2. 8 */ 9 10#include "config.h" 11#include "../include/asoundlib.h" 12#include <sound/tlv.h> 13#include <stdbool.h> 14 15struct elem_set_trial { 16 snd_ctl_t *handle; 17 18 snd_ctl_elem_type_t type; 19 unsigned int member_count; 20 unsigned int element_count; 21 22 snd_ctl_elem_id_t *id; 23 24 int (*add_elem_set)(struct elem_set_trial *trial, 25 snd_ctl_elem_info_t *info); 26 int (*check_elem_props)(struct elem_set_trial *trial, 27 snd_ctl_elem_info_t *info); 28 void (*change_elem_members)(struct elem_set_trial *trial, 29 snd_ctl_elem_value_t *elem_data); 30 int (*allocate_elem_set_tlv)(struct elem_set_trial *trial, 31 unsigned int **tlv); 32 33 bool tlv_readable; 34}; 35 36struct chmap_entry { 37 unsigned int type; 38 unsigned int length; 39 unsigned int maps[0]; 40}; 41 42/* 43 * History of TLV feature: 44 * 45 * 2016/09/15: 398fa4db6c69 ("ALSA: control: move layout of TLV payload to UAPI 46 * header") 47 * 2012/07/21: 2d3391ec0ecc ("ALSA: PCM: channel mapping API implementation") 48 * 2011/11/20: bf1d1c9b6179 ("ALSA: tlv: add DECLARE_TLV_DB_RANGE()") 49 * 2009/07/16: 085f30654175 ("ALSA: Add new TLV types for dBwith min/max") 50 * 2006/09/06: 55a29af5ed5d ("[ALSA] Add definition of TLV dB range compound") 51 * 2006/08/28: 063a40d9111c ("Add the definition of linear volume TLV") 52 * 2006/08/28: 42750b04c5ba ("[ALSA] Control API - TLV implementation for 53 * additional information like dB scale") 54 */ 55 56/* Operations for elements in an element set with boolean type. */ 57static int add_bool_elem_set(struct elem_set_trial *trial, 58 snd_ctl_elem_info_t *info) 59{ 60 return snd_ctl_add_boolean_elem_set(trial->handle, info, 61 trial->element_count, trial->member_count); 62} 63 64static void change_bool_elem_members(struct elem_set_trial *trial, 65 snd_ctl_elem_value_t *elem_data) 66{ 67 int val; 68 unsigned int i; 69 70 for (i = 0; i < trial->member_count; ++i) { 71 val = snd_ctl_elem_value_get_boolean(elem_data, i); 72 snd_ctl_elem_value_set_boolean(elem_data, i, !val); 73 } 74} 75 76static int allocate_bool_elem_set_tlv(struct elem_set_trial *trial, 77 unsigned int **tlv) 78{ 79 /* 80 * Performs like a toggle switch for attenuation, because they're bool 81 * elements. 82 */ 83 static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(range, -10000, 0); 84 85 *tlv = malloc(sizeof(range)); 86 if (*tlv == NULL) 87 return -ENOMEM; 88 memcpy(*tlv, range, sizeof(range)); 89 90 return 0; 91} 92 93/* Operations for elements in an element set with integer type. */ 94static int add_int_elem_set(struct elem_set_trial *trial, 95 snd_ctl_elem_info_t *info) 96{ 97 return snd_ctl_add_integer_elem_set(trial->handle, info, 98 trial->element_count, trial->member_count, 99 0, 25, 1); 100} 101 102static int check_int_elem_props(struct elem_set_trial *trial, 103 snd_ctl_elem_info_t *info) 104{ 105 if (snd_ctl_elem_info_get_min(info) != 0) 106 return -EIO; 107 if (snd_ctl_elem_info_get_max(info) != 25) 108 return -EIO; 109 if (snd_ctl_elem_info_get_step(info) != 1) 110 return -EIO; 111 112 return 0; 113} 114 115static void change_int_elem_members(struct elem_set_trial *trial, 116 snd_ctl_elem_value_t *elem_data) 117{ 118 long val; 119 unsigned int i; 120 121 for (i = 0; i < trial->member_count; ++i) { 122 val = snd_ctl_elem_value_get_integer(elem_data, i); 123 snd_ctl_elem_value_set_integer(elem_data, i, ++val); 124 } 125} 126 127static int allocate_int_elem_set_tlv(struct elem_set_trial *trial, 128 unsigned int **tlv) 129{ 130 unsigned int count, pos; 131 unsigned int i, j; 132 struct chmap_entry *entry; 133 134 /* Calculate size of TLV packet for channel-mapping information. */ 135 count = 0; 136 for (i = 1; i <= 25; ++i) { 137 count += 2; /* sizeof(struct chmap_entry). */ 138 count += i; /* struct chmap_entry.maps. */ 139 } 140 141 *tlv = malloc((2 + count) * sizeof(unsigned int)); 142 if (!*tlv) 143 return -ENOMEM; 144 145 /* 146 * Emulate channel-mapping information in in-kernel implementation. 147 * Here, 25 entries are for each different channel. 148 */ 149 (*tlv)[0] = SNDRV_CTL_TLVT_CONTAINER; 150 (*tlv)[1] = count * sizeof(unsigned int); 151 pos = 2; 152 153 for (i = 1; i <= 25 && pos < count; ++i) { 154 entry = (struct chmap_entry *)&(*tlv)[pos]; 155 156 entry->type = SNDRV_CTL_TLVT_CHMAP_FIXED; 157 entry->length = i * sizeof(unsigned int); 158 pos += 2; 159 160 for (j = 0; j < i; ++j) 161 entry->maps[j] = SND_CHMAP_MONO + j; 162 pos += i; 163 } 164 165 return 0; 166} 167 168/* Operations for elements in an element set with enumerated type. */ 169static const char *const labels[] = { 170 "trusty", 171 "utopic", 172 "vivid", 173 "willy", 174 "xenial", 175}; 176 177static int add_enum_elem_set(struct elem_set_trial *trial, 178 snd_ctl_elem_info_t *info) 179{ 180 return snd_ctl_add_enumerated_elem_set(trial->handle, info, 181 trial->element_count, trial->member_count, 182 sizeof(labels) / sizeof(labels[0]), 183 labels); 184} 185 186static int check_enum_elem_props(struct elem_set_trial *trial, 187 snd_ctl_elem_info_t *info) 188{ 189 unsigned int items; 190 unsigned int i; 191 const char *label; 192 int err; 193 194 items = snd_ctl_elem_info_get_items(info); 195 if (items != sizeof(labels) / sizeof(labels[0])) 196 return -EIO; 197 198 /* Enumerate and validate all of labels registered to this element. */ 199 for (i = 0; i < items; ++i) { 200 snd_ctl_elem_info_set_item(info, i); 201 err = snd_ctl_elem_info(trial->handle, info); 202 if (err < 0) 203 return err; 204 205 label = snd_ctl_elem_info_get_item_name(info); 206 if (strncmp(label, labels[i], strlen(labels[i])) != 0) 207 return -EIO; 208 } 209 210 return 0; 211} 212 213static void change_enum_elem_members(struct elem_set_trial *trial, 214 snd_ctl_elem_value_t *elem_data) 215{ 216 unsigned int val; 217 unsigned int i; 218 219 for (i = 0; i < trial->member_count; ++i) { 220 val = snd_ctl_elem_value_get_enumerated(elem_data, i); 221 snd_ctl_elem_value_set_enumerated(elem_data, i, ++val); 222 } 223} 224 225/* Operations for elements in an element set with bytes type. */ 226static int add_bytes_elem_set(struct elem_set_trial *trial, 227 snd_ctl_elem_info_t *info) 228{ 229 return snd_ctl_add_bytes_elem_set(trial->handle, info, 230 trial->element_count, trial->member_count); 231} 232 233static void change_bytes_elem_members(struct elem_set_trial *trial, 234 snd_ctl_elem_value_t *elem_data) 235{ 236 unsigned char val; 237 unsigned int i; 238 239 for (i = 0; i < trial->member_count; ++i) { 240 val = snd_ctl_elem_value_get_byte(elem_data, i); 241 snd_ctl_elem_value_set_byte(elem_data, i, ++val); 242 } 243} 244 245static int allocate_bytes_elem_set_tlv(struct elem_set_trial *trial, 246 unsigned int **tlv) 247{ 248 /* 249 * Emulate AK4396. 250 * 20 * log10(x/255) (dB) 251 * Here, x is written value. 252 */ 253 static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(range, -4813, 0); 254 255 *tlv = malloc(sizeof(range)); 256 if (*tlv == NULL) 257 return -ENOMEM; 258 memcpy(*tlv, range, sizeof(range)); 259 260 return 0; 261} 262 263/* Operations for elements in an element set with iec958 type. */ 264static int add_iec958_elem_set(struct elem_set_trial *trial, 265 snd_ctl_elem_info_t *info) 266{ 267 int err; 268 269 snd_ctl_elem_info_get_id(info, trial->id); 270 271 err = snd_ctl_elem_add_iec958(trial->handle, trial->id); 272 if (err < 0) 273 return err; 274 275 /* 276 * In historical reason, the above API is not allowed to fill all of 277 * fields in identification data. 278 */ 279 return snd_ctl_elem_info(trial->handle, info); 280} 281 282static void change_iec958_elem_members(struct elem_set_trial *trial, 283 snd_ctl_elem_value_t *elem_data) 284{ 285 snd_aes_iec958_t data; 286 287 /* To suppress GCC warnings. */ 288 trial->element_count = 1; 289 290 snd_ctl_elem_value_get_iec958(elem_data, &data); 291 /* This is an arbitrary number. */ 292 data.pad = 10; 293 snd_ctl_elem_value_set_iec958(elem_data, &data); 294} 295 296/* Operations for elements in an element set with integer64 type. */ 297static int add_int64_elem_set(struct elem_set_trial *trial, 298 snd_ctl_elem_info_t *info) 299{ 300 return snd_ctl_add_integer64_elem_set(trial->handle, info, 301 trial->element_count, trial->member_count, 302 0, 10000, 1); 303} 304 305static int check_int64_elem_props(struct elem_set_trial *trial, 306 snd_ctl_elem_info_t *info) 307{ 308 if (snd_ctl_elem_info_get_min64(info) != 0) 309 return -EIO; 310 if (snd_ctl_elem_info_get_max64(info) != 10000) 311 return -EIO; 312 if (snd_ctl_elem_info_get_step64(info) != 1) 313 return -EIO; 314 315 return 0; 316} 317 318static void change_int64_elem_members(struct elem_set_trial *trial, 319 snd_ctl_elem_value_t *elem_data) 320{ 321 long long val; 322 unsigned int i; 323 324 for (i = 0; i < trial->member_count; ++i) { 325 val = snd_ctl_elem_value_get_integer64(elem_data, i); 326 snd_ctl_elem_value_set_integer64(elem_data, i, ++val); 327 } 328} 329 330static int allocate_int64_elem_set_tlv(struct elem_set_trial *trial, 331 unsigned int **tlv) 332{ 333 /* 334 * Use this fomula between linear/dB value: 335 * 336 * Linear: dB range (coeff) 337 * 0<-> 4: -59.40<->-56.36 (44) 338 * 4<->22: -56.36<->-45.56 (60) 339 * 22<->33: -45.56<->-40.72 (76) 340 * 33<->37: -40.72<->-38.32 (44) 341 * 37<->48: -38.32<->-29.96 (76) 342 * 48<->66: -29.96<->-22.04 (60) 343 * 66<->84: -22.04<-> -8.36 (44) 344 * 84<->95: -8.36<-> -1.76 (60) 345 * 95<->99: -1.76<-> 0.00 (76) 346 * 100<->..: 0.0 347 */ 348 static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(range, 349 0, 4, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-5940, 44, 1), 350 4, 22, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-5636, 60, 0), 351 22, 33, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-4556, 76, 0), 352 33, 37, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-4072, 44, 0), 353 37, 48, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-3832, 76, 0), 354 48, 66, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-2996, 60, 0), 355 66, 84, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-2204, 44, 0), 356 84, 95, SNDRV_CTL_TLVD_DB_SCALE_ITEM( -836, 60, 0), 357 95, 99, SNDRV_CTL_TLVD_DB_SCALE_ITEM( -176, 76, 0), 358 100, 10000, SNDRV_CTL_TLVD_DB_SCALE_ITEM(0, 0, 0), 359 ); 360 361 *tlv = malloc(sizeof(range)); 362 if (*tlv == NULL) 363 return -ENOMEM; 364 memcpy(*tlv, range, sizeof(range)); 365 366 return 0; 367} 368 369/* Common operations. */ 370static int add_elem_set(struct elem_set_trial *trial) 371{ 372 snd_ctl_elem_info_t *info; 373 char name[64] = {0}; 374 int err; 375 376 snprintf(name, 64, "userspace-control-element-%s", 377 snd_ctl_elem_type_name(trial->type)); 378 379 snd_ctl_elem_info_alloca(&info); 380 snd_ctl_elem_info_set_interface(info, SND_CTL_ELEM_IFACE_MIXER); 381 snd_ctl_elem_info_set_name(info, name); 382 383 err = trial->add_elem_set(trial, info); 384 if (err >= 0) 385 snd_ctl_elem_info_get_id(info, trial->id); 386 387 return err; 388} 389 390static int check_event(struct elem_set_trial *trial, unsigned int mask, 391 unsigned int expected_count) 392{ 393 struct pollfd pfds; 394 int count; 395 unsigned short revents; 396 snd_ctl_event_t *event; 397 int err; 398 399 snd_ctl_event_alloca(&event); 400 401 if (snd_ctl_poll_descriptors_count(trial->handle) != 1) 402 return -ENXIO; 403 404 if (snd_ctl_poll_descriptors(trial->handle, &pfds, 1) != 1) 405 return -ENXIO; 406 407 while (expected_count > 0) { 408 count = poll(&pfds, 1, 1000); 409 if (count < 0) 410 return errno; 411 /* Some events are already supplied. */ 412 if (count == 0) 413 return -ETIMEDOUT; 414 415 err = snd_ctl_poll_descriptors_revents(trial->handle, &pfds, 416 count, &revents); 417 if (err < 0) 418 return err; 419 if (revents & POLLERR) 420 return -EIO; 421 if (!(revents & POLLIN)) 422 continue; 423 424 err = snd_ctl_read(trial->handle, event); 425 if (err < 0) 426 return err; 427 if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM) 428 continue; 429 /* 430 * I expect each event is generated separately to the same 431 * element or several events are generated at once. 432 */ 433 if ((snd_ctl_event_elem_get_mask(event) & mask) != mask) 434 continue; 435 --expected_count; 436 } 437 438 if (expected_count != 0) 439 return -EIO; 440 441 return 0; 442} 443 444static int check_elem_list(struct elem_set_trial *trial) 445{ 446 snd_ctl_elem_list_t *list; 447 snd_ctl_elem_id_t *id; 448 int e; 449 unsigned int i; 450 int err; 451 452 snd_ctl_elem_list_alloca(&list); 453 snd_ctl_elem_id_alloca(&id); 454 455 err = snd_ctl_elem_list(trial->handle, list); 456 if (err < 0) 457 return err; 458 459 /* Certainly some elements are already added. */ 460 if (snd_ctl_elem_list_get_count(list) == 0) 461 return -EIO; 462 463 err = snd_ctl_elem_list_alloc_space(list, 464 snd_ctl_elem_list_get_count(list)); 465 if (err < 0) 466 return err; 467 468 err = snd_ctl_elem_list(trial->handle, list); 469 if (err < 0) 470 goto end; 471 472 if (trial->element_count > snd_ctl_elem_list_get_count(list)) { 473 err = -EIO; 474 goto end; 475 } 476 477 i = 0; 478 for (e = 0; e < snd_ctl_elem_list_get_count(list); ++e) { 479 snd_ctl_elem_list_get_id(list, e, id); 480 481 if (strcmp(snd_ctl_elem_id_get_name(id), 482 snd_ctl_elem_id_get_name(trial->id)) != 0) 483 continue; 484 if (snd_ctl_elem_id_get_interface(id) != 485 snd_ctl_elem_id_get_interface(trial->id)) 486 continue; 487 if (snd_ctl_elem_id_get_device(id) != 488 snd_ctl_elem_id_get_device(trial->id)) 489 continue; 490 if (snd_ctl_elem_id_get_subdevice(id) != 491 snd_ctl_elem_id_get_subdevice(trial->id)) 492 continue; 493 494 /* 495 * Here, I expect the list includes element ID data in numerical 496 * order. Actually, it does. 497 */ 498 if (snd_ctl_elem_id_get_numid(id) != 499 snd_ctl_elem_id_get_numid(trial->id) + i) 500 continue; 501 if (snd_ctl_elem_id_get_index(id) != 502 snd_ctl_elem_id_get_index(trial->id) + i) 503 continue; 504 505 ++i; 506 } 507 508 if (i != trial->element_count) 509 err = -EIO; 510end: 511 snd_ctl_elem_list_free_space(list); 512 513 return err; 514} 515 516static int check_elem_set_props(struct elem_set_trial *trial) 517{ 518 snd_ctl_elem_id_t *id; 519 snd_ctl_elem_info_t *info; 520 unsigned int numid; 521 unsigned int index; 522 unsigned int i; 523 unsigned int j; 524 int err; 525 526 snd_ctl_elem_id_alloca(&id); 527 snd_ctl_elem_info_alloca(&info); 528 529 snd_ctl_elem_info_set_id(info, trial->id); 530 numid = snd_ctl_elem_id_get_numid(trial->id); 531 index = snd_ctl_elem_id_get_index(trial->id); 532 533 for (i = 0; i < trial->element_count; ++i) { 534 snd_ctl_elem_info_set_index(info, index + i); 535 536 /* 537 * In Linux 4.0 or former, ioctl(SNDRV_CTL_IOCTL_ELEM_ADD) 538 * doesn't fill all of fields for identification. 539 */ 540 if (numid > 0) 541 snd_ctl_elem_info_set_numid(info, numid + i); 542 543 err = snd_ctl_elem_info(trial->handle, info); 544 if (err < 0) 545 return err; 546 547 /* Check some common properties. */ 548 if (snd_ctl_elem_info_get_type(info) != trial->type) 549 return -EIO; 550 if (snd_ctl_elem_info_get_count(info) != trial->member_count) 551 return -EIO; 552 553 /* 554 * In a case of IPC, this is the others. But in this case, 555 * it's myself. 556 */ 557 if (snd_ctl_elem_info_get_owner(info) != getpid()) 558 return -EIO; 559 560 /* 561 * Just adding an element set by userspace applications, 562 * included elements are initially locked. 563 */ 564 if (!snd_ctl_elem_info_is_locked(info)) 565 return -EIO; 566 567 /* 568 * In initial state, any application can register TLV data for 569 * user-defined element set except for IEC 958 type, thus 570 * elements in any user-defined set should allow any write 571 * operation. 572 */ 573 if (trial->type != SND_CTL_ELEM_TYPE_IEC958 && 574 !snd_ctl_elem_info_is_tlv_writable(info)) 575 return -EIO; 576 577 /* Check type-specific properties. */ 578 if (trial->check_elem_props != NULL) { 579 err = trial->check_elem_props(trial, info); 580 if (err < 0) 581 return err; 582 } 583 584 snd_ctl_elem_info_get_id(info, id); 585 err = snd_ctl_elem_unlock(trial->handle, id); 586 if (err < 0) 587 return err; 588 589 /* 590 * Till kernel v4.14, ALSA control core allows elements in any 591 * user-defined set to have TLV_READ flag even if they have no 592 * TLV data in their initial state. In this case, any read 593 * operation for TLV data should return -ENXIO. 594 */ 595 if (snd_ctl_elem_info_is_tlv_readable(info)) { 596 unsigned int data[32]; 597 err = snd_ctl_elem_tlv_read(trial->handle, trial->id, 598 data, sizeof(data)); 599 if (err >= 0) 600 return -EIO; 601 if (err != -ENXIO) 602 return err; 603 604 trial->tlv_readable = true; 605 } 606 607 } 608 609 return 0; 610} 611 612static int check_elems(struct elem_set_trial *trial) 613{ 614 snd_ctl_elem_value_t *data; 615 unsigned int numid; 616 unsigned int index; 617 unsigned int i; 618 int err; 619 620 snd_ctl_elem_value_alloca(&data); 621 622 snd_ctl_elem_value_set_id(data, trial->id); 623 numid = snd_ctl_elem_id_get_numid(trial->id); 624 index = snd_ctl_elem_id_get_index(trial->id); 625 626 for (i = 0; i < trial->element_count; ++i) { 627 snd_ctl_elem_value_set_index(data, index + i); 628 629 /* 630 * In Linux 4.0 or former, ioctl(SNDRV_CTL_IOCTL_ELEM_ADD) 631 * doesn't fill all of fields for identification. 632 */ 633 if (numid > 0) 634 snd_ctl_elem_value_set_numid(data, numid + i); 635 636 err = snd_ctl_elem_read(trial->handle, data); 637 if (err < 0) 638 return err; 639 640 /* Change members of an element in this element set. */ 641 trial->change_elem_members(trial, data); 642 643 err = snd_ctl_elem_write(trial->handle, data); 644 if (err < 0) 645 return err; 646 } 647 648 return 0; 649} 650 651static int check_tlv(struct elem_set_trial *trial) 652{ 653 unsigned int *tlv; 654 int mask; 655 unsigned int count; 656 unsigned int len; 657 unsigned int *curr; 658 int err; 659 660 err = trial->allocate_elem_set_tlv(trial, &tlv); 661 if (err < 0) 662 return err; 663 664 len = tlv[SNDRV_CTL_TLVO_LEN] + sizeof(unsigned int) * 2; 665 curr = malloc(len); 666 if (curr == NULL) { 667 free(tlv); 668 return -ENOMEM; 669 } 670 671 /* 672 * In in-kernel implementation, write and command operations are the 673 * same for an element set added by userspace applications. Here, I 674 * use write. 675 */ 676 err = snd_ctl_elem_tlv_write(trial->handle, trial->id, 677 (const unsigned int *)tlv); 678 if (err < 0) 679 goto end; 680 681 /* 682 * Since kernel v4.14, any write operation to an element in user-defined 683 * set can change state of the other elements in the same set. In this 684 * case, any TLV data is firstly available after the operation. 685 */ 686 if (!trial->tlv_readable) { 687 mask = SND_CTL_EVENT_MASK_INFO | SND_CTL_EVENT_MASK_TLV; 688 count = trial->element_count; 689 } else { 690 mask = SND_CTL_EVENT_MASK_TLV; 691 count = 1; 692 } 693 err = check_event(trial, mask, count); 694 if (err < 0) 695 goto end; 696 if (!trial->tlv_readable) { 697 snd_ctl_elem_info_t *info; 698 snd_ctl_elem_info_alloca(&info); 699 700 snd_ctl_elem_info_set_id(info, trial->id); 701 err = snd_ctl_elem_info(trial->handle, info); 702 if (err < 0) 703 return err; 704 if (!snd_ctl_elem_info_is_tlv_readable(info)) 705 return -EIO; 706 707 /* Now TLV data is available for this element set. */ 708 trial->tlv_readable = true; 709 } 710 711 err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr, len); 712 if (err < 0) 713 goto end; 714 715 if (memcmp(curr, tlv, len) != 0) 716 err = -EIO; 717end: 718 free(tlv); 719 free(curr); 720 return 0; 721} 722 723int main(void) 724{ 725 struct elem_set_trial trial = {0}; 726 unsigned int i; 727 int err; 728 729 snd_ctl_elem_id_alloca(&trial.id); 730 731 err = snd_ctl_open(&trial.handle, "hw:0", 0); 732 if (err < 0) 733 return EXIT_FAILURE; 734 735 err = snd_ctl_subscribe_events(trial.handle, 1); 736 if (err < 0) 737 return EXIT_FAILURE; 738 739 /* Test all of types. */ 740 for (i = 0; i < SND_CTL_ELEM_TYPE_LAST; ++i) { 741 trial.type = i + 1; 742 743 /* Assign type-dependent operations. */ 744 switch (trial.type) { 745 case SND_CTL_ELEM_TYPE_BOOLEAN: 746 trial.element_count = 900; 747 trial.member_count = 128; 748 trial.add_elem_set = add_bool_elem_set; 749 trial.check_elem_props = NULL; 750 trial.change_elem_members = change_bool_elem_members; 751 trial.allocate_elem_set_tlv = 752 allocate_bool_elem_set_tlv; 753 trial.tlv_readable = false; 754 break; 755 case SND_CTL_ELEM_TYPE_INTEGER: 756 trial.element_count = 900; 757 trial.member_count = 128; 758 trial.add_elem_set = add_int_elem_set; 759 trial.check_elem_props = check_int_elem_props; 760 trial.change_elem_members = change_int_elem_members; 761 trial.allocate_elem_set_tlv = 762 allocate_int_elem_set_tlv; 763 trial.tlv_readable = false; 764 break; 765 case SND_CTL_ELEM_TYPE_ENUMERATED: 766 trial.element_count = 900; 767 trial.member_count = 128; 768 trial.add_elem_set = add_enum_elem_set; 769 trial.check_elem_props = check_enum_elem_props; 770 trial.change_elem_members = change_enum_elem_members; 771 trial.allocate_elem_set_tlv = NULL; 772 trial.tlv_readable = false; 773 break; 774 case SND_CTL_ELEM_TYPE_BYTES: 775 trial.element_count = 900; 776 trial.member_count = 512; 777 trial.add_elem_set = add_bytes_elem_set; 778 trial.check_elem_props = NULL; 779 trial.change_elem_members = change_bytes_elem_members; 780 trial.allocate_elem_set_tlv = 781 allocate_bytes_elem_set_tlv; 782 trial.tlv_readable = false; 783 break; 784 case SND_CTL_ELEM_TYPE_IEC958: 785 trial.element_count = 1; 786 trial.member_count = 1; 787 trial.add_elem_set = add_iec958_elem_set; 788 trial.check_elem_props = NULL; 789 trial.change_elem_members = change_iec958_elem_members; 790 trial.allocate_elem_set_tlv = NULL; 791 trial.tlv_readable = false; 792 break; 793 case SND_CTL_ELEM_TYPE_INTEGER64: 794 default: 795 trial.element_count = 900; 796 trial.member_count = 64; 797 trial.add_elem_set = add_int64_elem_set; 798 trial.check_elem_props = check_int64_elem_props; 799 trial.change_elem_members = change_int64_elem_members; 800 trial.allocate_elem_set_tlv = 801 allocate_int64_elem_set_tlv; 802 trial.tlv_readable = false; 803 break; 804 } 805 806 /* Test an operation to add an element set. */ 807 err = add_elem_set(&trial); 808 if (err < 0) { 809 printf("Fail to add an element set with %s type.\n", 810 snd_ctl_elem_type_name(trial.type)); 811 break; 812 } 813 err = check_event(&trial, SND_CTL_EVENT_MASK_ADD, 814 trial.element_count); 815 if (err < 0) { 816 printf("Fail to check some events to add elements with " 817 "%s type.\n", 818 snd_ctl_elem_type_name(trial.type)); 819 break; 820 } 821 822 /* Check added elements are retrieved in a list. */ 823 err = check_elem_list(&trial); 824 if (err < 0) { 825 printf("Fail to list each element with %s type.\n", 826 snd_ctl_elem_type_name(trial.type)); 827 break; 828 } 829 830 /* Check properties of each element in this element set. */ 831 err = check_elem_set_props(&trial); 832 if (err < 0) { 833 printf("Fail to check properties of each element with " 834 "%s type.\n", 835 snd_ctl_elem_type_name(trial.type)); 836 break; 837 } 838 839 /* 840 * Test operations to change the state of members in each 841 * element in the element set. 842 */ 843 err = check_elems(&trial); 844 if (err < 0) { 845 printf("Fail to change status of each element with %s " 846 "type.\n", 847 snd_ctl_elem_type_name(trial.type)); 848 break; 849 } 850 err = check_event(&trial, SND_CTL_EVENT_MASK_VALUE, 851 trial.element_count); 852 if (err < 0) { 853 printf("Fail to check some events to change status of " 854 "each elements with %s type.\n", 855 snd_ctl_elem_type_name(trial.type)); 856 break; 857 } 858 859 /* 860 * Test an operation to change TLV data of this element set, 861 * except for enumerated and IEC958 type. 862 */ 863 if (trial.allocate_elem_set_tlv != NULL) { 864 err = check_tlv(&trial); 865 if (err < 0) { 866 printf("Fail to change TLV data of an element " 867 "set with %s type.\n", 868 snd_ctl_elem_type_name(trial.type)); 869 break; 870 } 871 } 872 873 /* Test an operation to remove elements in this element set. */ 874 err = snd_ctl_elem_remove(trial.handle, trial.id); 875 if (err < 0) { 876 printf("Fail to remove elements with %s type.\n", 877 snd_ctl_elem_type_name(trial.type)); 878 break; 879 } 880 err = check_event(&trial, SND_CTL_EVENT_MASK_REMOVE, 881 trial.element_count); 882 if (err < 0) { 883 printf("Fail to check some events to remove each " 884 "element with %s type.\n", 885 snd_ctl_elem_type_name(trial.type)); 886 break; 887 } 888 } 889 890 if (err < 0) { 891 printf("%s\n", snd_strerror(err)); 892 893 /* To ensure. */ 894 snd_ctl_elem_remove(trial.handle, trial.id); 895 return EXIT_FAILURE; 896 } 897 898 return EXIT_SUCCESS; 899} 900