diff options
-rw-r--r-- | Documentation/sound/alsa/timestamping.txt | 2 | ||||
-rw-r--r-- | include/sound/hda_chmap.h | 2 | ||||
-rw-r--r-- | include/sound/hda_i915.h | 10 | ||||
-rw-r--r-- | sound/firewire/Kconfig | 1 | ||||
-rw-r--r-- | sound/firewire/amdtp-stream.c | 4 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.c | 217 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.h | 5 | ||||
-rw-r--r-- | sound/firewire/dice/dice.c | 34 | ||||
-rw-r--r-- | sound/firewire/digi00x/digi00x-transaction.c | 7 | ||||
-rw-r--r-- | sound/firewire/digi00x/digi00x.c | 107 | ||||
-rw-r--r-- | sound/firewire/digi00x/digi00x.h | 3 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.c | 168 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.h | 3 | ||||
-rw-r--r-- | sound/firewire/lib.c | 32 | ||||
-rw-r--r-- | sound/firewire/lib.h | 3 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw.c | 151 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw.h | 4 | ||||
-rw-r--r-- | sound/hda/hdac_i915.c | 62 | ||||
-rw-r--r-- | sound/hda/hdmi_chmap.c | 44 | ||||
-rw-r--r-- | sound/pci/ctxfi/cttimer.c | 6 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 386 | ||||
-rw-r--r-- | sound/pci/intel8x0.c | 20 | ||||
-rw-r--r-- | sound/usb/mixer.c | 78 | ||||
-rw-r--r-- | sound/usb/quirks.c | 1 |
24 files changed, 929 insertions, 421 deletions
diff --git a/Documentation/sound/alsa/timestamping.txt b/Documentation/sound/alsa/timestamping.txt index 0b191a23f534..1b6473f393a8 100644 --- a/Documentation/sound/alsa/timestamping.txt +++ b/Documentation/sound/alsa/timestamping.txt @@ -129,7 +129,7 @@ will be required to issue multiple queries and perform an interpolation of the results In some hardware-specific configuration, the system timestamp is -latched by a low-level audio subsytem, and the information provided +latched by a low-level audio subsystem, and the information provided back to the driver. Due to potential delays in the communication with the hardware, there is a risk of misalignment with the avail and delay information. To make sure applications are not confused, a diff --git a/include/sound/hda_chmap.h b/include/sound/hda_chmap.h index e20d219a0304..babd445c7505 100644 --- a/include/sound/hda_chmap.h +++ b/include/sound/hda_chmap.h @@ -36,6 +36,8 @@ struct hdac_chmap_ops { int (*chmap_validate)(struct hdac_chmap *hchmap, int ca, int channels, unsigned char *chmap); + int (*get_spk_alloc)(struct hdac_device *hdac, int pcm_idx); + void (*get_chmap)(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap); void (*set_chmap)(struct hdac_device *hdac, int pcm_idx, diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h index fa341fcb5829..eed87a7559b7 100644 --- a/include/sound/hda_i915.h +++ b/include/sound/hda_i915.h @@ -10,8 +10,8 @@ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); int snd_hdac_display_power(struct hdac_bus *bus, bool enable); int snd_hdac_get_display_clk(struct hdac_bus *bus); -int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate); -int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate); +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, bool *audio_enabled, char *buffer, int max_bytes); int snd_hdac_i915_init(struct hdac_bus *bus); int snd_hdac_i915_exit(struct hdac_bus *bus); @@ -29,12 +29,12 @@ static inline int snd_hdac_get_display_clk(struct hdac_bus *bus) { return 0; } -static inline int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, - int rate) +static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec, + hda_nid_t nid, int rate) { return 0; } -static inline int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, +static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, bool *audio_enabled, char *buffer, int max_bytes) { diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 2a779c2f63ab..ab894ed1ff67 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -134,6 +134,7 @@ config SND_FIREWIRE_TASCAM Say Y here to include support for TASCAM. * FW-1884 * FW-1082 + * FW-1804 To compile this driver as a module, choose M here: the module will be called snd-firewire-tascam. diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index ed2902609a4c..4484242da0e6 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -102,6 +102,10 @@ EXPORT_SYMBOL(amdtp_stream_init); */ void amdtp_stream_destroy(struct amdtp_stream *s) { + /* Not initialized. */ + if (s->protocol == NULL) + return; + WARN_ON(amdtp_stream_running(s)); kfree(s->protocol); mutex_destroy(&s->mutex); diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 3e4e0756e3fe..f7e2cbd2a313 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -67,7 +67,7 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS); #define MODEL_MAUDIO_PROJECTMIX 0x00010091 static int -name_device(struct snd_bebob *bebob, unsigned int vendor_id) +name_device(struct snd_bebob *bebob) { struct fw_device *fw_dev = fw_parent_device(bebob->unit); char vendor[24] = {0}; @@ -126,6 +126,17 @@ end: return err; } +static void bebob_free(struct snd_bebob *bebob) +{ + snd_bebob_stream_destroy_duplex(bebob); + fw_unit_put(bebob->unit); + + kfree(bebob->maudio_special_quirk); + + mutex_destroy(&bebob->mutex); + kfree(bebob); +} + /* * This module releases the FireWire unit data after all ALSA character devices * are released by applications. This is for releasing stream data or finishing @@ -137,18 +148,11 @@ bebob_card_free(struct snd_card *card) { struct snd_bebob *bebob = card->private_data; - snd_bebob_stream_destroy_duplex(bebob); - fw_unit_put(bebob->unit); - - kfree(bebob->maudio_special_quirk); - - if (bebob->card_index >= 0) { - mutex_lock(&devices_mutex); - clear_bit(bebob->card_index, devices_used); - mutex_unlock(&devices_mutex); - } + mutex_lock(&devices_mutex); + clear_bit(bebob->card_index, devices_used); + mutex_unlock(&devices_mutex); - mutex_destroy(&bebob->mutex); + bebob_free(card->private_data); } static const struct snd_bebob_spec * @@ -176,16 +180,17 @@ check_audiophile_booted(struct fw_unit *unit) return strncmp(name, "FW Audiophile Bootloader", 15) != 0; } -static int -bebob_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) +static void +do_registration(struct work_struct *work) { - struct snd_card *card; - struct snd_bebob *bebob; - const struct snd_bebob_spec *spec; + struct snd_bebob *bebob = + container_of(work, struct snd_bebob, dwork.work); unsigned int card_index; int err; + if (bebob->registered) + return; + mutex_lock(&devices_mutex); for (card_index = 0; card_index < SNDRV_CARDS; card_index++) { @@ -193,64 +198,39 @@ bebob_probe(struct fw_unit *unit, break; } if (card_index >= SNDRV_CARDS) { - err = -ENOENT; - goto end; + mutex_unlock(&devices_mutex); + return; } - if ((entry->vendor_id == VEN_FOCUSRITE) && - (entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH)) - spec = get_saffire_spec(unit); - else if ((entry->vendor_id == VEN_MAUDIO1) && - (entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH) && - !check_audiophile_booted(unit)) - spec = NULL; - else - spec = (const struct snd_bebob_spec *)entry->driver_data; - - if (spec == NULL) { - if ((entry->vendor_id == VEN_MAUDIO1) || - (entry->vendor_id == VEN_MAUDIO2)) - err = snd_bebob_maudio_load_firmware(unit); - else - err = -ENOSYS; - goto end; + err = snd_card_new(&bebob->unit->device, index[card_index], + id[card_index], THIS_MODULE, 0, &bebob->card); + if (err < 0) { + mutex_unlock(&devices_mutex); + return; } - err = snd_card_new(&unit->device, index[card_index], id[card_index], - THIS_MODULE, sizeof(struct snd_bebob), &card); + err = name_device(bebob); if (err < 0) - goto end; - bebob = card->private_data; - bebob->card_index = card_index; - set_bit(card_index, devices_used); - card->private_free = bebob_card_free; - - bebob->card = card; - bebob->unit = fw_unit_get(unit); - bebob->spec = spec; - mutex_init(&bebob->mutex); - spin_lock_init(&bebob->lock); - init_waitqueue_head(&bebob->hwdep_wait); + goto error; - err = name_device(bebob, entry->vendor_id); + if (bebob->spec == &maudio_special_spec) { + if (bebob->entry->model_id == MODEL_MAUDIO_FW1814) + err = snd_bebob_maudio_special_discover(bebob, true); + else + err = snd_bebob_maudio_special_discover(bebob, false); + } else { + err = snd_bebob_stream_discover(bebob); + } if (err < 0) goto error; - if ((entry->vendor_id == VEN_MAUDIO1) && - (entry->model_id == MODEL_MAUDIO_FW1814)) - err = snd_bebob_maudio_special_discover(bebob, true); - else if ((entry->vendor_id == VEN_MAUDIO1) && - (entry->model_id == MODEL_MAUDIO_PROJECTMIX)) - err = snd_bebob_maudio_special_discover(bebob, false); - else - err = snd_bebob_stream_discover(bebob); + err = snd_bebob_stream_init_duplex(bebob); if (err < 0) goto error; snd_bebob_proc_init(bebob); - if ((bebob->midi_input_ports > 0) || - (bebob->midi_output_ports > 0)) { + if (bebob->midi_input_ports > 0 || bebob->midi_output_ports > 0) { err = snd_bebob_create_midi_devices(bebob); if (err < 0) goto error; @@ -264,16 +244,75 @@ bebob_probe(struct fw_unit *unit, if (err < 0) goto error; - err = snd_bebob_stream_init_duplex(bebob); + err = snd_card_register(bebob->card); if (err < 0) goto error; - if (!bebob->maudio_special_quirk) { - err = snd_card_register(card); - if (err < 0) { - snd_bebob_stream_destroy_duplex(bebob); - goto error; - } + set_bit(card_index, devices_used); + mutex_unlock(&devices_mutex); + + /* + * After registered, bebob instance can be released corresponding to + * releasing the sound card instance. + */ + bebob->card->private_free = bebob_card_free; + bebob->card->private_data = bebob; + bebob->registered = true; + + return; +error: + mutex_unlock(&devices_mutex); + snd_bebob_stream_destroy_duplex(bebob); + snd_card_free(bebob->card); + dev_info(&bebob->unit->device, + "Sound card registration failed: %d\n", err); +} + +static int +bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) +{ + struct snd_bebob *bebob; + const struct snd_bebob_spec *spec; + + if (entry->vendor_id == VEN_FOCUSRITE && + entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH) + spec = get_saffire_spec(unit); + else if (entry->vendor_id == VEN_MAUDIO1 && + entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH && + !check_audiophile_booted(unit)) + spec = NULL; + else + spec = (const struct snd_bebob_spec *)entry->driver_data; + + if (spec == NULL) { + if (entry->vendor_id == VEN_MAUDIO1 || + entry->vendor_id == VEN_MAUDIO2) + return snd_bebob_maudio_load_firmware(unit); + else + return -ENODEV; + } + + /* Allocate this independent of sound card instance. */ + bebob = kzalloc(sizeof(struct snd_bebob), GFP_KERNEL); + if (bebob == NULL) + return -ENOMEM; + + bebob->unit = fw_unit_get(unit); + bebob->entry = entry; + bebob->spec = spec; + dev_set_drvdata(&unit->device, bebob); + + mutex_init(&bebob->mutex); + spin_lock_init(&bebob->lock); + init_waitqueue_head(&bebob->hwdep_wait); + + /* Allocate and register this sound card later. */ + INIT_DEFERRABLE_WORK(&bebob->dwork, do_registration); + + if (entry->vendor_id != VEN_MAUDIO1 || + (entry->model_id != MODEL_MAUDIO_FW1814 && + entry->model_id != MODEL_MAUDIO_PROJECTMIX)) { + snd_fw_schedule_registration(unit, &bebob->dwork); } else { /* * This is a workaround. This bus reset seems to have an effect @@ -285,19 +324,11 @@ bebob_probe(struct fw_unit *unit, * signals from dbus and starts I/Os. To avoid I/Os till the * future bus reset, registration is done in next update(). */ - bebob->deferred_registration = true; fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card, false, true); } - dev_set_drvdata(&unit->device, bebob); -end: - mutex_unlock(&devices_mutex); - return err; -error: - mutex_unlock(&devices_mutex); - snd_card_free(card); - return err; + return 0; } /* @@ -324,15 +355,11 @@ bebob_update(struct fw_unit *unit) if (bebob == NULL) return; - fcp_bus_reset(bebob->unit); - - if (bebob->deferred_registration) { - if (snd_card_register(bebob->card) < 0) { - snd_bebob_stream_destroy_duplex(bebob); - snd_card_free(bebob->card); - } - bebob->deferred_registration = false; - } + /* Postpone a workqueue for deferred registration. */ + if (!bebob->registered) + snd_fw_schedule_registration(unit, &bebob->dwork); + else + fcp_bus_reset(bebob->unit); } static void bebob_remove(struct fw_unit *unit) @@ -342,8 +369,20 @@ static void bebob_remove(struct fw_unit *unit) if (bebob == NULL) return; - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(bebob->card); + /* + * Confirm to stop the work for registration before the sound card is + * going to be released. The work is not scheduled again because bus + * reset handler is not called anymore. + */ + cancel_delayed_work_sync(&bebob->dwork); + + if (bebob->registered) { + /* No need to wait for releasing card object in this context. */ + snd_card_free_when_closed(bebob->card); + } else { + /* Don't forget this case. */ + bebob_free(bebob); + } } static const struct snd_bebob_rate_spec normal_rate_spec = { diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index b50bb33d9d46..2a442a7a2119 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -83,6 +83,10 @@ struct snd_bebob { struct mutex mutex; spinlock_t lock; + bool registered; + struct delayed_work dwork; + + const struct ieee1394_device_id *entry; const struct snd_bebob_spec *spec; unsigned int midi_input_ports; @@ -111,7 +115,6 @@ struct snd_bebob { /* for M-Audio special devices */ void *maudio_special_quirk; - bool deferred_registration; /* For BeBoB version quirk. */ unsigned int version; diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 8b64aef31a86..96fe68f42e5d 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -20,8 +20,6 @@ MODULE_LICENSE("GPL v2"); #define WEISS_CATEGORY_ID 0x00 #define LOUD_CATEGORY_ID 0x10 -#define PROBE_DELAY_MS (2 * MSEC_PER_SEC) - /* * Some models support several isochronous channels, while these streams are not * always available. In this case, add the model name to this list. @@ -201,6 +199,10 @@ static void do_registration(struct work_struct *work) dice_card_strings(dice); + err = snd_dice_stream_init_duplex(dice); + if (err < 0) + goto error; + snd_dice_create_proc(dice); err = snd_dice_create_pcm(dice); @@ -229,28 +231,14 @@ static void do_registration(struct work_struct *work) return; error: + snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); + snd_dice_stream_destroy_duplex(dice); snd_card_free(dice->card); dev_info(&dice->unit->device, "Sound card registration failed: %d\n", err); } -static void schedule_registration(struct snd_dice *dice) -{ - struct fw_card *fw_card = fw_parent_device(dice->unit)->card; - u64 now, delay; - - now = get_jiffies_64(); - delay = fw_card->reset_jiffies + msecs_to_jiffies(PROBE_DELAY_MS); - - if (time_after64(delay, now)) - delay -= now; - else - delay = 0; - - mod_delayed_work(system_wq, &dice->dwork, delay); -} - static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) { struct snd_dice *dice; @@ -273,15 +261,9 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) init_completion(&dice->clock_accepted); init_waitqueue_head(&dice->hwdep_wait); - err = snd_dice_stream_init_duplex(dice); - if (err < 0) { - dice_free(dice); - return err; - } - /* Allocate and register this sound card later. */ INIT_DEFERRABLE_WORK(&dice->dwork, do_registration); - schedule_registration(dice); + snd_fw_schedule_registration(unit, &dice->dwork); return 0; } @@ -312,7 +294,7 @@ static void dice_bus_reset(struct fw_unit *unit) /* Postpone a workqueue for deferred registration. */ if (!dice->registered) - schedule_registration(dice); + snd_fw_schedule_registration(unit, &dice->dwork); /* The handler address register becomes initialized. */ snd_dice_transaction_reinit(dice); diff --git a/sound/firewire/digi00x/digi00x-transaction.c b/sound/firewire/digi00x/digi00x-transaction.c index 554324d8c602..735d35640807 100644 --- a/sound/firewire/digi00x/digi00x-transaction.c +++ b/sound/firewire/digi00x/digi00x-transaction.c @@ -126,12 +126,17 @@ int snd_dg00x_transaction_register(struct snd_dg00x *dg00x) return err; error: fw_core_remove_address_handler(&dg00x->async_handler); - dg00x->async_handler.address_callback = NULL; + dg00x->async_handler.callback_data = NULL; return err; } void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x) { + if (dg00x->async_handler.callback_data == NULL) + return; + snd_fw_async_midi_port_destroy(&dg00x->out_control); fw_core_remove_address_handler(&dg00x->async_handler); + + dg00x->async_handler.callback_data = NULL; } diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index 1f33b7a1fca4..cc4776c6ded3 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -40,10 +40,8 @@ static int name_card(struct snd_dg00x *dg00x) return 0; } -static void dg00x_card_free(struct snd_card *card) +static void dg00x_free(struct snd_dg00x *dg00x) { - struct snd_dg00x *dg00x = card->private_data; - snd_dg00x_stream_destroy_duplex(dg00x); snd_dg00x_transaction_unregister(dg00x); @@ -52,28 +50,24 @@ static void dg00x_card_free(struct snd_card *card) mutex_destroy(&dg00x->mutex); } -static int snd_dg00x_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) +static void dg00x_card_free(struct snd_card *card) { - struct snd_card *card; - struct snd_dg00x *dg00x; - int err; + dg00x_free(card->private_data); +} - /* create card */ - err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, - sizeof(struct snd_dg00x), &card); - if (err < 0) - return err; - card->private_free = dg00x_card_free; +static void do_registration(struct work_struct *work) +{ + struct snd_dg00x *dg00x = + container_of(work, struct snd_dg00x, dwork.work); + int err; - /* initialize myself */ - dg00x = card->private_data; - dg00x->card = card; - dg00x->unit = fw_unit_get(unit); + if (dg00x->registered) + return; - mutex_init(&dg00x->mutex); - spin_lock_init(&dg00x->lock); - init_waitqueue_head(&dg00x->hwdep_wait); + err = snd_card_new(&dg00x->unit->device, -1, NULL, THIS_MODULE, 0, + &dg00x->card); + if (err < 0) + return; err = name_card(dg00x); if (err < 0) @@ -101,35 +95,86 @@ static int snd_dg00x_probe(struct fw_unit *unit, if (err < 0) goto error; - err = snd_card_register(card); + err = snd_card_register(dg00x->card); if (err < 0) goto error; - dev_set_drvdata(&unit->device, dg00x); + dg00x->card->private_free = dg00x_card_free; + dg00x->card->private_data = dg00x; + dg00x->registered = true; - return err; + return; error: - snd_card_free(card); - return err; + snd_dg00x_transaction_unregister(dg00x); + snd_dg00x_stream_destroy_duplex(dg00x); + snd_card_free(dg00x->card); + dev_info(&dg00x->unit->device, + "Sound card registration failed: %d\n", err); +} + +static int snd_dg00x_probe(struct fw_unit *unit, + const struct ieee1394_device_id *entry) +{ + struct snd_dg00x *dg00x; + + /* Allocate this independent of sound card instance. */ + dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL); + if (dg00x == NULL) + return -ENOMEM; + + dg00x->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, dg00x); + + mutex_init(&dg00x->mutex); + spin_lock_init(&dg00x->lock); + init_waitqueue_head(&dg00x->hwdep_wait); + + /* Allocate and register this sound card later. */ + INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration); + snd_fw_schedule_registration(unit, &dg00x->dwork); + + return 0; } static void snd_dg00x_update(struct fw_unit *unit) { struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); + /* Postpone a workqueue for deferred registration. */ + if (!dg00x->registered) + snd_fw_schedule_registration(unit, &dg00x->dwork); + snd_dg00x_transaction_reregister(dg00x); - mutex_lock(&dg00x->mutex); - snd_dg00x_stream_update_duplex(dg00x); - mutex_unlock(&dg00x->mutex); + /* + * After registration, userspace can start packet streaming, then this + * code block works fine. + */ + if (dg00x->registered) { + mutex_lock(&dg00x->mutex); + snd_dg00x_stream_update_duplex(dg00x); + mutex_unlock(&dg00x->mutex); + } } static void snd_dg00x_remove(struct fw_unit *unit) { struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(dg00x->card); + /* + * Confirm to stop the work for registration before the sound card is + * going to be released. The work is not scheduled again because bus + * reset handler is not called anymore. + */ + cancel_delayed_work_sync(&dg00x->dwork); + + if (dg00x->registered) { + /* No need to wait for releasing card object in this context. */ + snd_card_free_when_closed(dg00x->card); + } else { + /* Don't forget this case. */ + dg00x_free(dg00x); + } } static const struct ieee1394_device_id snd_dg00x_id_table[] = { diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 907e73993677..2cd465c0caae 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -37,6 +37,9 @@ struct snd_dg00x { struct mutex mutex; spinlock_t lock; + bool registered; + struct delayed_work dwork; + struct amdtp_stream tx_stream; struct fw_iso_resources tx_resources; diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 8f27b67503c8..71a0613d3da0 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -168,11 +168,34 @@ get_hardware_info(struct snd_efw *efw) sizeof(struct snd_efw_phys_grp) * hwinfo->phys_in_grp_count); memcpy(&efw->phys_out_grps, hwinfo->phys_out_grps, sizeof(struct snd_efw_phys_grp) * hwinfo->phys_out_grp_count); + + /* AudioFire8 (since 2009) and AudioFirePre8 */ + if (hwinfo->type == MODEL_ECHO_AUDIOFIRE_9) + efw->is_af9 = true; + /* These models uses the same firmware. */ + if (hwinfo->type == MODEL_ECHO_AUDIOFIRE_2 || + hwinfo->type == MODEL_ECHO_AUDIOFIRE_4 || + hwinfo->type == MODEL_ECHO_AUDIOFIRE_9 || + hwinfo->type == MODEL_GIBSON_RIP || + hwinfo->type == MODEL_GIBSON_GOLDTOP) + efw->is_fireworks3 = true; end: kfree(hwinfo); return err; } +static void efw_free(struct snd_efw *efw) +{ + snd_efw_stream_destroy_duplex(efw); + snd_efw_transaction_remove_instance(efw); + fw_unit_put(efw->unit); + + kfree(efw->resp_buf); + + mutex_destroy(&efw->mutex); + kfree(efw); +} + /* * This module releases the FireWire unit data after all ALSA character devices * are released by applications. This is for releasing stream data or finishing @@ -184,28 +207,24 @@ efw_card_free(struct snd_card *card) { struct snd_efw *efw = card->private_data; - snd_efw_stream_destroy_duplex(efw); - snd_efw_transaction_remove_instance(efw); - fw_unit_put(efw->unit); - - kfree(efw->resp_buf); - if (efw->card_index >= 0) { mutex_lock(&devices_mutex); clear_bit(efw->card_index, devices_used); mutex_unlock(&devices_mutex); } - mutex_destroy(&efw->mutex); + efw_free(card->private_data); } -static int -efw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) +static void +do_registration(struct work_struct *work) { - struct snd_card *card; - struct snd_efw *efw; - int card_index, err; + struct snd_efw *efw = container_of(work, struct snd_efw, dwork.work); + unsigned int card_index; + int err; + + if (efw->registered) + return; mutex_lock(&devices_mutex); @@ -215,24 +234,16 @@ efw_probe(struct fw_unit *unit, break; } if (card_index >= SNDRV_CARDS) { - err = -ENOENT; - goto end; + mutex_unlock(&devices_mutex); + return; } - err = snd_card_new(&unit->device, index[card_index], id[card_index], - THIS_MODULE, sizeof(struct snd_efw), &card); - if (err < 0) - goto end; - efw = card->private_data; - efw->card_index = card_index; - set_bit(card_index, devices_used); - card->private_free = efw_card_free; - - efw->card = card; - efw->unit = fw_unit_get(unit); - mutex_init(&efw->mutex); - spin_lock_init(&efw->lock); - init_waitqueue_head(&efw->hwdep_wait); + err = snd_card_new(&efw->unit->device, index[card_index], + id[card_index], THIS_MODULE, 0, &efw->card); + if (err < 0) { + mutex_unlock(&devices_mutex); + return; + } /* prepare response buffer */ snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, @@ -248,16 +259,10 @@ efw_probe(struct fw_unit *unit, err = get_hardware_info(efw); if (err < 0) goto error; - /* AudioFire8 (since 2009) and AudioFirePre8 */ - if (entry->model_id == MODEL_ECHO_AUDIOFIRE_9) - efw->is_af9 = true; - /* These models uses the same firmware. */ - if (entry->model_id == MODEL_ECHO_AUDIOFIRE_2 || - entry->model_id == MODEL_ECHO_AUDIOFIRE_4 || - entry->model_id == MODEL_ECHO_AUDIOFIRE_9 || - entry->model_id == MODEL_GIBSON_RIP || - entry->model_id == MODEL_GIBSON_GOLDTOP) - efw->is_fireworks3 = true; + + err = snd_efw_stream_init_duplex(efw); + if (err < 0) + goto error; snd_efw_proc_init(efw); @@ -275,44 +280,93 @@ efw_probe(struct fw_unit *unit, if (err < 0) goto error; - err = snd_efw_stream_init_duplex(efw); + err = snd_card_register(efw->card); if (err < 0) goto error; - err = snd_card_register(card); - if (err < 0) { - snd_efw_stream_destroy_duplex(efw); - goto error; - } - - dev_set_drvdata(&unit->device, efw); -end: + set_bit(card_index, devices_used); mutex_unlock(&devices_mutex); - return err; + + /* + * After registered, efw instance can be released corresponding to + * releasing the sound card instance. + */ + efw->card->private_free = efw_card_free; + efw->card->private_data = efw; + efw->registered = true; + + return; error: - snd_efw_transaction_remove_instance(efw); mutex_unlock(&devices_mutex); - snd_card_free(card); - return err; + snd_efw_transaction_remove_instance(efw); + snd_efw_stream_destroy_duplex(efw); + snd_card_free(efw->card); + dev_info(&efw->unit->device, + "Sound card registration failed: %d\n", err); +} + +static int +efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) +{ + struct snd_efw *efw; + + efw = kzalloc(sizeof(struct snd_efw), GFP_KERNEL); + if (efw == NULL) + return -ENOMEM; + + efw->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, efw); + + mutex_init(&efw->mutex); + spin_lock_init(&efw->lock); + init_waitqueue_head(&efw->hwdep_wait); + + /* Allocate and register this sound card later. */ + INIT_DEFERRABLE_WORK(&efw->dwork, do_registration); + snd_fw_schedule_registration(unit, &efw->dwork); + + return 0; } static void efw_update(struct fw_unit *unit) { struct snd_efw *efw = dev_get_drvdata(&unit->device); + /* Postpone a workqueue for deferred registration. */ + if (!efw->registered) + snd_fw_schedule_registration(unit, &efw->dwork); + snd_efw_transaction_bus_reset(efw->unit); - mutex_lock(&efw->mutex); - snd_efw_stream_update_duplex(efw); - mutex_unlock(&efw->mutex); + /* + * After registration, userspace can start packet streaming, then this + * code block works fine. + */ + if (efw->registered) { + mutex_lock(&efw->mutex); + snd_efw_stream_update_duplex(efw); + mutex_unlock(&efw->mutex); + } } static void efw_remove(struct fw_unit *unit) { struct snd_efw *efw = dev_get_drvdata(&unit->device); - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(efw->card); + /* + * Confirm to stop the work for registration before the sound card is + * going to be released. The work is not scheduled again because bus + * reset handler is not called anymore. + */ + cancel_delayed_work_sync(&efw->dwork); + + if (efw->registered) { + /* No need to wait for releasing card object in this context. */ + snd_card_free_when_closed(efw->card); + } else { + /* Don't forget this case. */ + efw_free(efw); + } } static const struct ieee1394_device_id efw_id_table[] = { diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 96c4e0c6a9bd..471c77254dfd 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -65,6 +65,9 @@ struct snd_efw { struct mutex mutex; spinlock_t lock; + bool registered; + struct delayed_work dwork; + /* for transaction */ u32 seqnum; bool resp_addr_changable; diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c index f80aafa44c89..ca4dfcf43175 100644 --- a/sound/firewire/lib.c +++ b/sound/firewire/lib.c @@ -67,6 +67,38 @@ int snd_fw_transaction(struct fw_unit *unit, int tcode, } EXPORT_SYMBOL(snd_fw_transaction); +#define PROBE_DELAY_MS (2 * MSEC_PER_SEC) + +/** + * snd_fw_schedule_registration - schedule work for sound card registration + * @unit: an instance for unit on IEEE 1394 bus + * @dwork: delayed work with callback function + * + * This function is not designed for general purposes. When new unit is + * connected to IEEE 1394 bus, the bus is under bus-reset state because of + * topological change. In this state, units tend to fail both of asynchronous + * and isochronous communication. To avoid this problem, this function is used + * to postpone sound card registration after the state. The callers must + * set up instance of delayed work in advance. + */ +void snd_fw_schedule_registration(struct fw_unit *unit, + struct delayed_work *dwork) +{ + u64 now, delay; + + now = get_jiffies_64(); + delay = fw_parent_device(unit)->card->reset_jiffies + + msecs_to_jiffies(PROBE_DELAY_MS); + + if (time_after64(delay, now)) + delay -= now; + else + delay = 0; + + mod_delayed_work(system_wq, dwork, delay); +} +EXPORT_SYMBOL(snd_fw_schedule_registration); + static void async_midi_port_callback(struct fw_card *card, int rcode, void *data, size_t length, void *callback_data) diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h index f3f6f84c48d6..f6769312ebfc 100644 --- a/sound/firewire/lib.h +++ b/sound/firewire/lib.h @@ -22,6 +22,9 @@ static inline bool rcode_is_permanent_error(int rcode) return rcode == RCODE_TYPE_ERROR || rcode == RCODE_ADDRESS_ERROR; } +void snd_fw_schedule_registration(struct fw_unit *unit, + struct delayed_work *dwork); + struct snd_fw_async_midi_port; typedef int (*snd_fw_async_midi_port_fill)( struct snd_rawmidi_substream *substream, diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index abedc2207261..e629b88f7d93 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -118,15 +118,8 @@ end: return err; } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void oxfw_card_free(struct snd_card *card) +static void oxfw_free(struct snd_oxfw *oxfw) { - struct snd_oxfw *oxfw = card->private_data; unsigned int i; snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); @@ -144,6 +137,17 @@ static void oxfw_card_free(struct snd_card *card) mutex_destroy(&oxfw->mutex); } +/* + * This module releases the FireWire unit data after all ALSA character devices + * are released by applications. This is for releasing stream data or finishing + * transactions safely. Thus at returning from .remove(), this module still keep + * references for the unit. + */ +static void oxfw_card_free(struct snd_card *card) +{ + oxfw_free(card->private_data); +} + static int detect_quirks(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); @@ -205,41 +209,39 @@ static int detect_quirks(struct snd_oxfw *oxfw) return 0; } -static int oxfw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) +static void do_registration(struct work_struct *work) { - struct snd_card *card; - struct snd_oxfw *oxfw; + struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work); int err; - if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) - return -ENODEV; + if (oxfw->registered) + return; - err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, - sizeof(*oxfw), &card); + err = snd_card_new(&oxfw->unit->device, -1, NULL, THIS_MODULE, 0, + &oxfw->card); if (err < 0) - return err; + return; - card->private_free = oxfw_card_free; - oxfw = card->private_data; - oxfw->card = card; - mutex_init(&oxfw->mutex); - oxfw->unit = fw_unit_get(unit); - oxfw->entry = entry; - spin_lock_init(&oxfw->lock); - init_waitqueue_head(&oxfw->hwdep_wait); + err = name_card(oxfw); + if (err < 0) + goto error; - err = snd_oxfw_stream_discover(oxfw); + err = detect_quirks(oxfw); if (err < 0) goto error; - err = name_card(oxfw); + err = snd_oxfw_stream_discover(oxfw); if (err < 0) goto error; - err = detect_quirks(oxfw); + err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream); if (err < 0) goto error; + if (oxfw->has_output) { + err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream); + if (err < 0) + goto error; + } err = snd_oxfw_create_pcm(oxfw); if (err < 0) @@ -255,54 +257,97 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error; - err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream); + err = snd_card_register(oxfw->card); if (err < 0) goto error; - if (oxfw->has_output) { - err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream); - if (err < 0) - goto error; - } - err = snd_card_register(card); - if (err < 0) { - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - goto error; - } + /* + * After registered, oxfw instance can be released corresponding to + * releasing the sound card instance. + */ + oxfw->card->private_free = oxfw_card_free; + oxfw->card->private_data = oxfw; + oxfw->registered = true; + + return; +error: + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); + snd_card_free(oxfw->card); + dev_info(&oxfw->unit->device, + "Sound card registration failed: %d\n", err); +} + +static int oxfw_probe(struct fw_unit *unit, + const struct ieee1394_device_id *entry) +{ + struct snd_oxfw *oxfw; + + if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) + return -ENODEV; + + /* Allocate this independent of sound card instance. */ + oxfw = kzalloc(sizeof(struct snd_oxfw), GFP_KERNEL); + if (oxfw == NULL) + return -ENOMEM; + + oxfw->entry = entry; + oxfw->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, oxfw); + mutex_init(&oxfw->mutex); + spin_lock_init(&oxfw->lock); + init_waitqueue_head(&oxfw->hwdep_wait); + + /* Allocate and register this sound card later. */ + INIT_DEFERRABLE_WORK(&oxfw->dwork, do_registration); + snd_fw_schedule_registration(unit, &oxfw->dwork); + return 0; -error: - snd_card_free(card); - return err; } static void oxfw_bus_reset(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); + if (!oxfw->registered) + snd_fw_schedule_registration(unit, &oxfw->dwork); + fcp_bus_reset(oxfw->unit); - mutex_lock(&oxfw->mutex); + if (oxfw->registered) { + mutex_lock(&oxfw->mutex); - snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream); + snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream); - mutex_unlock(&oxfw->mutex); + mutex_unlock(&oxfw->mutex); - if (oxfw->entry->vendor_id == OUI_STANTON) - snd_oxfw_scs1x_update(oxfw); + if (oxfw->entry->vendor_id == OUI_STANTON) + snd_oxfw_scs1x_update(oxfw); + } } static void oxfw_remove(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(oxfw->card); + /* + * Confirm to stop the work for registration before the sound card is + * going to be released. The work is not scheduled again because bus + * reset handler is not called anymore. + */ + cancel_delayed_work_sync(&oxfw->dwork); + + if (oxfw->registered) { + /* No need to wait for releasing card object in this context. */ + snd_card_free_when_closed(oxfw->card); + } else { + /* Don't forget this case. */ + oxfw_free(oxfw); + } } static const struct compat_info griffin_firewave = { diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 9beecc214767..2047dcb27625 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -36,10 +36,12 @@ struct snd_oxfw { struct snd_card *card; struct fw_unit *unit; - const struct device_info *device_info; struct mutex mutex; spinlock_t lock; + bool registered; + struct delayed_work dwork; + bool wrong_dbs; bool has_output; u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES]; diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index fb96aead8257..6800e0c5a38f 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -118,22 +118,40 @@ int snd_hdac_get_display_clk(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk); -/* There is a fixed mapping between audio pin node and display port - * on current Intel platforms: +/* There is a fixed mapping between audio pin node and display port. + * on SNB, IVY, HSW, BSW, SKL, BXT, KBL: * Pin Widget 5 - PORT B (port = 1 in i915 driver) * Pin Widget 6 - PORT C (port = 2 in i915 driver) * Pin Widget 7 - PORT D (port = 3 in i915 driver) + * + * on VLV, ILK: + * Pin Widget 4 - PORT B (port = 1 in i915 driver) + * Pin Widget 5 - PORT C (port = 2 in i915 driver) + * Pin Widget 6 - PORT D (port = 3 in i915 driver) */ -static int pin2port(hda_nid_t pin_nid) +static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid) { - if (WARN_ON(pin_nid < 5 || pin_nid > 7)) + int base_nid; + + switch (codec->vendor_id) { + case 0x80860054: /* ILK */ + case 0x80862804: /* ILK */ + case 0x80862882: /* VLV */ + base_nid = 3; + break; + default: + base_nid = 4; + break; + } + + if (WARN_ON(pin_nid <= base_nid || pin_nid > base_nid + 3)) return -1; - return pin_nid - 4; + return pin_nid - base_nid; } /** * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate - * @bus: HDA core bus + * @codec: HDA codec * @nid: the pin widget NID * @rate: the sample rate to set * @@ -143,14 +161,15 @@ static int pin2port(hda_nid_t pin_nid) * This function sets N/CTS value based on the given sample rate. * Returns zero for success, or a negative error code. */ -int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate) +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate) { + struct hdac_bus *bus = codec->bus; struct i915_audio_component *acomp = bus->audio_component; int port; if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate) return -ENODEV; - port = pin2port(nid); + port = pin2port(codec, nid); if (port < 0) return -EINVAL; return acomp->ops->sync_audio_rate(acomp->dev, port, rate); @@ -159,7 +178,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate); /** * snd_hdac_acomp_get_eld - Get the audio state and ELD via component - * @bus: HDA core bus + * @codec: HDA codec * @nid: the pin widget NID * @audio_enabled: the pointer to store the current audio state * @buffer: the buffer pointer to store ELD bytes @@ -177,16 +196,17 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate); * thus it may be over @max_bytes. If it's over @max_bytes, it implies * that only a part of ELD bytes have been fetched. */ -int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, bool *audio_enabled, char *buffer, int max_bytes) { + struct hdac_bus *bus = codec->bus; struct i915_audio_component *acomp = bus->audio_component; int port; if (!acomp || !acomp->ops || !acomp->ops->get_eld) return -ENODEV; - port = pin2port(nid); + port = pin2port(codec, nid); if (port < 0) return -EINVAL; return acomp->ops->get_eld(acomp->dev, port, audio_enabled, @@ -267,6 +287,18 @@ int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops } EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier); +/* check whether intel graphics is present */ +static bool i915_gfx_present(void) +{ + static struct pci_device_id ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), + .class = PCI_BASE_CLASS_DISPLAY << 16, + .class_mask = 0xff << 16 }, + {} + }; + return pci_dev_present(ids); +} + /** * snd_hdac_i915_init - Initialize i915 audio component * @bus: HDA core bus @@ -286,6 +318,12 @@ int snd_hdac_i915_init(struct hdac_bus *bus) struct i915_audio_component *acomp; int ret; + if (WARN_ON(hdac_acomp)) + return -EBUSY; + + if (!i915_gfx_present()) + return -ENODEV; + acomp = kzalloc(sizeof(*acomp), GFP_KERNEL); if (!acomp) return -ENOMEM; @@ -316,6 +354,7 @@ out_master_del: out_err: kfree(acomp); bus->audio_component = NULL; + hdac_acomp = NULL; dev_info(dev, "failed to add i915 component master (%d)\n", ret); return ret; @@ -349,6 +388,7 @@ int snd_hdac_i915_exit(struct hdac_bus *bus) kfree(acomp); bus->audio_component = NULL; + hdac_acomp = NULL; return 0; } diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index d7ec86263828..c6c75e7e0981 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -625,13 +625,30 @@ static void hdmi_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, WARN_ON(count != channels); } +static int spk_mask_from_spk_alloc(int spk_alloc) +{ + int i; + int spk_mask = eld_speaker_allocation_bits[0]; + + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { + if (spk_alloc & (1 << i)) + spk_mask |= eld_speaker_allocation_bits[i]; + } + + return spk_mask; +} + static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) { struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hdac_chmap *chmap = info->private_data; + int pcm_idx = kcontrol->private_value; unsigned int __user *dst; int chs, count = 0; + unsigned long max_chs; + int type; + int spk_alloc, spk_mask; if (size < 8) return -ENOMEM; @@ -639,40 +656,59 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -EFAULT; size -= 8; dst = tlv + 2; - for (chs = 2; chs <= chmap->channels_max; chs++) { + + spk_alloc = chmap->ops.get_spk_alloc(chmap->hdac, pcm_idx); + spk_mask = spk_mask_from_spk_alloc(spk_alloc); + + max_chs = hweight_long(spk_mask); + + for (chs = 2; chs <= max_chs; chs++) { int i; struct hdac_cea_channel_speaker_allocation *cap; cap = channel_allocations; for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) { int chs_bytes = chs * 4; - int type = chmap->ops.chmap_cea_alloc_validate_get_type( - chmap, cap, chs); unsigned int tlv_chmap[8]; - if (type < 0) + if (cap->channels != chs) + continue; + + if (!(cap->spk_mask == (spk_mask & cap->spk_mask))) continue; + + type = chmap->ops.chmap_cea_alloc_validate_get_type( + chmap, cap, chs); + if (type < 0) + return -ENODEV; if (size < 8) return -ENOMEM; + if (put_user(type, dst) || put_user(chs_bytes, dst + 1)) return -EFAULT; + dst += 2; size -= 8; count += 8; + if (size < chs_bytes) return -ENOMEM; + size -= chs_bytes; count += chs_bytes; chmap->ops.cea_alloc_to_tlv_chmap(chmap, cap, tlv_chmap, chs); + if (copy_to_user(dst, tlv_chmap, chs_bytes)) return -EFAULT; dst += chs; } } + if (put_user(count, tlv + 1)) return -EFAULT; + return 0; } diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index a5d460453d7b..8f945341720b 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -49,7 +49,7 @@ struct ct_timer { spinlock_t lock; /* global timer lock (for xfitimer) */ spinlock_t list_lock; /* lock for instance list */ struct ct_atc *atc; - struct ct_timer_ops *ops; + const struct ct_timer_ops *ops; struct list_head instance_head; struct list_head running_head; unsigned int wc; /* current wallclock */ @@ -128,7 +128,7 @@ static void ct_systimer_prepare(struct ct_timer_instance *ti) #define ct_systimer_free ct_systimer_prepare -static struct ct_timer_ops ct_systimer_ops = { +static const struct ct_timer_ops ct_systimer_ops = { .init = ct_systimer_init, .free_instance = ct_systimer_free, .prepare = ct_systimer_prepare, @@ -322,7 +322,7 @@ static void ct_xfitimer_free_global(struct ct_timer *atimer) ct_xfitimer_irq_stop(atimer); } -static struct ct_timer_ops ct_xfitimer_ops = { +static const struct ct_timer_ops ct_xfitimer_ops = { .prepare = ct_xfitimer_prepare, .start = ct_xfitimer_start, .stop = ct_xfitimer_stop, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5af372d01834..9452384d2000 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -114,6 +114,9 @@ struct hdmi_ops { int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format); + void (*pin_cvt_fixup)(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + hda_nid_t cvt_nid); }; struct hdmi_pcm { @@ -684,7 +687,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, if (!channels) return; - if (is_haswell_plus(codec)) + /* some HW (e.g. HSW+) needs reprogramming the amp at each time */ + if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); @@ -864,9 +868,6 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, struct hdmi_spec *spec = codec->spec; int err; - if (is_haswell_plus(codec)) - haswell_verify_D0(codec, cvt_nid, pin_nid); - err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format)); if (err) { @@ -884,7 +885,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, * of the pin. */ static int hdmi_choose_cvt(struct hda_codec *codec, - int pin_idx, int *cvt_id, int *mux_id) + int pin_idx, int *cvt_id) { struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin; @@ -925,8 +926,6 @@ static int hdmi_choose_cvt(struct hda_codec *codec, if (cvt_id) *cvt_id = cvt_idx; - if (mux_id) - *mux_id = mux_idx; return 0; } @@ -1019,9 +1018,6 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec, int mux_idx; struct hdmi_spec *spec = codec->spec; - if (!is_haswell_plus(codec) && !is_valleyview_plus(codec)) - return; - /* On Intel platform, the mapping of converter nid to * mux index of the pins are always the same. * The pin nid may be 0, this means all pins will not @@ -1032,6 +1028,17 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec, intel_not_share_assigned_cvt(codec, pin_nid, mux_idx); } +/* skeleton caller of pin_cvt_fixup ops */ +static void pin_cvt_fixup(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + hda_nid_t cvt_nid) +{ + struct hdmi_spec *spec = codec->spec; + + if (spec->ops.pin_cvt_fixup) + spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid); +} + /* called in hdmi_pcm_open when no pin is assigned to the PCM * in dyn_pcm_assign mode. */ @@ -1049,7 +1056,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo, if (pcm_idx < 0) return -EINVAL; - err = hdmi_choose_cvt(codec, -1, &cvt_idx, NULL); + err = hdmi_choose_cvt(codec, -1, &cvt_idx); if (err) return err; @@ -1057,7 +1064,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo, per_cvt->assigned = 1; hinfo->nid = per_cvt->cvt_nid; - intel_not_share_assigned_cvt_nid(codec, 0, per_cvt->cvt_nid); + pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid); set_bit(pcm_idx, &spec->pcm_in_use); /* todo: setup spdif ctls assign */ @@ -1089,7 +1096,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, { struct hdmi_spec *spec = codec->spec; struct snd_pcm_runtime *runtime = substream->runtime; - int pin_idx, cvt_idx, pcm_idx, mux_idx = 0; + int pin_idx, cvt_idx, pcm_idx; struct hdmi_spec_per_pin *per_pin; struct hdmi_eld *eld; struct hdmi_spec_per_cvt *per_cvt = NULL; @@ -1118,7 +1125,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, } } - err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx); + err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx); if (err < 0) { mutex_unlock(&spec->pcm_lock); return err; @@ -1135,11 +1142,10 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0, AC_VERB_SET_CONNECT_SEL, - mux_idx); + per_pin->mux_idx); /* configure unused pins to choose other converters */ - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) - intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx); + pin_cvt_fixup(codec, per_pin, 0); snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid); @@ -1372,12 +1378,7 @@ static void update_eld(struct hda_codec *codec, * and this can make HW reset converter selection on a pin. */ if (eld->eld_valid && !old_eld_valid && per_pin->setup) { - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { - intel_verify_pin_cvt_connect(codec, per_pin); - intel_not_share_assigned_cvt(codec, per_pin->pin_nid, - per_pin->mux_idx); - } - + pin_cvt_fixup(codec, per_pin, 0); hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); } @@ -1485,7 +1486,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec, mutex_lock(&per_pin->lock); eld->monitor_present = false; - size = snd_hdac_acomp_get_eld(&codec->bus->core, per_pin->pin_nid, + size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, &eld->monitor_present, eld->eld_buffer, ELD_MAX_SIZE); if (size > 0) { @@ -1712,7 +1713,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, * skip pin setup and return 0 to make audio playback * be ongoing */ - intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid); + pin_cvt_fixup(codec, NULL, cvt_nid); snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format); mutex_unlock(&spec->pcm_lock); @@ -1725,23 +1726,21 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, } per_pin = get_pin(spec, pin_idx); pin_nid = per_pin->pin_nid; - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { - /* Verify pin:cvt selections to avoid silent audio after S3. - * After S3, the audio driver restores pin:cvt selections - * but this can happen before gfx is ready and such selection - * is overlooked by HW. Thus multiple pins can share a same - * default convertor and mute control will affect each other, - * which can cause a resumed audio playback become silent - * after S3. - */ - intel_verify_pin_cvt_connect(codec, per_pin); - intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx); - } + + /* Verify pin:cvt selections to avoid silent audio after S3. + * After S3, the audio driver restores pin:cvt selections + * but this can happen before gfx is ready and such selection + * is overlooked by HW. Thus multiple pins can share a same + * default convertor and mute control will affect each other, + * which can cause a resumed audio playback become silent + * after S3. + */ + pin_cvt_fixup(codec, per_pin, 0); /* Call sync_audio_rate to set the N/CTS/M manually if necessary */ /* Todo: add DP1.2 MST audio support later */ if (codec_has_acomp(codec)) - snd_hdac_sync_audio_rate(&codec->bus->core, pin_nid, runtime->rate); + snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate); non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); @@ -1838,6 +1837,18 @@ static const struct hda_pcm_ops generic_ops = { .cleanup = generic_hdmi_playback_pcm_cleanup, }; +static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) +{ + struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); + + if (!per_pin) + return 0; + + return per_pin->sink_eld.info.spk_alloc; +} + static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap) { @@ -2074,6 +2085,20 @@ static void hdmi_array_free(struct hdmi_spec *spec) snd_array_free(&spec->cvts); } +static void generic_spec_free(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + + if (spec) { + if (spec->i915_bound) + snd_hdac_i915_exit(&codec->bus->core); + hdmi_array_free(spec); + kfree(spec); + codec->spec = NULL; + } + codec->dp_mst = false; +} + static void generic_hdmi_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -2098,10 +2123,7 @@ static void generic_hdmi_free(struct hda_codec *codec) spec->pcm_rec[pcm_idx].jack = NULL; } - if (spec->i915_bound) - snd_hdac_i915_exit(&codec->bus->core); - hdmi_array_free(spec); - kfree(spec); + generic_spec_free(codec); } #ifdef CONFIG_PM @@ -2139,6 +2161,55 @@ static const struct hdmi_ops generic_standard_hdmi_ops = { .setup_stream = hdmi_setup_stream, }; +/* allocate codec->spec and assign/initialize generic parser ops */ +static int alloc_generic_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + + spec->ops = generic_standard_hdmi_ops; + mutex_init(&spec->pcm_lock); + snd_hdac_register_chmap_ops(&codec->core, &spec->chmap); + + spec->chmap.ops.get_chmap = hdmi_get_chmap; + spec->chmap.ops.set_chmap = hdmi_set_chmap; + spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached; + spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc, + + codec->spec = spec; + hdmi_array_init(spec, 4); + + codec->patch_ops = generic_hdmi_patch_ops; + + return 0; +} + +/* generic HDMI parser */ +static int patch_generic_hdmi(struct hda_codec *codec) +{ + int err; + + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + + err = hdmi_parse_codec(codec); + if (err < 0) { + generic_spec_free(codec); + return err; + } + + generic_hdmi_init_per_pins(codec); + return 0; +} + +/* + * Intel codec parsers and helpers + */ + static void intel_haswell_fixup_connect_list(struct hda_codec *codec, hda_nid_t nid) { @@ -2216,12 +2287,23 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, static void intel_pin_eld_notify(void *audio_ptr, int port) { struct hda_codec *codec = audio_ptr; - int pin_nid = port + 0x04; + int pin_nid; /* we assume only from port-B to port-D */ if (port < 1 || port > 3) return; + switch (codec->core.vendor_id) { + case 0x80860054: /* ILK */ + case 0x80862804: /* ILK */ + case 0x80862882: /* VLV */ + pin_nid = port + 0x03; + break; + default: + pin_nid = port + 0x04; + break; + } + /* skip notification during system suspend (but not in runtime PM); * the state will be updated at resume */ @@ -2234,93 +2316,159 @@ static void intel_pin_eld_notify(void *audio_ptr, int port) check_presence_and_report(codec, pin_nid); } -static int patch_generic_hdmi(struct hda_codec *codec) +/* register i915 component pin_eld_notify callback */ +static void register_i915_notifier(struct hda_codec *codec) { - struct hdmi_spec *spec; + struct hdmi_spec *spec = codec->spec; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + spec->use_acomp_notifier = true; + spec->i915_audio_ops.audio_ptr = codec; + /* intel_audio_codec_enable() or intel_audio_codec_disable() + * will call pin_eld_notify with using audio_ptr pointer + * We need make sure audio_ptr is really setup + */ + wmb(); + spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify; + snd_hdac_i915_register_notifier(&spec->i915_audio_ops); +} - spec->ops = generic_standard_hdmi_ops; - mutex_init(&spec->pcm_lock); - snd_hdac_register_chmap_ops(&codec->core, &spec->chmap); +/* setup_stream ops override for HSW+ */ +static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, + hda_nid_t pin_nid, u32 stream_tag, int format) +{ + haswell_verify_D0(codec, cvt_nid, pin_nid); + return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); +} - spec->chmap.ops.get_chmap = hdmi_get_chmap; - spec->chmap.ops.set_chmap = hdmi_set_chmap; - spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached; +/* pin_cvt_fixup ops override for HSW+ and VLV+ */ +static void i915_pin_cvt_fixup(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + hda_nid_t cvt_nid) +{ + if (per_pin) { + intel_verify_pin_cvt_connect(codec, per_pin); + intel_not_share_assigned_cvt(codec, per_pin->pin_nid, + per_pin->mux_idx); + } else { + intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid); + } +} - codec->spec = spec; - hdmi_array_init(spec, 4); +/* Intel Haswell and onwards; audio component with eld notifier */ +static int patch_i915_hsw_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; -#ifdef CONFIG_SND_HDA_I915 - /* Try to bind with i915 for Intel HSW+ codecs (if not done yet) */ - if ((codec->core.vendor_id >> 16) == 0x8086 && - is_haswell_plus(codec)) { -#if 0 - /* on-demand binding leads to an unbalanced refcount when - * both i915 and hda drivers are probed concurrently; - * disabled temporarily for now - */ - if (!codec->bus->core.audio_component) - if (!snd_hdac_i915_init(&codec->bus->core)) - spec->i915_bound = true; -#endif - /* use i915 audio component notifier for hotplug */ - if (codec->bus->core.audio_component) - spec->use_acomp_notifier = true; + /* HSW+ requires i915 binding */ + if (!codec->bus->core.audio_component) { + codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); + return -ENODEV; } -#endif - if (is_haswell_plus(codec)) { - intel_haswell_enable_all_pins(codec, true); - intel_haswell_fixup_enable_dp12(codec); - } + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + spec = codec->spec; - /* For Valleyview/Cherryview, only the display codec is in the display - * power well and can use link_power ops to request/release the power. - * For Haswell/Broadwell, the controller is also in the power well and + intel_haswell_enable_all_pins(codec, true); + intel_haswell_fixup_enable_dp12(codec); + + /* For Haswell/Broadwell, the controller is also in the power well and * can cover the codec power request, and so need not set this flag. - * For previous platforms, there is no such power well feature. */ - if (is_valleyview_plus(codec) || is_skylake(codec) || - is_broxton(codec)) + if (!is_haswell(codec) && !is_broadwell(codec)) codec->core.link_power_control = 1; - if (hdmi_parse_codec(codec) < 0) { - if (spec->i915_bound) - snd_hdac_i915_exit(&codec->bus->core); - codec->spec = NULL; - kfree(spec); - return -EINVAL; + codec->patch_ops.set_power_state = haswell_set_power_state; + codec->dp_mst = true; + codec->depop_delay = 0; + codec->auto_runtime_pm = 1; + + spec->ops.setup_stream = i915_hsw_setup_stream; + spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; + + err = hdmi_parse_codec(codec); + if (err < 0) { + generic_spec_free(codec); + return err; } - codec->patch_ops = generic_hdmi_patch_ops; - if (is_haswell_plus(codec)) { - codec->patch_ops.set_power_state = haswell_set_power_state; - codec->dp_mst = true; + + generic_hdmi_init_per_pins(codec); + register_i915_notifier(codec); + return 0; +} + +/* Intel Baytrail and Braswell; with eld notifier */ +static int patch_i915_byt_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + /* requires i915 binding */ + if (!codec->bus->core.audio_component) { + codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n"); + return -ENODEV; } - /* Enable runtime pm for HDMI audio codec of HSW/BDW/SKL/BYT/BSW */ - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) - codec->auto_runtime_pm = 1; + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + spec = codec->spec; - generic_hdmi_init_per_pins(codec); + /* For Valleyview/Cherryview, only the display codec is in the display + * power well and can use link_power ops to request/release the power. + */ + codec->core.link_power_control = 1; + codec->depop_delay = 0; + codec->auto_runtime_pm = 1; - if (codec_has_acomp(codec)) { - codec->depop_delay = 0; - spec->i915_audio_ops.audio_ptr = codec; - /* intel_audio_codec_enable() or intel_audio_codec_disable() - * will call pin_eld_notify with using audio_ptr pointer - * We need make sure audio_ptr is really setup - */ - wmb(); - spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify; - snd_hdac_i915_register_notifier(&spec->i915_audio_ops); + spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; + + err = hdmi_parse_codec(codec); + if (err < 0) { + generic_spec_free(codec); + return err; } - WARN_ON(spec->dyn_pcm_assign && !codec_has_acomp(codec)); + generic_hdmi_init_per_pins(codec); + register_i915_notifier(codec); + return 0; +} + +/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */ +static int patch_i915_cpt_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + /* no i915 component should have been bound before this */ + if (WARN_ON(codec->bus->core.audio_component)) + return -EBUSY; + + err = alloc_generic_hdmi(codec); + if (err < 0) + return err; + spec = codec->spec; + + /* Try to bind with i915 now */ + err = snd_hdac_i915_init(&codec->bus->core); + if (err < 0) + goto error; + spec->i915_bound = true; + + err = hdmi_parse_codec(codec); + if (err < 0) + goto error; + + generic_hdmi_init_per_pins(codec); + register_i915_notifier(codec); return 0; + + error: + generic_spec_free(codec); + return err; } /* @@ -3491,21 +3639,21 @@ HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi), HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_i915_cpt_hdmi), HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_i915_cpt_hdmi), +HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_i915_cpt_hdmi), +HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi), +HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_generic_hdmi), -HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), +HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI", patch_generic_hdmi), /* special ID for generic HDMI */ HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi), diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 8151318a69a2..9720a30dbfff 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -42,12 +42,6 @@ #include <asm/pgtable.h> #include <asm/cacheflush.h> -#ifdef CONFIG_KVM_GUEST -#include <linux/kvm_para.h> -#else -#define kvm_para_available() (0) -#endif - MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); MODULE_LICENSE("GPL"); @@ -2972,25 +2966,17 @@ static int snd_intel8x0_inside_vm(struct pci_dev *pci) goto fini; } - /* detect KVM and Parallels virtual environments */ - result = kvm_para_available(); -#ifdef X86_FEATURE_HYPERVISOR - result = result || boot_cpu_has(X86_FEATURE_HYPERVISOR); -#endif - if (!result) - goto fini; - /* check for known (emulated) devices */ + result = 0; if (pci->subsystem_vendor == PCI_SUBVENDOR_ID_REDHAT_QUMRANET && pci->subsystem_device == PCI_SUBDEVICE_ID_QEMU) { /* KVM emulated sound, PCI SSID: 1af4:1100 */ msg = "enable KVM"; + result = 1; } else if (pci->subsystem_vendor == 0x1ab8) { /* Parallels VM emulated sound, PCI SSID: 1ab8:xxxx */ msg = "enable Parallels VM"; - } else { - msg = "disable (unknown or VT-d) VM"; - result = 0; + result = 1; } fini: diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 4f85757009b3..2f8c388ef84f 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -45,6 +45,7 @@ #include <linux/bitops.h> #include <linux/init.h> #include <linux/list.h> +#include <linux/log2.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/usb.h> @@ -1378,6 +1379,71 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, snd_usb_mixer_add_control(&cval->head, kctl); } +static int parse_clock_source_unit(struct mixer_build *state, int unitid, + void *_ftr) +{ + struct uac_clock_source_descriptor *hdr = _ftr; + struct usb_mixer_elem_info *cval; + struct snd_kcontrol *kctl; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + int ret; + + if (state->mixer->protocol != UAC_VERSION_2) + return -EINVAL; + + if (hdr->bLength != sizeof(*hdr)) { + usb_audio_dbg(state->chip, + "Bogus clock source descriptor length of %d, ignoring.\n", + hdr->bLength); + return 0; + } + + /* + * The only property of this unit we are interested in is the + * clock source validity. If that isn't readable, just bail out. + */ + if (!uac2_control_is_readable(hdr->bmControls, + ilog2(UAC2_CS_CONTROL_CLOCK_VALID))) + return 0; + + cval = kzalloc(sizeof(*cval), GFP_KERNEL); + if (!cval) + return -ENOMEM; + + snd_usb_mixer_elem_init_std(&cval->head, state->mixer, hdr->bClockID); + + cval->min = 0; + cval->max = 1; + cval->channels = 1; + cval->val_type = USB_MIXER_BOOLEAN; + cval->control = UAC2_CS_CONTROL_CLOCK_VALID; + + if (uac2_control_is_writeable(hdr->bmControls, + ilog2(UAC2_CS_CONTROL_CLOCK_VALID))) + kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); + else { + cval->master_readonly = 1; + kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); + } + + if (!kctl) { + kfree(cval); + return -ENOMEM; + } + + kctl->private_free = snd_usb_mixer_elem_free; + ret = snd_usb_copy_string_desc(state, hdr->iClockSource, + name, sizeof(name)); + if (ret > 0) + snprintf(kctl->id.name, sizeof(kctl->id.name), + "%s Validity", name); + else + snprintf(kctl->id.name, sizeof(kctl->id.name), + "Clock Source %d Validity", hdr->bClockID); + + return snd_usb_mixer_add_control(&cval->head, kctl); +} + /* * parse a feature unit * @@ -2126,10 +2192,11 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) switch (p1[2]) { case UAC_INPUT_TERMINAL: - case UAC2_CLOCK_SOURCE: return 0; /* NOP */ case UAC_MIXER_UNIT: return parse_audio_mixer_unit(state, unitid, p1); + case UAC2_CLOCK_SOURCE: + return parse_clock_source_unit(state, unitid, p1); case UAC_SELECTOR_UNIT: case UAC2_CLOCK_SELECTOR: return parse_audio_selector_unit(state, unitid, p1); @@ -2307,6 +2374,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, __u8 unitid = (index >> 8) & 0xff; __u8 control = (value >> 8) & 0xff; __u8 channel = value & 0xff; + unsigned int count = 0; if (channel >= MAX_CHANNELS) { usb_audio_dbg(mixer->chip, @@ -2315,6 +2383,12 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, return; } + for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) + count++; + + if (count == 0) + return; + for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) { struct usb_mixer_elem_info *info; @@ -2322,7 +2396,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, continue; info = (struct usb_mixer_elem_info *)list; - if (info->control != control) + if (count > 1 && info->control != control) continue; switch (attribute) { diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 6178bb5d0731..24c7c2311b47 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1137,6 +1137,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ + case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */ case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ return true; } |