Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ALSA: usb-audio: improve module param quirk_flags

It accepts strings like `VID:PID:quirk_flag_name1|quirk_flag_name2;...`
from now on, so that we can use it to debug USB audio devices more
intuitive and flexible. The compatibility of previous form is kept.

Co-developed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Cryolitia PukNgae <cryolitia@uniontech.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Cryolitia PukNgae and committed by
Takashi Iwai
ffd58612 ce017262

+118 -8
+26 -6
sound/usb/card.c
··· 73 73 static char *quirk_alias[SNDRV_CARDS]; 74 74 static char *delayed_register[SNDRV_CARDS]; 75 75 static bool implicit_fb[SNDRV_CARDS]; 76 - static unsigned int quirk_flags[SNDRV_CARDS]; 76 + static char *quirk_flags[SNDRV_CARDS]; 77 77 78 78 bool snd_usb_use_vmalloc = true; 79 79 bool snd_usb_skip_validation; ··· 103 103 MODULE_PARM_DESC(delayed_register, "Quirk for delayed registration, given by id:iface, e.g. 0123abcd:4."); 104 104 module_param_array(implicit_fb, bool, NULL, 0444); 105 105 MODULE_PARM_DESC(implicit_fb, "Apply generic implicit feedback sync mode."); 106 - module_param_array(quirk_flags, uint, NULL, 0444); 106 + module_param_array(quirk_flags, charp, NULL, 0444); 107 107 MODULE_PARM_DESC(quirk_flags, "Driver quirk bit flags."); 108 108 module_param_named(use_vmalloc, snd_usb_use_vmalloc, bool, 0444); 109 109 MODULE_PARM_DESC(use_vmalloc, "Use vmalloc for PCM intermediate buffers (default: yes)."); ··· 692 692 } 693 693 } 694 694 695 + static void snd_usb_init_quirk_flags(int idx, struct snd_usb_audio *chip) 696 + { 697 + size_t i; 698 + 699 + /* old style option found: the position-based integer value */ 700 + if (quirk_flags[idx] && 701 + !kstrtou32(quirk_flags[idx], 0, &chip->quirk_flags)) { 702 + snd_usb_apply_flag_dbg("module param", chip, chip->quirk_flags); 703 + return; 704 + } 705 + 706 + /* take the default quirk from the quirk table */ 707 + snd_usb_init_quirk_flags_table(chip); 708 + 709 + /* add or correct quirk bits from options */ 710 + for (i = 0; i < ARRAY_SIZE(quirk_flags); i++) { 711 + if (!quirk_flags[i] || !*quirk_flags[i]) 712 + break; 713 + 714 + snd_usb_init_quirk_flags_parse_string(chip, quirk_flags[i]); 715 + } 716 + } 717 + 695 718 /* 696 719 * create a chip instance and set its names. 697 720 */ ··· 773 750 INIT_LIST_HEAD(&chip->midi_v2_list); 774 751 INIT_LIST_HEAD(&chip->mixer_list); 775 752 776 - if (quirk_flags[idx]) 777 - chip->quirk_flags = quirk_flags[idx]; 778 - else 779 - snd_usb_init_quirk_flags(chip); 753 + snd_usb_init_quirk_flags(idx, chip); 780 754 781 755 card->private_free = snd_usb_audio_free; 782 756
+89 -1
sound/usb/quirks.c
··· 2521 2521 } 2522 2522 } 2523 2523 2524 - void snd_usb_init_quirk_flags(struct snd_usb_audio *chip) 2524 + void snd_usb_init_quirk_flags_table(struct snd_usb_audio *chip) 2525 2525 { 2526 2526 const struct usb_audio_quirk_flags_table *p; 2527 2527 ··· 2533 2533 chip->quirk_flags |= p->flags; 2534 2534 return; 2535 2535 } 2536 + } 2537 + } 2538 + 2539 + void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip, 2540 + const char *str) 2541 + { 2542 + u16 chip_vid = USB_ID_VENDOR(chip->usb_id); 2543 + u16 chip_pid = USB_ID_PRODUCT(chip->usb_id); 2544 + u32 mask_flags, unmask_flags, bit; 2545 + char *p, *field, *flag; 2546 + bool is_unmask; 2547 + u16 vid, pid; 2548 + 2549 + char *val __free(kfree) = kstrdup(str, GFP_KERNEL); 2550 + 2551 + if (!val) 2552 + return; 2553 + 2554 + for (p = val; p && *p;) { 2555 + /* Each entry consists of VID:PID:flags */ 2556 + field = strsep(&p, ":"); 2557 + if (!field) 2558 + break; 2559 + 2560 + if (strcmp(field, "*") == 0) 2561 + vid = 0; 2562 + else if (kstrtou16(field, 16, &vid)) 2563 + break; 2564 + 2565 + field = strsep(&p, ":"); 2566 + if (!field) 2567 + break; 2568 + 2569 + if (strcmp(field, "*") == 0) 2570 + pid = 0; 2571 + else if (kstrtou16(field, 16, &pid)) 2572 + break; 2573 + 2574 + field = strsep(&p, ";"); 2575 + if (!field || !*field) 2576 + break; 2577 + 2578 + if ((vid != 0 && vid != chip_vid) || 2579 + (pid != 0 && pid != chip_pid)) 2580 + continue; 2581 + 2582 + /* Collect the flags */ 2583 + mask_flags = 0; 2584 + unmask_flags = 0; 2585 + while (field && *field) { 2586 + flag = strsep(&field, "|"); 2587 + 2588 + if (!flag) 2589 + break; 2590 + 2591 + if (*flag == '!') { 2592 + is_unmask = true; 2593 + flag++; 2594 + } else { 2595 + is_unmask = false; 2596 + } 2597 + 2598 + if (!kstrtou32(flag, 16, &bit)) { 2599 + if (is_unmask) 2600 + unmask_flags |= bit; 2601 + else 2602 + mask_flags |= bit; 2603 + 2604 + break; 2605 + } 2606 + 2607 + bit = snd_usb_quirk_flags_from_name(flag); 2608 + 2609 + if (bit) { 2610 + if (is_unmask) 2611 + unmask_flags |= bit; 2612 + else 2613 + mask_flags |= bit; 2614 + } else { 2615 + pr_warn("snd_usb_audio: unknown flag %s while parsing param quirk_flags\n", 2616 + flag); 2617 + } 2618 + } 2619 + 2620 + chip->quirk_flags &= ~unmask_flags; 2621 + chip->quirk_flags |= mask_flags; 2622 + snd_usb_apply_flag_dbg("module param", chip, 2623 + chip->quirk_flags); 2536 2624 } 2537 2625 }
+3 -1
sound/usb/quirks.h
··· 52 52 struct snd_usb_audio *chip, 53 53 unsigned long flag); 54 54 55 - void snd_usb_init_quirk_flags(struct snd_usb_audio *chip); 55 + void snd_usb_init_quirk_flags_table(struct snd_usb_audio *chip); 56 + void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip, 57 + const char *str); 56 58 57 59 const char *snd_usb_quirk_flag_find_name(unsigned long flag); 58 60 u32 snd_usb_quirk_flags_from_name(const char *name);