summaryrefslogtreecommitdiffstats
path: root/sound/usb/card.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2016-01-11 08:39:12 -0500
committerTakashi Iwai <tiwai@suse.de>2016-01-29 01:36:10 -0500
commite2703363316278cd4a8880671d38f783f7de18ba (patch)
tree84649bbdd9e0de9d853888cb464fcf6871b730ef /sound/usb/card.c
parent79289e24194a9d099bf18f200894832c5760cd83 (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.c47
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 };
82static int device_setup[SNDRV_CARDS]; /* device parameter for this card */ 82static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
83static bool ignore_ctl_error; 83static bool ignore_ctl_error;
84static bool autoclock = true; 84static bool autoclock = true;
85static char *quirk_alias[SNDRV_CARDS];
85 86
86module_param_array(index, int, NULL, 0444); 87module_param_array(index, int, NULL, 0444);
87MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); 88MODULE_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.");
101module_param(autoclock, bool, 0444); 102module_param(autoclock, bool, 0444);
102MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes)."); 103MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes).");
104module_param_array(quirk_alias, charp, NULL, 0444);
105MODULE_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 */
464static 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
485static struct usb_device_id usb_audio_ids[]; /* defined below */
486
487/* look for the corresponding quirk */
488static const struct snd_usb_audio_quirk *
489get_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