diff options
| author | Takashi Iwai <tiwai@suse.de> | 2016-01-11 08:39:12 -0500 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2016-01-29 01:36:10 -0500 |
| commit | e2703363316278cd4a8880671d38f783f7de18ba (patch) | |
| tree | 84649bbdd9e0de9d853888cb464fcf6871b730ef /sound/usb/card.c | |
| parent | 79289e24194a9d099bf18f200894832c5760cd83 (diff) | |
ALSA: usb-audio: Add quirk_alias option
This patch adds a new option "quirk_alias" to snd-usb-audio driver for
allowing user to pass the quirk alias list. A quirk alias consists of
a string form like 0123abcd:5678beef, which makes to apply a quirk to
a device with USB ID 0123:abcd treated as if it were 5678:beef.
This feature is useful to test an existing quirk, typically for a
newer model of the same vendor, without patching / rebuilding the
kernel driver.
The current implementation is fairly simplistic: since there is no API
for matching a usb_device_id to the given ID pair, it has an open code
to loop over the id table and matches only with vendor:product pair.
So far, this is OK, as all existing entries are with vendor:product
pairs, indeed. Once when we have another matching entry, however,
we'd need to update get_alias_quirk() as well.
Note that this option is provided only for testing / development. If
you want to have a proper support, contact to upstream for adding the
matching quirk in the driver code statically.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/card.c')
| -rw-r--r-- | sound/usb/card.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index 2c0269014b85..3fc63583a537 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
| @@ -82,6 +82,7 @@ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; | |||
| 82 | static int device_setup[SNDRV_CARDS]; /* device parameter for this card */ | 82 | static int device_setup[SNDRV_CARDS]; /* device parameter for this card */ |
| 83 | static bool ignore_ctl_error; | 83 | static bool ignore_ctl_error; |
| 84 | static bool autoclock = true; | 84 | static bool autoclock = true; |
| 85 | static char *quirk_alias[SNDRV_CARDS]; | ||
| 85 | 86 | ||
| 86 | module_param_array(index, int, NULL, 0444); | 87 | module_param_array(index, int, NULL, 0444); |
| 87 | MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); | 88 | MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); |
| @@ -100,6 +101,8 @@ MODULE_PARM_DESC(ignore_ctl_error, | |||
| 100 | "Ignore errors from USB controller for mixer interfaces."); | 101 | "Ignore errors from USB controller for mixer interfaces."); |
| 101 | module_param(autoclock, bool, 0444); | 102 | module_param(autoclock, bool, 0444); |
| 102 | MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes)."); | 103 | MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes)."); |
| 104 | module_param_array(quirk_alias, charp, NULL, 0444); | ||
| 105 | MODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef."); | ||
| 103 | 106 | ||
| 104 | /* | 107 | /* |
| 105 | * we keep the snd_usb_audio_t instances by ourselves for merging | 108 | * we keep the snd_usb_audio_t instances by ourselves for merging |
| @@ -457,6 +460,48 @@ static int snd_usb_audio_create(struct usb_interface *intf, | |||
| 457 | return 0; | 460 | return 0; |
| 458 | } | 461 | } |
| 459 | 462 | ||
| 463 | /* look for a matching quirk alias id */ | ||
| 464 | static bool get_alias_id(struct usb_device *dev, unsigned int *id) | ||
| 465 | { | ||
| 466 | int i; | ||
| 467 | unsigned int src, dst; | ||
| 468 | |||
| 469 | for (i = 0; i < ARRAY_SIZE(quirk_alias); i++) { | ||
| 470 | if (!quirk_alias[i] || | ||
| 471 | sscanf(quirk_alias[i], "%x:%x", &src, &dst) != 2 || | ||
| 472 | src != *id) | ||
| 473 | continue; | ||
| 474 | dev_info(&dev->dev, | ||
| 475 | "device (%04x:%04x): applying quirk alias %04x:%04x\n", | ||
| 476 | USB_ID_VENDOR(*id), USB_ID_PRODUCT(*id), | ||
| 477 | USB_ID_VENDOR(dst), USB_ID_PRODUCT(dst)); | ||
| 478 | *id = dst; | ||
| 479 | return true; | ||
| 480 | } | ||
| 481 | |||
| 482 | return false; | ||
| 483 | } | ||
| 484 | |||
| 485 | static struct usb_device_id usb_audio_ids[]; /* defined below */ | ||
| 486 | |||
| 487 | /* look for the corresponding quirk */ | ||
| 488 | static const struct snd_usb_audio_quirk * | ||
| 489 | get_alias_quirk(struct usb_device *dev, unsigned int id) | ||
| 490 | { | ||
| 491 | const struct usb_device_id *p; | ||
| 492 | |||
| 493 | for (p = usb_audio_ids; p->match_flags; p++) { | ||
| 494 | /* FIXME: this checks only vendor:product pair in the list */ | ||
| 495 | if ((p->match_flags & USB_DEVICE_ID_MATCH_DEVICE) == | ||
| 496 | USB_DEVICE_ID_MATCH_DEVICE && | ||
| 497 | p->idVendor == USB_ID_VENDOR(id) && | ||
| 498 | p->idProduct == USB_ID_PRODUCT(id)) | ||
| 499 | return (const struct snd_usb_audio_quirk *)p->driver_info; | ||
| 500 | } | ||
| 501 | |||
| 502 | return NULL; | ||
| 503 | } | ||
| 504 | |||
| 460 | /* | 505 | /* |
| 461 | * probe the active usb device | 506 | * probe the active usb device |
| 462 | * | 507 | * |
| @@ -483,6 +528,8 @@ static int usb_audio_probe(struct usb_interface *intf, | |||
| 483 | ifnum = get_iface_desc(alts)->bInterfaceNumber; | 528 | ifnum = get_iface_desc(alts)->bInterfaceNumber; |
| 484 | id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | 529 | id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), |
| 485 | le16_to_cpu(dev->descriptor.idProduct)); | 530 | le16_to_cpu(dev->descriptor.idProduct)); |
| 531 | if (get_alias_id(dev, &id)) | ||
| 532 | quirk = get_alias_quirk(dev, id); | ||
| 486 | if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) | 533 | if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) |
| 487 | return -ENXIO; | 534 | return -ENXIO; |
| 488 | 535 | ||
