From d6e68c57e35b69b31d9fa5a61b37c840973db362 Mon Sep 17 00:00:00 2001 From: George Harker Date: Fri, 26 Feb 2021 21:24:56 +0000 Subject: ALSA: usb-audio: use usb headers rather than define structs locally Use struct definitions from linux/usb/midi.h rather than locally define the structs in sound/usb/midi.c. Signed-off-by: George Harker Link: https://lore.kernel.org/r/20210226212457.24538-1-george@george-graphics.co.uk Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 0c23fa6d8525..610cf54eefd9 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -77,23 +78,6 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("USB Audio/MIDI helper module"); MODULE_LICENSE("Dual BSD/GPL"); - -struct usb_ms_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bcdMSC[2]; - __le16 wTotalLength; -} __attribute__ ((packed)); - -struct usb_ms_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bNumEmbMIDIJack; - __u8 baAssocJackID[]; -} __attribute__ ((packed)); - struct snd_usb_midi_in_endpoint; struct snd_usb_midi_out_endpoint; struct snd_usb_midi_endpoint; @@ -1875,7 +1859,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, ms_header->bDescriptorType == USB_DT_CS_INTERFACE && ms_header->bDescriptorSubtype == UAC_HEADER) dev_dbg(&umidi->dev->dev, "MIDIStreaming version %02x.%02x\n", - ms_header->bcdMSC[1], ms_header->bcdMSC[0]); + ((uint8_t *)&ms_header->bcdMSC)[1], ((uint8_t *)&ms_header->bcdMSC)[0]); else dev_warn(&umidi->dev->dev, "MIDIStreaming interface descriptor not found\n"); -- cgit v1.2.3-58-ga151 From eb596e0fd13c83b4a66559a45b57b71aac340d30 Mon Sep 17 00:00:00 2001 From: George Harker Date: Fri, 26 Feb 2021 21:26:16 +0000 Subject: ALSA: usb-audio: generate midi streaming substream names from jack names A number of devices have named substreams which are hard to remember / decypher from MIDI n names. Eg. Korg puts a pass through on one substream and iConnectivity devices name the connections. This makes it easier to connect to the correct device. Devices which handle naming through quirks are unaffected by this change. Addresses TODO comment in sound/usb/midi.c Signed-off-by: George Harker Link: https://lore.kernel.org/r/20210226212617.24616-1-george@george-graphics.co.uk Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- sound/usb/midi.h | 2 ++ 2 files changed, 100 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 610cf54eefd9..9efda4b06acb 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1740,12 +1740,68 @@ static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number, } } +static struct usb_midi_in_jack_descriptor *find_usb_in_jack_descriptor( + struct usb_host_interface *hostif, uint8_t jack_id) +{ + unsigned char *extra = hostif->extra; + int extralen = hostif->extralen; + + while (extralen > 4) { + struct usb_midi_in_jack_descriptor *injd = + (struct usb_midi_in_jack_descriptor *)extra; + + if (injd->bLength > 4 && + injd->bDescriptorType == USB_DT_CS_INTERFACE && + injd->bDescriptorSubtype == UAC_MIDI_IN_JACK && + injd->bJackID == jack_id) + return injd; + if (!extra[0]) + break; + extralen -= extra[0]; + extra += extra[0]; + } + return NULL; +} + +static struct usb_midi_out_jack_descriptor *find_usb_out_jack_descriptor( + struct usb_host_interface *hostif, uint8_t jack_id) +{ + unsigned char *extra = hostif->extra; + int extralen = hostif->extralen; + + while (extralen > 4) { + struct usb_midi_out_jack_descriptor *outjd = + (struct usb_midi_out_jack_descriptor *)extra; + + if (outjd->bLength > 4 && + outjd->bDescriptorType == USB_DT_CS_INTERFACE && + outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK && + outjd->bJackID == jack_id) + return outjd; + if (!extra[0]) + break; + extralen -= extra[0]; + extra += extra[0]; + } + return NULL; +} + static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, - int stream, int number, + int stream, int number, int jack_id, struct snd_rawmidi_substream **rsubstream) { struct port_info *port_info; const char *name_format; + struct usb_interface *intf; + struct usb_host_interface *hostif; + struct usb_midi_in_jack_descriptor *injd; + struct usb_midi_out_jack_descriptor *outjd; + uint8_t jack_name_buf[32]; + uint8_t *default_jack_name = "MIDI"; + uint8_t *jack_name = default_jack_name; + uint8_t iJack; + size_t sz; + int res; struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number); @@ -1755,11 +1811,36 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, return; } - /* TODO: read port name from jack descriptor */ + intf = umidi->iface; + if (intf && jack_id >= 0) { + hostif = intf->cur_altsetting; + iJack = 0; + if (stream != SNDRV_RAWMIDI_STREAM_OUTPUT) { + /* in jacks connect to outs */ + outjd = find_usb_out_jack_descriptor(hostif, jack_id); + if (outjd) { + sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins); + iJack = *(((uint8_t *) outjd) + sz - sizeof(uint8_t)); + } + } else { + /* and out jacks connect to ins */ + injd = find_usb_in_jack_descriptor(hostif, jack_id); + if (injd) + iJack = injd->iJack; + } + if (iJack != 0) { + res = usb_string(umidi->dev, iJack, jack_name_buf, + ARRAY_SIZE(jack_name_buf)); + if (res) + jack_name = jack_name_buf; + } + } + port_info = find_port_info(umidi, number); - name_format = port_info ? port_info->name : "%s MIDI %d"; + name_format = port_info ? port_info->name : + (jack_name != default_jack_name ? "%s %s" : "%s %s %d"); snprintf(substream->name, sizeof(substream->name), - name_format, umidi->card->shortname, number + 1); + name_format, umidi->card->shortname, jack_name, number + 1); *rsubstream = substream; } @@ -1794,6 +1875,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi *umidi, snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, out_ports, + endpoints[i].assoc_out_jacks[j], &umidi->endpoints[i].out->ports[j].substream); ++out_ports; } @@ -1801,6 +1883,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi *umidi, snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, in_ports, + endpoints[i].assoc_in_jacks[j], &umidi->endpoints[i].in->ports[j].substream); ++in_ports; } @@ -1846,7 +1929,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, struct usb_host_endpoint *hostep; struct usb_endpoint_descriptor *ep; struct usb_ms_endpoint_descriptor *ms_ep; - int i, epidx; + int i, j, epidx; intf = umidi->iface; if (!intf) @@ -1895,6 +1978,10 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, endpoints[epidx].out_interval = 1; endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; + for (j = 0; j < ms_ep->bNumEmbMIDIJack; ++j) + endpoints[epidx].assoc_out_jacks[j] = ms_ep->baAssocJackID[j]; + for (; j < ARRAY_SIZE(endpoints[epidx].assoc_out_jacks); ++j) + endpoints[epidx].assoc_out_jacks[j] = -1; dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); } else { @@ -1912,6 +1999,10 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; + for (j = 0; j < ms_ep->bNumEmbMIDIJack; ++j) + endpoints[epidx].assoc_in_jacks[j] = ms_ep->baAssocJackID[j]; + for (; j < ARRAY_SIZE(endpoints[epidx].assoc_in_jacks); ++j) + endpoints[epidx].assoc_in_jacks[j] = -1; dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); } @@ -2228,11 +2319,13 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi *umidi, snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable, + -1 /* prevent trying to find jack */, &umidi->endpoints[cable & 1].out->ports[cable].substream); if (endpoint->in_cables & (1 << cable)) snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, cable, + -1 /* prevent trying to find jack */, &umidi->endpoints[0].in->ports[cable].substream); } return 0; diff --git a/sound/usb/midi.h b/sound/usb/midi.h index 8c38aec22999..3f153195c841 100644 --- a/sound/usb/midi.h +++ b/sound/usb/midi.h @@ -13,6 +13,8 @@ struct snd_usb_midi_endpoint_info { uint8_t in_interval; uint16_t out_cables; /* bitmask */ uint16_t in_cables; /* bitmask */ + int16_t assoc_in_jacks[16]; + int16_t assoc_out_jacks[16]; }; /* for QUIRK_MIDI_YAMAHA, data is NULL */ -- cgit v1.2.3-58-ga151 From a3c30b0cb6d05f5bf66d1a5d42e876f31753a447 Mon Sep 17 00:00:00 2001 From: Nicolas MURE Date: Mon, 1 Mar 2021 16:27:26 +0100 Subject: ALSA: usb-audio: Add Pioneer DJM-850 to quirks-table Declare the Pioneer DJM-850 interfaces for capture and playback. See https://github.com/nm2107/Pioneer-DJM-850-driver-reverse-engineering/blob/172fb9a61055960c88c67b7c416fe5bf3609807b/doc/usb-device-specifications.md for the complete device spec. Signed-off-by: Nicolas MURE Link: https://lore.kernel.org/r/20210301152729.18094-2-nicolas.mure2019@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 1165a5ac60f2..9716a9f7c095 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3817,6 +3817,69 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } } }, +{ + /* + * Pioneer DJ DJM-850 + * 8 channels playback and 8 channels capture @ 44.1/48/96kHz S24LE + * Playback on EP 0x05 + * Capture on EP 0x86 + */ + USB_DEVICE_VENDOR_SPEC(0x08e4, 0x0163), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x05, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_DATA, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x86, + .ep_idx = 1, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_DATA, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, + { + .ifnum = -1 + } + } + } +}, { /* * Pioneer DJ DJM-450 -- cgit v1.2.3-58-ga151 From 7687850b95b4883b7a4778be45576d8288603ee6 Mon Sep 17 00:00:00 2001 From: Nicolas MURE Date: Mon, 1 Mar 2021 16:27:27 +0100 Subject: ALSA: usb-audio: Declare Pioneer DJM-850 mixer controls Declare audio capture controls to choose the audio source, and also to set the capture level (in dB). See https://github.com/nm2107/Pioneer-DJM-850-driver-reverse-engineering/blob/172fb9a61055960c88c67b7c416fe5bf3609807b/doc/windows-djm-850-setting-utility/mixer-output-tab/README.md Signed-off-by: Nicolas MURE Link: https://lore.kernel.org/r/20210301152729.18094-3-nicolas.mure2019@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 08873d2afe4d..b325b6597d91 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2649,9 +2649,11 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_DEVICE_SHIFT 24 // device table index +// used for the snd_djm_devices table, so please update accordingly #define SND_DJM_250MK2_IDX 0x0 #define SND_DJM_750_IDX 0x1 -#define SND_DJM_900NXS2_IDX 0x2 +#define SND_DJM_850_IDX 0x2 +#define SND_DJM_900NXS2_IDX 0x3 #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ @@ -2733,11 +2735,12 @@ static const char *snd_djm_get_label(u16 wvalue, u16 windex) } }; - -// DJM-250MK2 +// common DJM capture level option values static const u16 snd_djm_opts_cap_level[] = { 0x0000, 0x0100, 0x0200, 0x0300 }; + +// DJM-250MK2 static const u16 snd_djm_opts_250mk2_cap1[] = { 0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a }; @@ -2781,6 +2784,25 @@ static const struct snd_djm_ctl snd_djm_ctls_750[] = { }; +// DJM-850 +static const u16 snd_djm_opts_850_cap1[] = { + 0x0100, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f }; +static const u16 snd_djm_opts_850_cap2[] = { + 0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f }; +static const u16 snd_djm_opts_850_cap3[] = { + 0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f }; +static const u16 snd_djm_opts_850_cap4[] = { + 0x0400, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; + +static const struct snd_djm_ctl snd_djm_ctls_850[] = { + SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Ch1 Input", 850_cap1, 1, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch2 Input", 850_cap2, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch3 Input", 850_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch4 Input", 850_cap4, 1, SND_DJM_WINDEX_CAP) +}; + + // DJM-900NXS2 static const u16 snd_djm_opts_900nxs2_cap1[] = { 0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a }; @@ -2806,6 +2828,7 @@ static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = { static const struct snd_djm_device snd_djm_devices[] = { SND_DJM_DEVICE(250mk2), SND_DJM_DEVICE(750), + SND_DJM_DEVICE(850), SND_DJM_DEVICE(900nxs2) }; @@ -3045,6 +3068,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */ err = snd_djm_controls_create(mixer, SND_DJM_750_IDX); break; + case USB_ID(0x08e4, 0x0163): /* Pioneer DJ DJM-850 */ + err = snd_djm_controls_create(mixer, SND_DJM_850_IDX); + break; case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX); break; -- cgit v1.2.3-58-ga151 From 1a2a94a4392d5d1e5e25cc127573452f4c7fa9b8 Mon Sep 17 00:00:00 2001 From: Nicolas MURE Date: Mon, 1 Mar 2021 16:27:28 +0100 Subject: ALSA: usb-audio: Configure Pioneer DJM-850 samplerate Send an `URB_CONTROL out` USB frame to the device to configure its samplerate. This should be done before using the device for audio streaming (capture or playback). See https://github.com/nm2107/Pioneer-DJM-850-driver-reverse-engineering/blob/172fb9a61055960c88c67b7c416fe5bf3609807b/doc/windows-dvs/framerate-setting/README.md Signed-off-by: Nicolas MURE Link: https://lore.kernel.org/r/20210301152729.18094-4-nicolas.mure2019@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 737b2729c0d3..d02dac5fcd40 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1503,6 +1503,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */ pioneer_djm_set_format_quirk(subs, 0x0082); break; + case USB_ID(0x08e4, 0x0163): /* Pioneer DJM-850 */ + pioneer_djm_set_format_quirk(subs, 0x0086); + break; } } -- cgit v1.2.3-58-ga151 From b8db8be812cb2c08cd8f6d12c6c773c198be83f1 Mon Sep 17 00:00:00 2001 From: Nicolas MURE Date: Mon, 1 Mar 2021 16:27:29 +0100 Subject: ALSA: usb-audio: fix Pioneer DJM-850 control label info Unlike the other DJM, the value to set the "CD/LINE" and "LINE" capture control options are inverted. This fix makes sure that the displayed info label while using `alsamixer` matches the input switches label on the DJM-850 mixer. Signed-off-by: Nicolas MURE Link: https://lore.kernel.org/r/20210301152729.18094-5-nicolas.mure2019@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index b325b6597d91..5b77e8140ba6 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2693,7 +2693,7 @@ static const char *snd_djm_get_label_caplevel(u16 wvalue) } }; -static const char *snd_djm_get_label_cap(u16 wvalue) +static const char *snd_djm_get_label_cap_common(u16 wvalue) { switch (wvalue & 0x00ff) { case SND_DJM_CAP_LINE: return "Control Tone LINE"; @@ -2715,6 +2715,25 @@ static const char *snd_djm_get_label_cap(u16 wvalue) } }; +// The DJM-850 has different values for CD/LINE and LINE capture +// control options than the other DJM declared in this file. +static const char *snd_djm_get_label_cap_850(u16 wvalue) +{ + switch (wvalue & 0x00ff) { + case 0x00: return "Control Tone CD/LINE"; + case 0x01: return "Control Tone LINE"; + default: return snd_djm_get_label_cap_common(wvalue); + } +}; + +static const char *snd_djm_get_label_cap(u8 device_idx, u16 wvalue) +{ + switch (device_idx) { + case SND_DJM_850_IDX: return snd_djm_get_label_cap_850(wvalue); + default: return snd_djm_get_label_cap_common(wvalue); + } +}; + static const char *snd_djm_get_label_pb(u16 wvalue) { switch (wvalue & 0x00ff) { @@ -2725,11 +2744,11 @@ static const char *snd_djm_get_label_pb(u16 wvalue) } }; -static const char *snd_djm_get_label(u16 wvalue, u16 windex) +static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) { switch (windex) { case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(wvalue); - case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(wvalue); + case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(device_idx, wvalue); case SND_DJM_WINDEX_PB: return snd_djm_get_label_pb(wvalue); default: return NULL; } @@ -2852,7 +2871,8 @@ static int snd_djm_controls_info(struct snd_kcontrol *kctl, if (info->value.enumerated.item >= noptions) info->value.enumerated.item = noptions - 1; - name = snd_djm_get_label(ctl->options[info->value.enumerated.item], + name = snd_djm_get_label(device_idx, + ctl->options[info->value.enumerated.item], ctl->wIndex); if (!name) return -EINVAL; -- cgit v1.2.3-58-ga151 From d49c3e711c2b79841bc5c5cf5b46144bb681e380 Mon Sep 17 00:00:00 2001 From: dingsenjie Date: Tue, 2 Mar 2021 11:40:53 +0800 Subject: ALSA: ps3: fix spelling typo of values vaules -> values Signed-off-by: dingsenjie Link: https://lore.kernel.org/r/20210302034053.34524-1-dingsenjie@163.com Signed-off-by: Takashi Iwai --- sound/ppc/snd_ps3_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/ppc/snd_ps3_reg.h b/sound/ppc/snd_ps3_reg.h index 566a3189766d..e2212b79335c 100644 --- a/sound/ppc/snd_ps3_reg.h +++ b/sound/ppc/snd_ps3_reg.h @@ -308,7 +308,7 @@ Indicates Interrupt status, which interrupt has occurred, and can clear each interrupt in this register. Writing 1b to a field containing 1b clears field and de-asserts interrupt. Writing 0b to a field has no effect. -Field vaules are the following: +Field values are the following: 0 - Interrupt hasn't occurred. 1 - Interrupt has occurred. -- cgit v1.2.3-58-ga151 From 60fd71150391cf6be0276f3be1e71f7196547302 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:54:28 -0600 Subject: ALSA: vx: fix kernel-doc warning make W=1 warning: sound/drivers/vx/vx_core.c:410: warning: expecting prototype for snd_vx_boot_xilinx(). Prototype was for snd_vx_load_boot_image() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302215430.87309-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index d5c65cab195b..a22e5b1a5458 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -402,7 +402,7 @@ int vx_send_rih(struct vx_core *chip, int cmd) #define END_OF_RESET_WAIT_TIME 500 /* us */ /** - * snd_vx_boot_xilinx - boot up the xilinx interface + * snd_vx_load_boot_image - boot up the xilinx interface * @chip: VX core instance * @boot: the boot record to load */ -- cgit v1.2.3-58-ga151 From 06495facbb05126017b2badb78d747a0c5d53295 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:54:29 -0600 Subject: ALSA: pci: mixart: fix kernel-doc warning make W=1 warning: sound/pci/mixart/mixart_hwdep.c:36: warning: expecting prototype for exit with a timeout(). Prototype was for mixart_wait_nice_for_register_value() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302215430.87309-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart_hwdep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index 13dcb2fd0a85..f579f7698bba 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -22,7 +22,8 @@ /** - * wait for a value on a peudo register, exit with a timeout + * mixart_wait_nice_for_register_value - wait for a value on a peudo register, + * exit with a timeout * * @mgr: pointer to miXart manager structure * @offset: unsigned pseudo_register base + offset of value -- cgit v1.2.3-58-ga151 From 2c48653c1bc3aa6894e45e6037c7693949008816 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:54:30 -0600 Subject: ALSA: pci: vx222: fix kernel-doc warning make W=1 warnings: sound/pci/vx222/vx222_ops.c:86: warning: expecting prototype for snd_vx_inb(). Prototype was for vx2_inb() instead sound/pci/vx222/vx222_ops.c:97: warning: expecting prototype for snd_vx_outb(). Prototype was for vx2_outb() instead sound/pci/vx222/vx222_ops.c:110: warning: expecting prototype for snd_vx_inl(). Prototype was for vx2_inl() instead sound/pci/vx222/vx222_ops.c:121: warning: expecting prototype for snd_vx_outl(). Prototype was for vx2_outl() instead sound/pci/vx222/vx222_ops.c:221: warning: expecting prototype for vx_setup_pseudo_dma(). Prototype was for vx2_setup_pseudo_dma() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302215430.87309-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/vx222/vx222_ops.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 23d4338dc553..a05537202738 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -78,7 +78,7 @@ static inline unsigned long vx2_reg_addr(struct vx_core *_chip, int reg) } /** - * snd_vx_inb - read a byte from the register + * vx2_inb - read a byte from the register * @chip: VX core instance * @offset: register enum */ @@ -88,7 +88,7 @@ static unsigned char vx2_inb(struct vx_core *chip, int offset) } /** - * snd_vx_outb - write a byte on the register + * vx2_outb - write a byte on the register * @chip: VX core instance * @offset: the register offset * @val: the value to write @@ -102,7 +102,7 @@ static void vx2_outb(struct vx_core *chip, int offset, unsigned char val) } /** - * snd_vx_inl - read a 32bit word from the register + * vx2_inl - read a 32bit word from the register * @chip: VX core instance * @offset: register enum */ @@ -112,7 +112,7 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset) } /** - * snd_vx_outl - write a 32bit word on the register + * vx2_outl - write a 32bit word on the register * @chip: VX core instance * @offset: the register enum * @val: the value to write @@ -213,7 +213,7 @@ static int vx2_test_xilinx(struct vx_core *_chip) /** - * vx_setup_pseudo_dma - set up the pseudo dma read/write mode. + * vx2_setup_pseudo_dma - set up the pseudo dma read/write mode. * @chip: VX core instance * @do_write: 0 = read, 1 = set up for DMA write */ -- cgit v1.2.3-58-ga151 From 04f7791b7a4ba6ff3f53b3f3978b353924d10e78 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Fri, 5 Mar 2021 17:26:08 +0800 Subject: ALSA: hda - bind headset buttons to the headphone jack With the HDA driver, if the headset buttons are supported, an audio Jack will be created for them. This audio Jack is a bit confusing to users since it can't report headphone/mic insertion events but it claims to support these events. And in addition, the driver already builds a headphone Jack and a mic Jack, and most of those buttons are used for headphone playback, so do some change to bind those buttons to the headphone Jack. After this change, the key events are generated from NID 0x55, and are reported to the input layer via headphone jack (NID 0x21). If there is no headphone Jack, then build an audio jack to support those buttons same as previously. Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20210305092608.109599-1-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_jack.c | 73 ++++++++++++++++++++++++++++++++++++++++++- sound/pci/hda/hda_jack.h | 8 +++++ sound/pci/hda/patch_realtek.c | 15 ++++++--- 3 files changed, 91 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index b8b568046592..30e9ebf1f341 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -388,6 +388,69 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, } EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); +/** + * snd_hda_jack_bind_keymap - bind keys generated from one NID to another jack. + * @codec: the HDA codec + * @key_nid: key event is generated by this pin NID + * @keymap: map of key type and key code + * @jack_nid: key reports to the jack of this pin NID + * + * This function is used in the case of key is generated from one NID while is + * reported to the jack of another NID. + */ +int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid, + const struct hda_jack_keymap *keymap, + hda_nid_t jack_nid) +{ + const struct hda_jack_keymap *map; + struct hda_jack_tbl *key_gen = snd_hda_jack_tbl_get(codec, key_nid); + struct hda_jack_tbl *report_to = snd_hda_jack_tbl_get(codec, jack_nid); + + WARN_ON(codec->dp_mst); + + if (!key_gen || !report_to || !report_to->jack) + return -EINVAL; + + key_gen->key_report_jack = jack_nid; + + if (keymap) + for (map = keymap; map->type; map++) + snd_jack_set_key(report_to->jack, map->type, map->key); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_jack_bind_keymap); + +/** + * snd_hda_jack_set_button_state - report button event to the hda_jack_tbl button_state. + * @codec: the HDA codec + * @jack_nid: the button event reports to the jack_tbl of this NID + * @button_state: the button event captured by codec + * + * Codec driver calls this function to report the button event. + */ +void snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid, + int button_state) +{ + struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, jack_nid); + + if (!jack) + return; + + if (jack->key_report_jack) { + struct hda_jack_tbl *report_to = + snd_hda_jack_tbl_get(codec, jack->key_report_jack); + + if (report_to) { + report_to->button_state = button_state; + return; + } + } + + jack->button_state = button_state; +} +EXPORT_SYMBOL_GPL(snd_hda_jack_set_button_state); + /** * snd_hda_jack_report_sync - sync the states of all jacks and report if changed * @codec: the HDA codec @@ -651,7 +714,15 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) } if (!event) return; - event->jack_dirty = 1; + + if (event->key_report_jack) { + struct hda_jack_tbl *report_to = + snd_hda_jack_tbl_get_mst(codec, event->key_report_jack, + event->dev_id); + if (report_to) + report_to->jack_dirty = 1; + } else + event->jack_dirty = 1; call_jack_callback(codec, res, event); snd_hda_jack_report_sync(codec); diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 8ceaf0ef5df1..2abf7aac243a 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -40,6 +40,7 @@ struct hda_jack_tbl { unsigned int block_report:1; /* in a transitional state - do not report to userspace */ hda_nid_t gating_jack; /* valid when gating jack plugged */ hda_nid_t gated_jack; /* gated is dependent on this jack */ + hda_nid_t key_report_jack; /* key reports to this jack */ int type; int button_state; struct snd_jack *jack; @@ -99,6 +100,13 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid); +int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid, + const struct hda_jack_keymap *keymap, + hda_nid_t jack_nid); + +void snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid, + int button_state); + u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id); /* the jack state returned from snd_hda_jack_detect_state() */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4871507cd4bf..ee8d70afe636 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3102,7 +3102,7 @@ static void alc_headset_btn_callback(struct hda_codec *codec, if (jack->unsol_res & (7 << 10)) report |= SND_JACK_BTN_3; - jack->jack->button_state = report; + snd_hda_jack_set_button_state(codec, jack->nid, report); } static void alc_disable_headset_jack_key(struct hda_codec *codec) @@ -3163,16 +3163,23 @@ static void alc_fixup_headset_jack(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: spec->has_hs_key = 1; snd_hda_jack_detect_enable_callback(codec, 0x55, alc_headset_btn_callback); - snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false, - SND_JACK_HEADSET, alc_headset_btn_keymap); break; - case HDA_FIXUP_ACT_INIT: + case HDA_FIXUP_ACT_BUILD: + hp_pin = alc_get_hp_pin(spec); + if (!hp_pin || snd_hda_jack_bind_keymap(codec, 0x55, + alc_headset_btn_keymap, + hp_pin)) + snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", + false, SND_JACK_HEADSET, + alc_headset_btn_keymap); + alc_enable_headset_jack_key(codec); break; } -- cgit v1.2.3-58-ga151 From de3a9980d8c34b2479173e809afa820473db676a Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:02 +0100 Subject: ALSA: virtio: add virtio sound driver Introduce skeleton of the virtio sound driver. The driver implements the virtio sound device specification, which has become part of the virtio standard. Initial initialization of the device, virtqueues and creation of an empty ALSA sound device. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-3-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- MAINTAINERS | 9 ++ include/uapi/linux/virtio_snd.h | 334 ++++++++++++++++++++++++++++++++++++++++ sound/Kconfig | 2 + sound/Makefile | 3 +- sound/virtio/Kconfig | 10 ++ sound/virtio/Makefile | 7 + sound/virtio/virtio_card.c | 324 ++++++++++++++++++++++++++++++++++++++ sound/virtio/virtio_card.h | 65 ++++++++ 8 files changed, 753 insertions(+), 1 deletion(-) create mode 100644 include/uapi/linux/virtio_snd.h create mode 100644 sound/virtio/Kconfig create mode 100644 sound/virtio/Makefile create mode 100644 sound/virtio/virtio_card.c create mode 100644 sound/virtio/virtio_card.h (limited to 'sound') diff --git a/MAINTAINERS b/MAINTAINERS index d92f85ca831d..a68c543c28f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19086,6 +19086,15 @@ W: https://virtio-mem.gitlab.io/ F: drivers/virtio/virtio_mem.c F: include/uapi/linux/virtio_mem.h +VIRTIO SOUND DRIVER +M: Anton Yakovlev +M: "Michael S. Tsirkin" +L: virtualization@lists.linux-foundation.org +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: include/uapi/linux/virtio_snd.h +F: sound/virtio/* + VIRTUAL BOX GUEST DEVICE DRIVER M: Hans de Goede M: Arnd Bergmann diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h new file mode 100644 index 000000000000..dfe49547a7b0 --- /dev/null +++ b/include/uapi/linux/virtio_snd.h @@ -0,0 +1,334 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (C) 2021 OpenSynergy GmbH + */ +#ifndef VIRTIO_SND_IF_H +#define VIRTIO_SND_IF_H + +#include + +/******************************************************************************* + * CONFIGURATION SPACE + */ +struct virtio_snd_config { + /* # of available physical jacks */ + __le32 jacks; + /* # of available PCM streams */ + __le32 streams; + /* # of available channel maps */ + __le32 chmaps; +}; + +enum { + /* device virtqueue indexes */ + VIRTIO_SND_VQ_CONTROL = 0, + VIRTIO_SND_VQ_EVENT, + VIRTIO_SND_VQ_TX, + VIRTIO_SND_VQ_RX, + /* # of device virtqueues */ + VIRTIO_SND_VQ_MAX +}; + +/******************************************************************************* + * COMMON DEFINITIONS + */ + +/* supported dataflow directions */ +enum { + VIRTIO_SND_D_OUTPUT = 0, + VIRTIO_SND_D_INPUT +}; + +enum { + /* jack control request types */ + VIRTIO_SND_R_JACK_INFO = 1, + VIRTIO_SND_R_JACK_REMAP, + + /* PCM control request types */ + VIRTIO_SND_R_PCM_INFO = 0x0100, + VIRTIO_SND_R_PCM_SET_PARAMS, + VIRTIO_SND_R_PCM_PREPARE, + VIRTIO_SND_R_PCM_RELEASE, + VIRTIO_SND_R_PCM_START, + VIRTIO_SND_R_PCM_STOP, + + /* channel map control request types */ + VIRTIO_SND_R_CHMAP_INFO = 0x0200, + + /* jack event types */ + VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000, + VIRTIO_SND_EVT_JACK_DISCONNECTED, + + /* PCM event types */ + VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100, + VIRTIO_SND_EVT_PCM_XRUN, + + /* common status codes */ + VIRTIO_SND_S_OK = 0x8000, + VIRTIO_SND_S_BAD_MSG, + VIRTIO_SND_S_NOT_SUPP, + VIRTIO_SND_S_IO_ERR +}; + +/* common header */ +struct virtio_snd_hdr { + __le32 code; +}; + +/* event notification */ +struct virtio_snd_event { + /* VIRTIO_SND_EVT_XXX */ + struct virtio_snd_hdr hdr; + /* optional event data */ + __le32 data; +}; + +/* common control request to query an item information */ +struct virtio_snd_query_info { + /* VIRTIO_SND_R_XXX_INFO */ + struct virtio_snd_hdr hdr; + /* item start identifier */ + __le32 start_id; + /* item count to query */ + __le32 count; + /* item information size in bytes */ + __le32 size; +}; + +/* common item information header */ +struct virtio_snd_info { + /* function group node id (High Definition Audio Specification 7.1.2) */ + __le32 hda_fn_nid; +}; + +/******************************************************************************* + * JACK CONTROL MESSAGES + */ +struct virtio_snd_jack_hdr { + /* VIRTIO_SND_R_JACK_XXX */ + struct virtio_snd_hdr hdr; + /* 0 ... virtio_snd_config::jacks - 1 */ + __le32 jack_id; +}; + +/* supported jack features */ +enum { + VIRTIO_SND_JACK_F_REMAP = 0 +}; + +struct virtio_snd_jack_info { + /* common header */ + struct virtio_snd_info hdr; + /* supported feature bit map (1 << VIRTIO_SND_JACK_F_XXX) */ + __le32 features; + /* pin configuration (High Definition Audio Specification 7.3.3.31) */ + __le32 hda_reg_defconf; + /* pin capabilities (High Definition Audio Specification 7.3.4.9) */ + __le32 hda_reg_caps; + /* current jack connection status (0: disconnected, 1: connected) */ + __u8 connected; + + __u8 padding[7]; +}; + +/* jack remapping control request */ +struct virtio_snd_jack_remap { + /* .code = VIRTIO_SND_R_JACK_REMAP */ + struct virtio_snd_jack_hdr hdr; + /* selected association number */ + __le32 association; + /* selected sequence number */ + __le32 sequence; +}; + +/******************************************************************************* + * PCM CONTROL MESSAGES + */ +struct virtio_snd_pcm_hdr { + /* VIRTIO_SND_R_PCM_XXX */ + struct virtio_snd_hdr hdr; + /* 0 ... virtio_snd_config::streams - 1 */ + __le32 stream_id; +}; + +/* supported PCM stream features */ +enum { + VIRTIO_SND_PCM_F_SHMEM_HOST = 0, + VIRTIO_SND_PCM_F_SHMEM_GUEST, + VIRTIO_SND_PCM_F_MSG_POLLING, + VIRTIO_SND_PCM_F_EVT_SHMEM_PERIODS, + VIRTIO_SND_PCM_F_EVT_XRUNS +}; + +/* supported PCM sample formats */ +enum { + /* analog formats (width / physical width) */ + VIRTIO_SND_PCM_FMT_IMA_ADPCM = 0, /* 4 / 4 bits */ + VIRTIO_SND_PCM_FMT_MU_LAW, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_A_LAW, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_S8, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_U8, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_S16, /* 16 / 16 bits */ + VIRTIO_SND_PCM_FMT_U16, /* 16 / 16 bits */ + VIRTIO_SND_PCM_FMT_S18_3, /* 18 / 24 bits */ + VIRTIO_SND_PCM_FMT_U18_3, /* 18 / 24 bits */ + VIRTIO_SND_PCM_FMT_S20_3, /* 20 / 24 bits */ + VIRTIO_SND_PCM_FMT_U20_3, /* 20 / 24 bits */ + VIRTIO_SND_PCM_FMT_S24_3, /* 24 / 24 bits */ + VIRTIO_SND_PCM_FMT_U24_3, /* 24 / 24 bits */ + VIRTIO_SND_PCM_FMT_S20, /* 20 / 32 bits */ + VIRTIO_SND_PCM_FMT_U20, /* 20 / 32 bits */ + VIRTIO_SND_PCM_FMT_S24, /* 24 / 32 bits */ + VIRTIO_SND_PCM_FMT_U24, /* 24 / 32 bits */ + VIRTIO_SND_PCM_FMT_S32, /* 32 / 32 bits */ + VIRTIO_SND_PCM_FMT_U32, /* 32 / 32 bits */ + VIRTIO_SND_PCM_FMT_FLOAT, /* 32 / 32 bits */ + VIRTIO_SND_PCM_FMT_FLOAT64, /* 64 / 64 bits */ + /* digital formats (width / physical width) */ + VIRTIO_SND_PCM_FMT_DSD_U8, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_DSD_U16, /* 16 / 16 bits */ + VIRTIO_SND_PCM_FMT_DSD_U32, /* 32 / 32 bits */ + VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME /* 32 / 32 bits */ +}; + +/* supported PCM frame rates */ +enum { + VIRTIO_SND_PCM_RATE_5512 = 0, + VIRTIO_SND_PCM_RATE_8000, + VIRTIO_SND_PCM_RATE_11025, + VIRTIO_SND_PCM_RATE_16000, + VIRTIO_SND_PCM_RATE_22050, + VIRTIO_SND_PCM_RATE_32000, + VIRTIO_SND_PCM_RATE_44100, + VIRTIO_SND_PCM_RATE_48000, + VIRTIO_SND_PCM_RATE_64000, + VIRTIO_SND_PCM_RATE_88200, + VIRTIO_SND_PCM_RATE_96000, + VIRTIO_SND_PCM_RATE_176400, + VIRTIO_SND_PCM_RATE_192000, + VIRTIO_SND_PCM_RATE_384000 +}; + +struct virtio_snd_pcm_info { + /* common header */ + struct virtio_snd_info hdr; + /* supported feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */ + __le32 features; + /* supported sample format bit map (1 << VIRTIO_SND_PCM_FMT_XXX) */ + __le64 formats; + /* supported frame rate bit map (1 << VIRTIO_SND_PCM_RATE_XXX) */ + __le64 rates; + /* dataflow direction (VIRTIO_SND_D_XXX) */ + __u8 direction; + /* minimum # of supported channels */ + __u8 channels_min; + /* maximum # of supported channels */ + __u8 channels_max; + + __u8 padding[5]; +}; + +/* set PCM stream format */ +struct virtio_snd_pcm_set_params { + /* .code = VIRTIO_SND_R_PCM_SET_PARAMS */ + struct virtio_snd_pcm_hdr hdr; + /* size of the hardware buffer */ + __le32 buffer_bytes; + /* size of the hardware period */ + __le32 period_bytes; + /* selected feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */ + __le32 features; + /* selected # of channels */ + __u8 channels; + /* selected sample format (VIRTIO_SND_PCM_FMT_XXX) */ + __u8 format; + /* selected frame rate (VIRTIO_SND_PCM_RATE_XXX) */ + __u8 rate; + + __u8 padding; +}; + +/******************************************************************************* + * PCM I/O MESSAGES + */ + +/* I/O request header */ +struct virtio_snd_pcm_xfer { + /* 0 ... virtio_snd_config::streams - 1 */ + __le32 stream_id; +}; + +/* I/O request status */ +struct virtio_snd_pcm_status { + /* VIRTIO_SND_S_XXX */ + __le32 status; + /* current device latency */ + __le32 latency_bytes; +}; + +/******************************************************************************* + * CHANNEL MAP CONTROL MESSAGES + */ +struct virtio_snd_chmap_hdr { + /* VIRTIO_SND_R_CHMAP_XXX */ + struct virtio_snd_hdr hdr; + /* 0 ... virtio_snd_config::chmaps - 1 */ + __le32 chmap_id; +}; + +/* standard channel position definition */ +enum { + VIRTIO_SND_CHMAP_NONE = 0, /* undefined */ + VIRTIO_SND_CHMAP_NA, /* silent */ + VIRTIO_SND_CHMAP_MONO, /* mono stream */ + VIRTIO_SND_CHMAP_FL, /* front left */ + VIRTIO_SND_CHMAP_FR, /* front right */ + VIRTIO_SND_CHMAP_RL, /* rear left */ + VIRTIO_SND_CHMAP_RR, /* rear right */ + VIRTIO_SND_CHMAP_FC, /* front center */ + VIRTIO_SND_CHMAP_LFE, /* low frequency (LFE) */ + VIRTIO_SND_CHMAP_SL, /* side left */ + VIRTIO_SND_CHMAP_SR, /* side right */ + VIRTIO_SND_CHMAP_RC, /* rear center */ + VIRTIO_SND_CHMAP_FLC, /* front left center */ + VIRTIO_SND_CHMAP_FRC, /* front right center */ + VIRTIO_SND_CHMAP_RLC, /* rear left center */ + VIRTIO_SND_CHMAP_RRC, /* rear right center */ + VIRTIO_SND_CHMAP_FLW, /* front left wide */ + VIRTIO_SND_CHMAP_FRW, /* front right wide */ + VIRTIO_SND_CHMAP_FLH, /* front left high */ + VIRTIO_SND_CHMAP_FCH, /* front center high */ + VIRTIO_SND_CHMAP_FRH, /* front right high */ + VIRTIO_SND_CHMAP_TC, /* top center */ + VIRTIO_SND_CHMAP_TFL, /* top front left */ + VIRTIO_SND_CHMAP_TFR, /* top front right */ + VIRTIO_SND_CHMAP_TFC, /* top front center */ + VIRTIO_SND_CHMAP_TRL, /* top rear left */ + VIRTIO_SND_CHMAP_TRR, /* top rear right */ + VIRTIO_SND_CHMAP_TRC, /* top rear center */ + VIRTIO_SND_CHMAP_TFLC, /* top front left center */ + VIRTIO_SND_CHMAP_TFRC, /* top front right center */ + VIRTIO_SND_CHMAP_TSL, /* top side left */ + VIRTIO_SND_CHMAP_TSR, /* top side right */ + VIRTIO_SND_CHMAP_LLFE, /* left LFE */ + VIRTIO_SND_CHMAP_RLFE, /* right LFE */ + VIRTIO_SND_CHMAP_BC, /* bottom center */ + VIRTIO_SND_CHMAP_BLC, /* bottom left center */ + VIRTIO_SND_CHMAP_BRC /* bottom right center */ +}; + +/* maximum possible number of channels */ +#define VIRTIO_SND_CHMAP_MAX_SIZE 18 + +struct virtio_snd_chmap_info { + /* common header */ + struct virtio_snd_info hdr; + /* dataflow direction (VIRTIO_SND_D_XXX) */ + __u8 direction; + /* # of valid channel position values */ + __u8 channels; + /* channel position values (VIRTIO_SND_CHMAP_XXX) */ + __u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE]; +}; + +#endif /* VIRTIO_SND_IF_H */ diff --git a/sound/Kconfig b/sound/Kconfig index 36785410fbe1..e56d96d2b11c 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -99,6 +99,8 @@ source "sound/synth/Kconfig" source "sound/xen/Kconfig" +source "sound/virtio/Kconfig" + endif # SND endif # !UML diff --git a/sound/Makefile b/sound/Makefile index 797ecdcd35e2..04ef04b1168f 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_DMASOUND) += oss/dmasound/ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ - firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ xen/ + firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ xen/ \ + virtio/ obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out diff --git a/sound/virtio/Kconfig b/sound/virtio/Kconfig new file mode 100644 index 000000000000..094cba24ee5b --- /dev/null +++ b/sound/virtio/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Sound card driver for virtio + +config SND_VIRTIO + tristate "Virtio sound driver" + depends on VIRTIO + select SND_PCM + select SND_JACK + help + This is the virtual sound driver for virtio. Say Y or M. diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile new file mode 100644 index 000000000000..8c87ebb9982b --- /dev/null +++ b/sound/virtio/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o + +virtio_snd-objs := \ + virtio_card.o + diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c new file mode 100644 index 000000000000..5a37056858e9 --- /dev/null +++ b/sound/virtio/virtio_card.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include +#include +#include +#include +#include + +#include "virtio_card.h" + +static void virtsnd_remove(struct virtio_device *vdev); + +/** + * virtsnd_event_send() - Add an event to the event queue. + * @vqueue: Underlying event virtqueue. + * @event: Event. + * @notify: Indicates whether or not to send a notification to the device. + * @gfp: Kernel flags for memory allocation. + * + * Context: Any context. + */ +static void virtsnd_event_send(struct virtqueue *vqueue, + struct virtio_snd_event *event, bool notify, + gfp_t gfp) +{ + struct scatterlist sg; + struct scatterlist *psgs[1] = { &sg }; + + /* reset event content */ + memset(event, 0, sizeof(*event)); + + sg_init_one(&sg, event, sizeof(*event)); + + if (virtqueue_add_sgs(vqueue, psgs, 0, 1, event, gfp) || !notify) + return; + + if (virtqueue_kick_prepare(vqueue)) + virtqueue_notify(vqueue); +} + +/** + * virtsnd_event_dispatch() - Dispatch an event from the device side. + * @snd: VirtIO sound device. + * @event: VirtIO sound event. + * + * Context: Any context. + */ +static void virtsnd_event_dispatch(struct virtio_snd *snd, + struct virtio_snd_event *event) +{ +} + +/** + * virtsnd_event_notify_cb() - Dispatch all reported events from the event queue. + * @vqueue: Underlying event virtqueue. + * + * This callback function is called upon a vring interrupt request from the + * device. + * + * Context: Interrupt context. + */ +static void virtsnd_event_notify_cb(struct virtqueue *vqueue) +{ + struct virtio_snd *snd = vqueue->vdev->priv; + struct virtio_snd_queue *queue = virtsnd_event_queue(snd); + struct virtio_snd_event *event; + u32 length; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + do { + virtqueue_disable_cb(vqueue); + while ((event = virtqueue_get_buf(vqueue, &length))) { + virtsnd_event_dispatch(snd, event); + virtsnd_event_send(vqueue, event, true, GFP_ATOMIC); + } + if (unlikely(virtqueue_is_broken(vqueue))) + break; + } while (!virtqueue_enable_cb(vqueue)); + spin_unlock_irqrestore(&queue->lock, flags); +} + +/** + * virtsnd_find_vqs() - Enumerate and initialize all virtqueues. + * @snd: VirtIO sound device. + * + * After calling this function, the event queue is disabled. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_find_vqs(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb + }; + static const char *names[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_EVENT] = "virtsnd-event" + }; + struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; + unsigned int i; + unsigned int n; + int rc; + + rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names, + NULL); + if (rc) { + dev_err(&vdev->dev, "failed to initialize virtqueues\n"); + return rc; + } + + for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) + snd->queues[i].vqueue = vqs[i]; + + /* Allocate events and populate the event queue */ + virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]); + + n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]); + + snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs), + GFP_KERNEL); + if (!snd->event_msgs) + return -ENOMEM; + + for (i = 0; i < n; ++i) + virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT], + &snd->event_msgs[i], false, GFP_KERNEL); + + return 0; +} + +/** + * virtsnd_enable_event_vq() - Enable the event virtqueue. + * @snd: VirtIO sound device. + * + * Context: Any context. + */ +static void virtsnd_enable_event_vq(struct virtio_snd *snd) +{ + struct virtio_snd_queue *queue = virtsnd_event_queue(snd); + + if (!virtqueue_enable_cb(queue->vqueue)) + virtsnd_event_notify_cb(queue->vqueue); +} + +/** + * virtsnd_disable_event_vq() - Disable the event virtqueue. + * @snd: VirtIO sound device. + * + * Context: Any context. + */ +static void virtsnd_disable_event_vq(struct virtio_snd *snd) +{ + struct virtio_snd_queue *queue = virtsnd_event_queue(snd); + struct virtio_snd_event *event; + u32 length; + unsigned long flags; + + if (queue->vqueue) { + spin_lock_irqsave(&queue->lock, flags); + virtqueue_disable_cb(queue->vqueue); + while ((event = virtqueue_get_buf(queue->vqueue, &length))) + virtsnd_event_dispatch(snd, event); + spin_unlock_irqrestore(&queue->lock, flags); + } +} + +/** + * virtsnd_build_devs() - Read configuration and build ALSA devices. + * @snd: VirtIO sound device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_build_devs(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct device *dev = &vdev->dev; + int rc; + + rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &snd->card); + if (rc < 0) + return rc; + + snd->card->private_data = snd; + + strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER, + sizeof(snd->card->driver)); + strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME, + sizeof(snd->card->shortname)); + if (dev->parent->bus) + snprintf(snd->card->longname, sizeof(snd->card->longname), + VIRTIO_SND_CARD_NAME " at %s/%s/%s", + dev->parent->bus->name, dev_name(dev->parent), + dev_name(dev)); + else + snprintf(snd->card->longname, sizeof(snd->card->longname), + VIRTIO_SND_CARD_NAME " at %s/%s", + dev_name(dev->parent), dev_name(dev)); + + return snd_card_register(snd->card); +} + +/** + * virtsnd_validate() - Validate if the device can be started. + * @vdev: VirtIO parent device. + * + * Context: Any context. + * Return: 0 on success, -EINVAL on failure. + */ +static int virtsnd_validate(struct virtio_device *vdev) +{ + if (!vdev->config->get) { + dev_err(&vdev->dev, "configuration access disabled\n"); + return -EINVAL; + } + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + dev_err(&vdev->dev, + "device does not comply with spec version 1.x\n"); + return -EINVAL; + } + + return 0; +} + +/** + * virtsnd_probe() - Create and initialize the device. + * @vdev: VirtIO parent device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_probe(struct virtio_device *vdev) +{ + struct virtio_snd *snd; + unsigned int i; + int rc; + + snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL); + if (!snd) + return -ENOMEM; + + snd->vdev = vdev; + + vdev->priv = snd; + + for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) + spin_lock_init(&snd->queues[i].lock); + + rc = virtsnd_find_vqs(snd); + if (rc) + goto on_exit; + + virtio_device_ready(vdev); + + rc = virtsnd_build_devs(snd); + if (rc) + goto on_exit; + + virtsnd_enable_event_vq(snd); + +on_exit: + if (rc) + virtsnd_remove(vdev); + + return rc; +} + +/** + * virtsnd_remove() - Remove VirtIO and ALSA devices. + * @vdev: VirtIO parent device. + * + * Context: Any context that permits to sleep. + */ +static void virtsnd_remove(struct virtio_device *vdev) +{ + struct virtio_snd *snd = vdev->priv; + + virtsnd_disable_event_vq(snd); + + if (snd->card) + snd_card_free(snd->card); + + vdev->config->del_vqs(vdev); + vdev->config->reset(vdev); + + kfree(snd->event_msgs); +} + +static const struct virtio_device_id id_table[] = { + { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static struct virtio_driver virtsnd_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .validate = virtsnd_validate, + .probe = virtsnd_probe, + .remove = virtsnd_remove, +}; + +static int __init init(void) +{ + return register_virtio_driver(&virtsnd_driver); +} +module_init(init); + +static void __exit fini(void) +{ + unregister_virtio_driver(&virtsnd_driver); +} +module_exit(fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio sound card driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h new file mode 100644 index 000000000000..b903b1b12e90 --- /dev/null +++ b/sound/virtio/virtio_card.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#ifndef VIRTIO_SND_CARD_H +#define VIRTIO_SND_CARD_H + +#include +#include +#include +#include + +#define VIRTIO_SND_CARD_DRIVER "virtio-snd" +#define VIRTIO_SND_CARD_NAME "VirtIO SoundCard" + +/** + * struct virtio_snd_queue - Virtqueue wrapper structure. + * @lock: Used to synchronize access to a virtqueue. + * @vqueue: Underlying virtqueue. + */ +struct virtio_snd_queue { + spinlock_t lock; + struct virtqueue *vqueue; +}; + +/** + * struct virtio_snd - VirtIO sound card device. + * @vdev: Underlying virtio device. + * @queues: Virtqueue wrappers. + * @card: ALSA sound card. + * @event_msgs: Device events. + */ +struct virtio_snd { + struct virtio_device *vdev; + struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX]; + struct snd_card *card; + struct virtio_snd_event *event_msgs; +}; + +static inline struct virtio_snd_queue * +virtsnd_control_queue(struct virtio_snd *snd) +{ + return &snd->queues[VIRTIO_SND_VQ_CONTROL]; +} + +static inline struct virtio_snd_queue * +virtsnd_event_queue(struct virtio_snd *snd) +{ + return &snd->queues[VIRTIO_SND_VQ_EVENT]; +} + +static inline struct virtio_snd_queue * +virtsnd_tx_queue(struct virtio_snd *snd) +{ + return &snd->queues[VIRTIO_SND_VQ_TX]; +} + +static inline struct virtio_snd_queue * +virtsnd_rx_queue(struct virtio_snd *snd) +{ + return &snd->queues[VIRTIO_SND_VQ_RX]; +} + +#endif /* VIRTIO_SND_CARD_H */ -- cgit v1.2.3-58-ga151 From 9d45e514da88ff74fc24ffb34e7d6eb92576440b Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:03 +0100 Subject: ALSA: virtio: handling control messages The control queue can be used by different parts of the driver to send commands to the device. Control messages can be either synchronous or asynchronous. The lifetime of a message is controlled by a reference count. Introduce a module parameter to set the message completion timeout: msg_timeout_ms [=1000] Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-4-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 3 +- sound/virtio/virtio_card.c | 13 ++ sound/virtio/virtio_card.h | 7 + sound/virtio/virtio_ctl_msg.c | 310 ++++++++++++++++++++++++++++++++++++++++++ sound/virtio/virtio_ctl_msg.h | 78 +++++++++++ 5 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 sound/virtio/virtio_ctl_msg.c create mode 100644 sound/virtio/virtio_ctl_msg.h (limited to 'sound') diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 8c87ebb9982b..dc551e637441 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -3,5 +3,6 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ - virtio_card.o + virtio_card.o \ + virtio_ctl_msg.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 5a37056858e9..b757b2444078 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -11,6 +11,10 @@ #include "virtio_card.h" +u32 virtsnd_msg_timeout_ms = MSEC_PER_SEC; +module_param_named(msg_timeout_ms, virtsnd_msg_timeout_ms, uint, 0644); +MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds"); + static void virtsnd_remove(struct virtio_device *vdev); /** @@ -96,9 +100,11 @@ static int virtsnd_find_vqs(struct virtio_snd *snd) { struct virtio_device *vdev = snd->vdev; static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb, [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb }; static const char *names[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl", [VIRTIO_SND_VQ_EVENT] = "virtsnd-event" }; struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; @@ -226,6 +232,11 @@ static int virtsnd_validate(struct virtio_device *vdev) return -EINVAL; } + if (!virtsnd_msg_timeout_ms) { + dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n"); + return -EINVAL; + } + return 0; } @@ -247,6 +258,7 @@ static int virtsnd_probe(struct virtio_device *vdev) return -ENOMEM; snd->vdev = vdev; + INIT_LIST_HEAD(&snd->ctl_msgs); vdev->priv = snd; @@ -283,6 +295,7 @@ static void virtsnd_remove(struct virtio_device *vdev) struct virtio_snd *snd = vdev->priv; virtsnd_disable_event_vq(snd); + virtsnd_ctl_msg_cancel_all(snd); if (snd->card) snd_card_free(snd->card); diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index b903b1b12e90..1e76eeff160f 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -11,6 +11,8 @@ #include #include +#include "virtio_ctl_msg.h" + #define VIRTIO_SND_CARD_DRIVER "virtio-snd" #define VIRTIO_SND_CARD_NAME "VirtIO SoundCard" @@ -29,15 +31,20 @@ struct virtio_snd_queue { * @vdev: Underlying virtio device. * @queues: Virtqueue wrappers. * @card: ALSA sound card. + * @ctl_msgs: Pending control request list. * @event_msgs: Device events. */ struct virtio_snd { struct virtio_device *vdev; struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX]; struct snd_card *card; + struct list_head ctl_msgs; struct virtio_snd_event *event_msgs; }; +/* Message completion timeout in milliseconds (module parameter). */ +extern u32 virtsnd_msg_timeout_ms; + static inline struct virtio_snd_queue * virtsnd_control_queue(struct virtio_snd *snd) { diff --git a/sound/virtio/virtio_ctl_msg.c b/sound/virtio/virtio_ctl_msg.c new file mode 100644 index 000000000000..26ff7e7cc041 --- /dev/null +++ b/sound/virtio/virtio_ctl_msg.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include +#include + +#include "virtio_card.h" + +/** + * struct virtio_snd_msg - Control message. + * @sg_request: Scattergather list containing a device request (header). + * @sg_response: Scattergather list containing a device response (status). + * @list: Pending message list entry. + * @notify: Request completed notification. + * @ref_count: Reference count used to manage a message lifetime. + */ +struct virtio_snd_msg { + struct scatterlist sg_request; + struct scatterlist sg_response; + struct list_head list; + struct completion notify; + refcount_t ref_count; +}; + +/** + * virtsnd_ctl_msg_ref() - Increment reference counter for the message. + * @msg: Control message. + * + * Context: Any context. + */ +void virtsnd_ctl_msg_ref(struct virtio_snd_msg *msg) +{ + refcount_inc(&msg->ref_count); +} + +/** + * virtsnd_ctl_msg_unref() - Decrement reference counter for the message. + * @msg: Control message. + * + * The message will be freed when the ref_count value is 0. + * + * Context: Any context. + */ +void virtsnd_ctl_msg_unref(struct virtio_snd_msg *msg) +{ + if (refcount_dec_and_test(&msg->ref_count)) + kfree(msg); +} + +/** + * virtsnd_ctl_msg_request() - Get a pointer to the request header. + * @msg: Control message. + * + * Context: Any context. + */ +void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg) +{ + return sg_virt(&msg->sg_request); +} + +/** + * virtsnd_ctl_msg_request() - Get a pointer to the response header. + * @msg: Control message. + * + * Context: Any context. + */ +void *virtsnd_ctl_msg_response(struct virtio_snd_msg *msg) +{ + return sg_virt(&msg->sg_response); +} + +/** + * virtsnd_ctl_msg_alloc() - Allocate and initialize a control message. + * @request_size: Size of request header. + * @response_size: Size of response header. + * @gfp: Kernel flags for memory allocation. + * + * The message will be automatically freed when the ref_count value is 0. + * + * Context: Any context. May sleep if @gfp flags permit. + * Return: Allocated message on success, NULL on failure. + */ +struct virtio_snd_msg *virtsnd_ctl_msg_alloc(size_t request_size, + size_t response_size, gfp_t gfp) +{ + struct virtio_snd_msg *msg; + + if (!request_size || !response_size) + return NULL; + + msg = kzalloc(sizeof(*msg) + request_size + response_size, gfp); + if (!msg) + return NULL; + + sg_init_one(&msg->sg_request, (u8 *)msg + sizeof(*msg), request_size); + sg_init_one(&msg->sg_response, (u8 *)msg + sizeof(*msg) + request_size, + response_size); + + INIT_LIST_HEAD(&msg->list); + init_completion(&msg->notify); + /* This reference is dropped in virtsnd_ctl_msg_complete(). */ + refcount_set(&msg->ref_count, 1); + + return msg; +} + +/** + * virtsnd_ctl_msg_send() - Send a control message. + * @snd: VirtIO sound device. + * @msg: Control message. + * @out_sgs: Additional sg-list to attach to the request header (may be NULL). + * @in_sgs: Additional sg-list to attach to the response header (may be NULL). + * @nowait: Flag indicating whether to wait for completion. + * + * Context: Any context. Takes and releases the control queue spinlock. + * May sleep if @nowait is false. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg, + struct scatterlist *out_sgs, + struct scatterlist *in_sgs, bool nowait) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_snd_queue *queue = virtsnd_control_queue(snd); + unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms); + struct virtio_snd_hdr *request = virtsnd_ctl_msg_request(msg); + struct virtio_snd_hdr *response = virtsnd_ctl_msg_response(msg); + unsigned int nouts = 0; + unsigned int nins = 0; + struct scatterlist *psgs[4]; + bool notify = false; + unsigned long flags; + int rc; + + virtsnd_ctl_msg_ref(msg); + + /* Set the default status in case the message was canceled. */ + response->code = cpu_to_le32(VIRTIO_SND_S_IO_ERR); + + psgs[nouts++] = &msg->sg_request; + if (out_sgs) + psgs[nouts++] = out_sgs; + + psgs[nouts + nins++] = &msg->sg_response; + if (in_sgs) + psgs[nouts + nins++] = in_sgs; + + spin_lock_irqsave(&queue->lock, flags); + rc = virtqueue_add_sgs(queue->vqueue, psgs, nouts, nins, msg, + GFP_ATOMIC); + if (!rc) { + notify = virtqueue_kick_prepare(queue->vqueue); + + list_add_tail(&msg->list, &snd->ctl_msgs); + } + spin_unlock_irqrestore(&queue->lock, flags); + + if (rc) { + dev_err(&vdev->dev, "failed to send control message (0x%08x)\n", + le32_to_cpu(request->code)); + + /* + * Since in this case virtsnd_ctl_msg_complete() will not be + * called, it is necessary to decrement the reference count. + */ + virtsnd_ctl_msg_unref(msg); + + goto on_exit; + } + + if (notify) + virtqueue_notify(queue->vqueue); + + if (nowait) + goto on_exit; + + rc = wait_for_completion_interruptible_timeout(&msg->notify, js); + if (rc <= 0) { + if (!rc) { + dev_err(&vdev->dev, + "control message (0x%08x) timeout\n", + le32_to_cpu(request->code)); + rc = -ETIMEDOUT; + } + + goto on_exit; + } + + switch (le32_to_cpu(response->code)) { + case VIRTIO_SND_S_OK: + rc = 0; + break; + case VIRTIO_SND_S_NOT_SUPP: + rc = -EOPNOTSUPP; + break; + case VIRTIO_SND_S_IO_ERR: + rc = -EIO; + break; + default: + rc = -EINVAL; + break; + } + +on_exit: + virtsnd_ctl_msg_unref(msg); + + return rc; +} + +/** + * virtsnd_ctl_msg_complete() - Complete a control message. + * @msg: Control message. + * + * Context: Any context. Expects the control queue spinlock to be held by + * caller. + */ +void virtsnd_ctl_msg_complete(struct virtio_snd_msg *msg) +{ + list_del(&msg->list); + complete(&msg->notify); + + virtsnd_ctl_msg_unref(msg); +} + +/** + * virtsnd_ctl_msg_cancel_all() - Cancel all pending control messages. + * @snd: VirtIO sound device. + * + * Context: Any context. + */ +void virtsnd_ctl_msg_cancel_all(struct virtio_snd *snd) +{ + struct virtio_snd_queue *queue = virtsnd_control_queue(snd); + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + while (!list_empty(&snd->ctl_msgs)) { + struct virtio_snd_msg *msg = + list_first_entry(&snd->ctl_msgs, struct virtio_snd_msg, + list); + + virtsnd_ctl_msg_complete(msg); + } + spin_unlock_irqrestore(&queue->lock, flags); +} + +/** + * virtsnd_ctl_query_info() - Query the item configuration from the device. + * @snd: VirtIO sound device. + * @command: Control request code (VIRTIO_SND_R_XXX_INFO). + * @start_id: Item start identifier. + * @count: Item count to query. + * @size: Item information size in bytes. + * @info: Buffer for storing item information. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_ctl_query_info(struct virtio_snd *snd, int command, int start_id, + int count, size_t size, void *info) +{ + struct virtio_snd_msg *msg; + struct virtio_snd_query_info *query; + struct scatterlist sg; + + msg = virtsnd_ctl_msg_alloc(sizeof(*query), + sizeof(struct virtio_snd_hdr), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + query = virtsnd_ctl_msg_request(msg); + query->hdr.code = cpu_to_le32(command); + query->start_id = cpu_to_le32(start_id); + query->count = cpu_to_le32(count); + query->size = cpu_to_le32(size); + + sg_init_one(&sg, info, count * size); + + return virtsnd_ctl_msg_send(snd, msg, NULL, &sg, false); +} + +/** + * virtsnd_ctl_notify_cb() - Process all completed control messages. + * @vqueue: Underlying control virtqueue. + * + * This callback function is called upon a vring interrupt request from the + * device. + * + * Context: Interrupt context. Takes and releases the control queue spinlock. + */ +void virtsnd_ctl_notify_cb(struct virtqueue *vqueue) +{ + struct virtio_snd *snd = vqueue->vdev->priv; + struct virtio_snd_queue *queue = virtsnd_control_queue(snd); + struct virtio_snd_msg *msg; + u32 length; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + do { + virtqueue_disable_cb(vqueue); + while ((msg = virtqueue_get_buf(vqueue, &length))) + virtsnd_ctl_msg_complete(msg); + if (unlikely(virtqueue_is_broken(vqueue))) + break; + } while (!virtqueue_enable_cb(vqueue)); + spin_unlock_irqrestore(&queue->lock, flags); +} diff --git a/sound/virtio/virtio_ctl_msg.h b/sound/virtio/virtio_ctl_msg.h new file mode 100644 index 000000000000..7f4db044f28e --- /dev/null +++ b/sound/virtio/virtio_ctl_msg.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#ifndef VIRTIO_SND_MSG_H +#define VIRTIO_SND_MSG_H + +#include +#include + +struct virtio_snd; +struct virtio_snd_msg; + +void virtsnd_ctl_msg_ref(struct virtio_snd_msg *msg); + +void virtsnd_ctl_msg_unref(struct virtio_snd_msg *msg); + +void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg); + +void *virtsnd_ctl_msg_response(struct virtio_snd_msg *msg); + +struct virtio_snd_msg *virtsnd_ctl_msg_alloc(size_t request_size, + size_t response_size, gfp_t gfp); + +int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg, + struct scatterlist *out_sgs, + struct scatterlist *in_sgs, bool nowait); + +/** + * virtsnd_ctl_msg_send_sync() - Simplified sending of synchronous message. + * @snd: VirtIO sound device. + * @msg: Control message. + * + * After returning from this function, the message will be deleted. If message + * content is still needed, the caller must additionally to + * virtsnd_ctl_msg_ref/unref() it. + * + * The msg_timeout_ms module parameter defines the message completion timeout. + * If the message is not completed within this time, the function will return an + * error. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + * + * The return value is a message status code (VIRTIO_SND_S_XXX) converted to an + * appropriate -errno value. + */ +static inline int virtsnd_ctl_msg_send_sync(struct virtio_snd *snd, + struct virtio_snd_msg *msg) +{ + return virtsnd_ctl_msg_send(snd, msg, NULL, NULL, false); +} + +/** + * virtsnd_ctl_msg_send_async() - Simplified sending of asynchronous message. + * @snd: VirtIO sound device. + * @msg: Control message. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static inline int virtsnd_ctl_msg_send_async(struct virtio_snd *snd, + struct virtio_snd_msg *msg) +{ + return virtsnd_ctl_msg_send(snd, msg, NULL, NULL, true); +} + +void virtsnd_ctl_msg_cancel_all(struct virtio_snd *snd); + +void virtsnd_ctl_msg_complete(struct virtio_snd_msg *msg); + +int virtsnd_ctl_query_info(struct virtio_snd *snd, int command, int start_id, + int count, size_t size, void *info); + +void virtsnd_ctl_notify_cb(struct virtqueue *vqueue); + +#endif /* VIRTIO_SND_MSG_H */ -- cgit v1.2.3-58-ga151 From 29b96bf50ba958eb5f097cdc3fbd4c1acf9547a2 Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:04 +0100 Subject: ALSA: virtio: build PCM devices and substream hardware descriptors Like the HDA specification, the virtio sound device specification links PCM substreams, jacks and PCM channel maps into functional groups. For each discovered group, a PCM device is created, the number of which coincides with the group number. Introduce the module parameters for setting the hardware buffer parameters: pcm_buffer_ms [=160] pcm_periods_min [=2] pcm_periods_max [=16] pcm_period_ms_min [=10] pcm_period_ms_max [=80] Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-5-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 3 +- sound/virtio/virtio_card.c | 18 ++ sound/virtio/virtio_card.h | 10 + sound/virtio/virtio_pcm.c | 479 +++++++++++++++++++++++++++++++++++++++++++++ sound/virtio/virtio_pcm.h | 72 +++++++ 5 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 sound/virtio/virtio_pcm.c create mode 100644 sound/virtio/virtio_pcm.h (limited to 'sound') diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index dc551e637441..69162a545a41 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ virtio_card.o \ - virtio_ctl_msg.o + virtio_ctl_msg.o \ + virtio_pcm.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index b757b2444078..11c76ee311b7 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -209,6 +209,16 @@ static int virtsnd_build_devs(struct virtio_snd *snd) VIRTIO_SND_CARD_NAME " at %s/%s", dev_name(dev->parent), dev_name(dev)); + rc = virtsnd_pcm_parse_cfg(snd); + if (rc) + return rc; + + if (snd->nsubstreams) { + rc = virtsnd_pcm_build_devs(snd); + if (rc) + return rc; + } + return snd_card_register(snd->card); } @@ -237,6 +247,9 @@ static int virtsnd_validate(struct virtio_device *vdev) return -EINVAL; } + if (virtsnd_pcm_validate(vdev)) + return -EINVAL; + return 0; } @@ -259,6 +272,7 @@ static int virtsnd_probe(struct virtio_device *vdev) snd->vdev = vdev; INIT_LIST_HEAD(&snd->ctl_msgs); + INIT_LIST_HEAD(&snd->pcm_list); vdev->priv = snd; @@ -293,6 +307,7 @@ on_exit: static void virtsnd_remove(struct virtio_device *vdev) { struct virtio_snd *snd = vdev->priv; + unsigned int i; virtsnd_disable_event_vq(snd); virtsnd_ctl_msg_cancel_all(snd); @@ -303,6 +318,9 @@ static void virtsnd_remove(struct virtio_device *vdev) vdev->config->del_vqs(vdev); vdev->config->reset(vdev); + for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) + cancel_work_sync(&snd->substreams[i].elapsed_period); + kfree(snd->event_msgs); } diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index 1e76eeff160f..77a1b7255370 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -12,9 +12,13 @@ #include #include "virtio_ctl_msg.h" +#include "virtio_pcm.h" #define VIRTIO_SND_CARD_DRIVER "virtio-snd" #define VIRTIO_SND_CARD_NAME "VirtIO SoundCard" +#define VIRTIO_SND_PCM_NAME "VirtIO PCM" + +struct virtio_pcm_substream; /** * struct virtio_snd_queue - Virtqueue wrapper structure. @@ -33,6 +37,9 @@ struct virtio_snd_queue { * @card: ALSA sound card. * @ctl_msgs: Pending control request list. * @event_msgs: Device events. + * @pcm_list: VirtIO PCM device list. + * @substreams: VirtIO PCM substreams. + * @nsubstreams: Number of PCM substreams. */ struct virtio_snd { struct virtio_device *vdev; @@ -40,6 +47,9 @@ struct virtio_snd { struct snd_card *card; struct list_head ctl_msgs; struct virtio_snd_event *event_msgs; + struct list_head pcm_list; + struct virtio_pcm_substream *substreams; + u32 nsubstreams; }; /* Message completion timeout in milliseconds (module parameter). */ diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c new file mode 100644 index 000000000000..e16567e2e214 --- /dev/null +++ b/sound/virtio/virtio_pcm.c @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include +#include + +#include "virtio_card.h" + +static u32 pcm_buffer_ms = 160; +module_param(pcm_buffer_ms, uint, 0644); +MODULE_PARM_DESC(pcm_buffer_ms, "PCM substream buffer time in milliseconds"); + +static u32 pcm_periods_min = 2; +module_param(pcm_periods_min, uint, 0644); +MODULE_PARM_DESC(pcm_periods_min, "Minimum number of PCM periods"); + +static u32 pcm_periods_max = 16; +module_param(pcm_periods_max, uint, 0644); +MODULE_PARM_DESC(pcm_periods_max, "Maximum number of PCM periods"); + +static u32 pcm_period_ms_min = 10; +module_param(pcm_period_ms_min, uint, 0644); +MODULE_PARM_DESC(pcm_period_ms_min, "Minimum PCM period time in milliseconds"); + +static u32 pcm_period_ms_max = 80; +module_param(pcm_period_ms_max, uint, 0644); +MODULE_PARM_DESC(pcm_period_ms_max, "Maximum PCM period time in milliseconds"); + +/* Map for converting VirtIO format to ALSA format. */ +static const snd_pcm_format_t g_v2a_format_map[] = { + [VIRTIO_SND_PCM_FMT_IMA_ADPCM] = SNDRV_PCM_FORMAT_IMA_ADPCM, + [VIRTIO_SND_PCM_FMT_MU_LAW] = SNDRV_PCM_FORMAT_MU_LAW, + [VIRTIO_SND_PCM_FMT_A_LAW] = SNDRV_PCM_FORMAT_A_LAW, + [VIRTIO_SND_PCM_FMT_S8] = SNDRV_PCM_FORMAT_S8, + [VIRTIO_SND_PCM_FMT_U8] = SNDRV_PCM_FORMAT_U8, + [VIRTIO_SND_PCM_FMT_S16] = SNDRV_PCM_FORMAT_S16_LE, + [VIRTIO_SND_PCM_FMT_U16] = SNDRV_PCM_FORMAT_U16_LE, + [VIRTIO_SND_PCM_FMT_S18_3] = SNDRV_PCM_FORMAT_S18_3LE, + [VIRTIO_SND_PCM_FMT_U18_3] = SNDRV_PCM_FORMAT_U18_3LE, + [VIRTIO_SND_PCM_FMT_S20_3] = SNDRV_PCM_FORMAT_S20_3LE, + [VIRTIO_SND_PCM_FMT_U20_3] = SNDRV_PCM_FORMAT_U20_3LE, + [VIRTIO_SND_PCM_FMT_S24_3] = SNDRV_PCM_FORMAT_S24_3LE, + [VIRTIO_SND_PCM_FMT_U24_3] = SNDRV_PCM_FORMAT_U24_3LE, + [VIRTIO_SND_PCM_FMT_S20] = SNDRV_PCM_FORMAT_S20_LE, + [VIRTIO_SND_PCM_FMT_U20] = SNDRV_PCM_FORMAT_U20_LE, + [VIRTIO_SND_PCM_FMT_S24] = SNDRV_PCM_FORMAT_S24_LE, + [VIRTIO_SND_PCM_FMT_U24] = SNDRV_PCM_FORMAT_U24_LE, + [VIRTIO_SND_PCM_FMT_S32] = SNDRV_PCM_FORMAT_S32_LE, + [VIRTIO_SND_PCM_FMT_U32] = SNDRV_PCM_FORMAT_U32_LE, + [VIRTIO_SND_PCM_FMT_FLOAT] = SNDRV_PCM_FORMAT_FLOAT_LE, + [VIRTIO_SND_PCM_FMT_FLOAT64] = SNDRV_PCM_FORMAT_FLOAT64_LE, + [VIRTIO_SND_PCM_FMT_DSD_U8] = SNDRV_PCM_FORMAT_DSD_U8, + [VIRTIO_SND_PCM_FMT_DSD_U16] = SNDRV_PCM_FORMAT_DSD_U16_LE, + [VIRTIO_SND_PCM_FMT_DSD_U32] = SNDRV_PCM_FORMAT_DSD_U32_LE, + [VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME] = + SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE +}; + +/* Map for converting VirtIO frame rate to ALSA frame rate. */ +struct virtsnd_v2a_rate { + unsigned int alsa_bit; + unsigned int rate; +}; + +static const struct virtsnd_v2a_rate g_v2a_rate_map[] = { + [VIRTIO_SND_PCM_RATE_5512] = { SNDRV_PCM_RATE_5512, 5512 }, + [VIRTIO_SND_PCM_RATE_8000] = { SNDRV_PCM_RATE_8000, 8000 }, + [VIRTIO_SND_PCM_RATE_11025] = { SNDRV_PCM_RATE_11025, 11025 }, + [VIRTIO_SND_PCM_RATE_16000] = { SNDRV_PCM_RATE_16000, 16000 }, + [VIRTIO_SND_PCM_RATE_22050] = { SNDRV_PCM_RATE_22050, 22050 }, + [VIRTIO_SND_PCM_RATE_32000] = { SNDRV_PCM_RATE_32000, 32000 }, + [VIRTIO_SND_PCM_RATE_44100] = { SNDRV_PCM_RATE_44100, 44100 }, + [VIRTIO_SND_PCM_RATE_48000] = { SNDRV_PCM_RATE_48000, 48000 }, + [VIRTIO_SND_PCM_RATE_64000] = { SNDRV_PCM_RATE_64000, 64000 }, + [VIRTIO_SND_PCM_RATE_88200] = { SNDRV_PCM_RATE_88200, 88200 }, + [VIRTIO_SND_PCM_RATE_96000] = { SNDRV_PCM_RATE_96000, 96000 }, + [VIRTIO_SND_PCM_RATE_176400] = { SNDRV_PCM_RATE_176400, 176400 }, + [VIRTIO_SND_PCM_RATE_192000] = { SNDRV_PCM_RATE_192000, 192000 } +}; + +/** + * virtsnd_pcm_build_hw() - Parse substream config and build HW descriptor. + * @vss: VirtIO substream. + * @info: VirtIO substream information entry. + * + * Context: Any context. + * Return: 0 on success, -EINVAL if configuration is invalid. + */ +static int virtsnd_pcm_build_hw(struct virtio_pcm_substream *vss, + struct virtio_snd_pcm_info *info) +{ + struct virtio_device *vdev = vss->snd->vdev; + unsigned int i; + u64 values; + size_t sample_max = 0; + size_t sample_min = 0; + + vss->features = le32_to_cpu(info->features); + + /* + * TODO: set SNDRV_PCM_INFO_{BATCH,BLOCK_TRANSFER} if device supports + * only message-based transport. + */ + vss->hw.info = + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE; + + if (!info->channels_min || info->channels_min > info->channels_max) { + dev_err(&vdev->dev, + "SID %u: invalid channel range [%u %u]\n", + vss->sid, info->channels_min, info->channels_max); + return -EINVAL; + } + + vss->hw.channels_min = info->channels_min; + vss->hw.channels_max = info->channels_max; + + values = le64_to_cpu(info->formats); + + vss->hw.formats = 0; + + for (i = 0; i < ARRAY_SIZE(g_v2a_format_map); ++i) + if (values & (1ULL << i)) { + snd_pcm_format_t alsa_fmt = g_v2a_format_map[i]; + int bytes = snd_pcm_format_physical_width(alsa_fmt) / 8; + + if (!sample_min || sample_min > bytes) + sample_min = bytes; + + if (sample_max < bytes) + sample_max = bytes; + + vss->hw.formats |= pcm_format_to_bits(alsa_fmt); + } + + if (!vss->hw.formats) { + dev_err(&vdev->dev, + "SID %u: no supported PCM sample formats found\n", + vss->sid); + return -EINVAL; + } + + values = le64_to_cpu(info->rates); + + vss->hw.rates = 0; + + for (i = 0; i < ARRAY_SIZE(g_v2a_rate_map); ++i) + if (values & (1ULL << i)) { + if (!vss->hw.rate_min || + vss->hw.rate_min > g_v2a_rate_map[i].rate) + vss->hw.rate_min = g_v2a_rate_map[i].rate; + + if (vss->hw.rate_max < g_v2a_rate_map[i].rate) + vss->hw.rate_max = g_v2a_rate_map[i].rate; + + vss->hw.rates |= g_v2a_rate_map[i].alsa_bit; + } + + if (!vss->hw.rates) { + dev_err(&vdev->dev, + "SID %u: no supported PCM frame rates found\n", + vss->sid); + return -EINVAL; + } + + vss->hw.periods_min = pcm_periods_min; + vss->hw.periods_max = pcm_periods_max; + + /* + * We must ensure that there is enough space in the buffer to store + * pcm_buffer_ms ms for the combination (Cmax, Smax, Rmax), where: + * Cmax = maximum supported number of channels, + * Smax = maximum supported sample size in bytes, + * Rmax = maximum supported frame rate. + */ + vss->hw.buffer_bytes_max = + PAGE_ALIGN(sample_max * vss->hw.channels_max * pcm_buffer_ms * + (vss->hw.rate_max / MSEC_PER_SEC)); + + /* + * We must ensure that the minimum period size is enough to store + * pcm_period_ms_min ms for the combination (Cmin, Smin, Rmin), where: + * Cmin = minimum supported number of channels, + * Smin = minimum supported sample size in bytes, + * Rmin = minimum supported frame rate. + */ + vss->hw.period_bytes_min = + sample_min * vss->hw.channels_min * pcm_period_ms_min * + (vss->hw.rate_min / MSEC_PER_SEC); + + /* + * We must ensure that the maximum period size is enough to store + * pcm_period_ms_max ms for the combination (Cmax, Smax, Rmax). + */ + vss->hw.period_bytes_max = + sample_max * vss->hw.channels_max * pcm_period_ms_max * + (vss->hw.rate_max / MSEC_PER_SEC); + + return 0; +} + +/** + * virtsnd_pcm_find() - Find the PCM device for the specified node ID. + * @snd: VirtIO sound device. + * @nid: Function node ID. + * + * Context: Any context. + * Return: a pointer to the PCM device or ERR_PTR(-ENOENT). + */ +struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid) +{ + struct virtio_pcm *vpcm; + + list_for_each_entry(vpcm, &snd->pcm_list, list) + if (vpcm->nid == nid) + return vpcm; + + return ERR_PTR(-ENOENT); +} + +/** + * virtsnd_pcm_find_or_create() - Find or create the PCM device for the + * specified node ID. + * @snd: VirtIO sound device. + * @nid: Function node ID. + * + * Context: Any context that permits to sleep. + * Return: a pointer to the PCM device or ERR_PTR(-errno). + */ +struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_pcm *vpcm; + + vpcm = virtsnd_pcm_find(snd, nid); + if (!IS_ERR(vpcm)) + return vpcm; + + vpcm = devm_kzalloc(&vdev->dev, sizeof(*vpcm), GFP_KERNEL); + if (!vpcm) + return ERR_PTR(-ENOMEM); + + vpcm->nid = nid; + list_add_tail(&vpcm->list, &snd->pcm_list); + + return vpcm; +} + +/** + * virtsnd_pcm_validate() - Validate if the device can be started. + * @vdev: VirtIO parent device. + * + * Context: Any context. + * Return: 0 on success, -EINVAL on failure. + */ +int virtsnd_pcm_validate(struct virtio_device *vdev) +{ + if (pcm_periods_min < 2 || pcm_periods_min > pcm_periods_max) { + dev_err(&vdev->dev, + "invalid range [%u %u] of the number of PCM periods\n", + pcm_periods_min, pcm_periods_max); + return -EINVAL; + } + + if (!pcm_period_ms_min || pcm_period_ms_min > pcm_period_ms_max) { + dev_err(&vdev->dev, + "invalid range [%u %u] of the size of the PCM period\n", + pcm_period_ms_min, pcm_period_ms_max); + return -EINVAL; + } + + if (pcm_buffer_ms < pcm_periods_min * pcm_period_ms_min) { + dev_err(&vdev->dev, + "pcm_buffer_ms(=%u) value cannot be < %u ms\n", + pcm_buffer_ms, pcm_periods_min * pcm_period_ms_min); + return -EINVAL; + } + + if (pcm_period_ms_max > pcm_buffer_ms / 2) { + dev_err(&vdev->dev, + "pcm_period_ms_max(=%u) value cannot be > %u ms\n", + pcm_period_ms_max, pcm_buffer_ms / 2); + return -EINVAL; + } + + return 0; +} + +/** + * virtsnd_pcm_period_elapsed() - Kernel work function to handle the elapsed + * period state. + * @work: Elapsed period work. + * + * The main purpose of this function is to call snd_pcm_period_elapsed() in + * a process context, not in an interrupt context. This is necessary because PCM + * devices operate in non-atomic mode. + * + * Context: Process context. + */ +static void virtsnd_pcm_period_elapsed(struct work_struct *work) +{ + struct virtio_pcm_substream *vss = + container_of(work, struct virtio_pcm_substream, elapsed_period); + + snd_pcm_period_elapsed(vss->substream); +} + +/** + * virtsnd_pcm_parse_cfg() - Parse the stream configuration. + * @snd: VirtIO sound device. + * + * This function is called during initial device initialization. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_pcm_parse_cfg(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_snd_pcm_info *info; + u32 i; + int rc; + + virtio_cread_le(vdev, struct virtio_snd_config, streams, + &snd->nsubstreams); + if (!snd->nsubstreams) + return 0; + + snd->substreams = devm_kcalloc(&vdev->dev, snd->nsubstreams, + sizeof(*snd->substreams), GFP_KERNEL); + if (!snd->substreams) + return -ENOMEM; + + info = kcalloc(snd->nsubstreams, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_PCM_INFO, 0, + snd->nsubstreams, sizeof(*info), info); + if (rc) + goto on_exit; + + for (i = 0; i < snd->nsubstreams; ++i) { + struct virtio_pcm_substream *vss = &snd->substreams[i]; + struct virtio_pcm *vpcm; + + vss->snd = snd; + vss->sid = i; + INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); + + rc = virtsnd_pcm_build_hw(vss, &info[i]); + if (rc) + goto on_exit; + + vss->nid = le32_to_cpu(info[i].hdr.hda_fn_nid); + + vpcm = virtsnd_pcm_find_or_create(snd, vss->nid); + if (IS_ERR(vpcm)) { + rc = PTR_ERR(vpcm); + goto on_exit; + } + + switch (info[i].direction) { + case VIRTIO_SND_D_OUTPUT: + vss->direction = SNDRV_PCM_STREAM_PLAYBACK; + break; + case VIRTIO_SND_D_INPUT: + vss->direction = SNDRV_PCM_STREAM_CAPTURE; + break; + default: + dev_err(&vdev->dev, "SID %u: unknown direction (%u)\n", + vss->sid, info[i].direction); + rc = -EINVAL; + goto on_exit; + } + + vpcm->streams[vss->direction].nsubstreams++; + } + +on_exit: + kfree(info); + + return rc; +} + +/** + * virtsnd_pcm_build_devs() - Build ALSA PCM devices. + * @snd: VirtIO sound device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_pcm_build_devs(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_pcm *vpcm; + u32 i; + int rc; + + list_for_each_entry(vpcm, &snd->pcm_list, list) { + unsigned int npbs = + vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK].nsubstreams; + unsigned int ncps = + vpcm->streams[SNDRV_PCM_STREAM_CAPTURE].nsubstreams; + + if (!npbs && !ncps) + continue; + + rc = snd_pcm_new(snd->card, VIRTIO_SND_CARD_DRIVER, vpcm->nid, + npbs, ncps, &vpcm->pcm); + if (rc) { + dev_err(&vdev->dev, "snd_pcm_new[%u] failed: %d\n", + vpcm->nid, rc); + return rc; + } + + vpcm->pcm->info_flags = 0; + vpcm->pcm->dev_class = SNDRV_PCM_CLASS_GENERIC; + vpcm->pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; + snprintf(vpcm->pcm->name, sizeof(vpcm->pcm->name), + VIRTIO_SND_PCM_NAME " %u", vpcm->pcm->device); + vpcm->pcm->private_data = vpcm; + vpcm->pcm->nonatomic = true; + + for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { + struct virtio_pcm_stream *stream = &vpcm->streams[i]; + + if (!stream->nsubstreams) + continue; + + stream->substreams = + devm_kcalloc(&vdev->dev, stream->nsubstreams, + sizeof(*stream->substreams), + GFP_KERNEL); + if (!stream->substreams) + return -ENOMEM; + + stream->nsubstreams = 0; + } + } + + for (i = 0; i < snd->nsubstreams; ++i) { + struct virtio_pcm_stream *vs; + struct virtio_pcm_substream *vss = &snd->substreams[i]; + + vpcm = virtsnd_pcm_find(snd, vss->nid); + if (IS_ERR(vpcm)) + return PTR_ERR(vpcm); + + vs = &vpcm->streams[vss->direction]; + vs->substreams[vs->nsubstreams++] = vss; + } + + list_for_each_entry(vpcm, &snd->pcm_list, list) { + for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { + struct virtio_pcm_stream *vs = &vpcm->streams[i]; + struct snd_pcm_str *ks = &vpcm->pcm->streams[i]; + struct snd_pcm_substream *kss; + + if (!vs->nsubstreams) + continue; + + for (kss = ks->substream; kss; kss = kss->next) + vs->substreams[kss->number]->substream = kss; + } + + snd_pcm_set_managed_buffer_all(vpcm->pcm, + SNDRV_DMA_TYPE_VMALLOC, NULL, + 0, 0); + } + + return 0; +} diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h new file mode 100644 index 000000000000..84f2f3f14f48 --- /dev/null +++ b/sound/virtio/virtio_pcm.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#ifndef VIRTIO_SND_PCM_H +#define VIRTIO_SND_PCM_H + +#include +#include +#include + +struct virtio_pcm; +struct virtio_pcm_msg; + +/** + * struct virtio_pcm_substream - VirtIO PCM substream. + * @snd: VirtIO sound device. + * @nid: Function group node identifier. + * @sid: Stream identifier. + * @direction: Stream data flow direction (SNDRV_PCM_STREAM_XXX). + * @features: Stream VirtIO feature bit map (1 << VIRTIO_SND_PCM_F_XXX). + * @substream: Kernel ALSA substream. + * @hw: Kernel ALSA substream hardware descriptor. + * @elapsed_period: Kernel work to handle the elapsed period state. + */ +struct virtio_pcm_substream { + struct virtio_snd *snd; + u32 nid; + u32 sid; + u32 direction; + u32 features; + struct snd_pcm_substream *substream; + struct snd_pcm_hardware hw; + struct work_struct elapsed_period; +}; + +/** + * struct virtio_pcm_stream - VirtIO PCM stream. + * @substreams: VirtIO substreams belonging to the stream. + * @nsubstreams: Number of substreams. + */ +struct virtio_pcm_stream { + struct virtio_pcm_substream **substreams; + u32 nsubstreams; +}; + +/** + * struct virtio_pcm - VirtIO PCM device. + * @list: VirtIO PCM list entry. + * @nid: Function group node identifier. + * @pcm: Kernel PCM device. + * @streams: VirtIO PCM streams (playback and capture). + */ +struct virtio_pcm { + struct list_head list; + u32 nid; + struct snd_pcm *pcm; + struct virtio_pcm_stream streams[SNDRV_PCM_STREAM_LAST + 1]; +}; + +int virtsnd_pcm_validate(struct virtio_device *vdev); + +int virtsnd_pcm_parse_cfg(struct virtio_snd *snd); + +int virtsnd_pcm_build_devs(struct virtio_snd *snd); + +struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid); + +struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid); + +#endif /* VIRTIO_SND_PCM_H */ -- cgit v1.2.3-58-ga151 From f40a28679e0b7cb3a9cc6627a8dbb40961990f0a Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:05 +0100 Subject: ALSA: virtio: handling control and I/O messages for the PCM device The driver implements a message-based transport for I/O substream operations. Before the start of the substream, the hardware buffer is sliced into I/O messages, the number of which is equal to the current number of periods. The size of each message is equal to the current size of one period. I/O messages are organized in an ordered queue. The completion of the I/O message indicates an elapsed period (the only exception is the end of the stream for the capture substream). Upon completion, the message is automatically re-added to the end of the queue. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-6-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 3 +- sound/virtio/virtio_card.c | 22 ++- sound/virtio/virtio_card.h | 9 + sound/virtio/virtio_pcm.c | 32 ++++ sound/virtio/virtio_pcm.h | 40 ++++ sound/virtio/virtio_pcm_msg.c | 414 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 515 insertions(+), 5 deletions(-) create mode 100644 sound/virtio/virtio_pcm_msg.c (limited to 'sound') diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 69162a545a41..626af3cc3ed7 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ virtio_card.o \ virtio_ctl_msg.o \ - virtio_pcm.o + virtio_pcm.o \ + virtio_pcm_msg.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 11c76ee311b7..57b9b7f3a9c0 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -55,6 +55,12 @@ static void virtsnd_event_send(struct virtqueue *vqueue, static void virtsnd_event_dispatch(struct virtio_snd *snd, struct virtio_snd_event *event) { + switch (le32_to_cpu(event->hdr.code)) { + case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED: + case VIRTIO_SND_EVT_PCM_XRUN: + virtsnd_pcm_event(snd, event); + break; + } } /** @@ -101,11 +107,15 @@ static int virtsnd_find_vqs(struct virtio_snd *snd) struct virtio_device *vdev = snd->vdev; static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb, - [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb + [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb, + [VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb, + [VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb }; static const char *names[VIRTIO_SND_VQ_MAX] = { [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl", - [VIRTIO_SND_VQ_EVENT] = "virtsnd-event" + [VIRTIO_SND_VQ_EVENT] = "virtsnd-event", + [VIRTIO_SND_VQ_TX] = "virtsnd-tx", + [VIRTIO_SND_VQ_RX] = "virtsnd-rx" }; struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; unsigned int i; @@ -318,8 +328,12 @@ static void virtsnd_remove(struct virtio_device *vdev) vdev->config->del_vqs(vdev); vdev->config->reset(vdev); - for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) - cancel_work_sync(&snd->substreams[i].elapsed_period); + for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) { + struct virtio_pcm_substream *vss = &snd->substreams[i]; + + cancel_work_sync(&vss->elapsed_period); + virtsnd_pcm_msg_free(vss); + } kfree(snd->event_msgs); } diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index 77a1b7255370..c43f9744d362 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -79,4 +79,13 @@ virtsnd_rx_queue(struct virtio_snd *snd) return &snd->queues[VIRTIO_SND_VQ_RX]; } +static inline struct virtio_snd_queue * +virtsnd_pcm_queue(struct virtio_pcm_substream *vss) +{ + if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK) + return virtsnd_tx_queue(vss->snd); + else + return virtsnd_rx_queue(vss->snd); +} + #endif /* VIRTIO_SND_CARD_H */ diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c index e16567e2e214..2dcd763efa29 100644 --- a/sound/virtio/virtio_pcm.c +++ b/sound/virtio/virtio_pcm.c @@ -353,6 +353,8 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd) vss->snd = snd; vss->sid = i; INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); + init_waitqueue_head(&vss->msg_empty); + spin_lock_init(&vss->lock); rc = virtsnd_pcm_build_hw(vss, &info[i]); if (rc) @@ -477,3 +479,33 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd) return 0; } + +/** + * virtsnd_pcm_event() - Handle the PCM device event notification. + * @snd: VirtIO sound device. + * @event: VirtIO sound event. + * + * Context: Interrupt context. + */ +void virtsnd_pcm_event(struct virtio_snd *snd, struct virtio_snd_event *event) +{ + struct virtio_pcm_substream *vss; + u32 sid = le32_to_cpu(event->data); + + if (sid >= snd->nsubstreams) + return; + + vss = &snd->substreams[sid]; + + switch (le32_to_cpu(event->hdr.code)) { + case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED: + /* TODO: deal with shmem elapsed period */ + break; + case VIRTIO_SND_EVT_PCM_XRUN: + spin_lock(&vss->lock); + if (vss->xfer_enabled) + vss->xfer_xrun = true; + spin_unlock(&vss->lock); + break; + } +} diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index 84f2f3f14f48..6722f1139666 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -23,6 +23,17 @@ struct virtio_pcm_msg; * @substream: Kernel ALSA substream. * @hw: Kernel ALSA substream hardware descriptor. * @elapsed_period: Kernel work to handle the elapsed period state. + * @lock: Spinlock that protects fields shared by interrupt handlers and + * substream operators. + * @buffer_bytes: Current buffer size in bytes. + * @hw_ptr: Substream hardware pointer value in bytes [0 ... buffer_bytes). + * @xfer_enabled: Data transfer state (0 - off, 1 - on). + * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun). + * @msgs: Allocated I/O messages. + * @nmsgs: Number of allocated I/O messages. + * @msg_last_enqueued: Index of the last I/O message added to the virtqueue. + * @msg_count: Number of pending I/O messages in the virtqueue. + * @msg_empty: Notify when msg_count is zero. */ struct virtio_pcm_substream { struct virtio_snd *snd; @@ -33,6 +44,16 @@ struct virtio_pcm_substream { struct snd_pcm_substream *substream; struct snd_pcm_hardware hw; struct work_struct elapsed_period; + spinlock_t lock; + size_t buffer_bytes; + size_t hw_ptr; + bool xfer_enabled; + bool xfer_xrun; + struct virtio_pcm_msg **msgs; + unsigned int nmsgs; + int msg_last_enqueued; + unsigned int msg_count; + wait_queue_head_t msg_empty; }; /** @@ -65,8 +86,27 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd); int virtsnd_pcm_build_devs(struct virtio_snd *snd); +void virtsnd_pcm_event(struct virtio_snd *snd, struct virtio_snd_event *event); + +void virtsnd_pcm_tx_notify_cb(struct virtqueue *vqueue); + +void virtsnd_pcm_rx_notify_cb(struct virtqueue *vqueue); + struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid); struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid); +struct virtio_snd_msg * +virtsnd_pcm_ctl_msg_alloc(struct virtio_pcm_substream *vss, + unsigned int command, gfp_t gfp); + +int virtsnd_pcm_msg_alloc(struct virtio_pcm_substream *vss, + unsigned int periods, unsigned int period_bytes); + +void virtsnd_pcm_msg_free(struct virtio_pcm_substream *vss); + +int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss); + +unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss); + #endif /* VIRTIO_SND_PCM_H */ diff --git a/sound/virtio/virtio_pcm_msg.c b/sound/virtio/virtio_pcm_msg.c new file mode 100644 index 000000000000..f88c8f29cbd8 --- /dev/null +++ b/sound/virtio/virtio_pcm_msg.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include + +#include "virtio_card.h" + +/** + * struct virtio_pcm_msg - VirtIO I/O message. + * @substream: VirtIO PCM substream. + * @xfer: Request header payload. + * @status: Response header payload. + * @length: Data length in bytes. + * @sgs: Payload scatter-gather table. + */ +struct virtio_pcm_msg { + struct virtio_pcm_substream *substream; + struct virtio_snd_pcm_xfer xfer; + struct virtio_snd_pcm_status status; + size_t length; + struct scatterlist sgs[0]; +}; + +/** + * enum pcm_msg_sg_index - Index values for the virtio_pcm_msg->sgs field in + * an I/O message. + * @PCM_MSG_SG_XFER: Element containing a virtio_snd_pcm_xfer structure. + * @PCM_MSG_SG_STATUS: Element containing a virtio_snd_pcm_status structure. + * @PCM_MSG_SG_DATA: The first element containing a data buffer. + */ +enum pcm_msg_sg_index { + PCM_MSG_SG_XFER = 0, + PCM_MSG_SG_STATUS, + PCM_MSG_SG_DATA +}; + +/** + * virtsnd_pcm_sg_num() - Count the number of sg-elements required to represent + * vmalloc'ed buffer. + * @data: Pointer to vmalloc'ed buffer. + * @length: Buffer size. + * + * Context: Any context. + * Return: Number of physically contiguous parts in the @data. + */ +static int virtsnd_pcm_sg_num(u8 *data, unsigned int length) +{ + phys_addr_t sg_address; + unsigned int sg_length; + int num = 0; + + while (length) { + struct page *pg = vmalloc_to_page(data); + phys_addr_t pg_address = page_to_phys(pg); + size_t pg_length; + + pg_length = PAGE_SIZE - offset_in_page(data); + if (pg_length > length) + pg_length = length; + + if (!num || sg_address + sg_length != pg_address) { + sg_address = pg_address; + sg_length = pg_length; + num++; + } else { + sg_length += pg_length; + } + + data += pg_length; + length -= pg_length; + } + + return num; +} + +/** + * virtsnd_pcm_sg_from() - Build sg-list from vmalloc'ed buffer. + * @sgs: Preallocated sg-list to populate. + * @nsgs: The maximum number of elements in the @sgs. + * @data: Pointer to vmalloc'ed buffer. + * @length: Buffer size. + * + * Splits the buffer into physically contiguous parts and makes an sg-list of + * such parts. + * + * Context: Any context. + */ +static void virtsnd_pcm_sg_from(struct scatterlist *sgs, int nsgs, u8 *data, + unsigned int length) +{ + int idx = -1; + + while (length) { + struct page *pg = vmalloc_to_page(data); + size_t pg_length; + + pg_length = PAGE_SIZE - offset_in_page(data); + if (pg_length > length) + pg_length = length; + + if (idx == -1 || + sg_phys(&sgs[idx]) + sgs[idx].length != page_to_phys(pg)) { + if (idx + 1 == nsgs) + break; + sg_set_page(&sgs[++idx], pg, pg_length, + offset_in_page(data)); + } else { + sgs[idx].length += pg_length; + } + + data += pg_length; + length -= pg_length; + } + + sg_mark_end(&sgs[idx]); +} + +/** + * virtsnd_pcm_msg_alloc() - Allocate I/O messages. + * @vss: VirtIO PCM substream. + * @periods: Current number of periods. + * @period_bytes: Current period size in bytes. + * + * The function slices the buffer into @periods parts (each with the size of + * @period_bytes), and creates @periods corresponding I/O messages. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -ENOMEM on failure. + */ +int virtsnd_pcm_msg_alloc(struct virtio_pcm_substream *vss, + unsigned int periods, unsigned int period_bytes) +{ + struct snd_pcm_runtime *runtime = vss->substream->runtime; + unsigned int i; + + vss->msgs = kcalloc(periods, sizeof(*vss->msgs), GFP_KERNEL); + if (!vss->msgs) + return -ENOMEM; + + vss->nmsgs = periods; + + for (i = 0; i < periods; ++i) { + u8 *data = runtime->dma_area + period_bytes * i; + int sg_num = virtsnd_pcm_sg_num(data, period_bytes); + struct virtio_pcm_msg *msg; + + msg = kzalloc(sizeof(*msg) + sizeof(*msg->sgs) * (sg_num + 2), + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->substream = vss; + sg_init_one(&msg->sgs[PCM_MSG_SG_XFER], &msg->xfer, + sizeof(msg->xfer)); + sg_init_one(&msg->sgs[PCM_MSG_SG_STATUS], &msg->status, + sizeof(msg->status)); + msg->length = period_bytes; + virtsnd_pcm_sg_from(&msg->sgs[PCM_MSG_SG_DATA], sg_num, data, + period_bytes); + + vss->msgs[i] = msg; + } + + return 0; +} + +/** + * virtsnd_pcm_msg_free() - Free all allocated I/O messages. + * @vss: VirtIO PCM substream. + * + * Context: Any context. + */ +void virtsnd_pcm_msg_free(struct virtio_pcm_substream *vss) +{ + unsigned int i; + + for (i = 0; vss->msgs && i < vss->nmsgs; ++i) + kfree(vss->msgs[i]); + kfree(vss->msgs); + + vss->msgs = NULL; + vss->nmsgs = 0; +} + +/** + * virtsnd_pcm_msg_send() - Send asynchronous I/O messages. + * @vss: VirtIO PCM substream. + * + * All messages are organized in an ordered circular list. Each time the + * function is called, all currently non-enqueued messages are added to the + * virtqueue. For this, the function keeps track of two values: + * + * msg_last_enqueued = index of the last enqueued message, + * msg_count = # of pending messages in the virtqueue. + * + * Context: Any context. Expects the tx/rx queue and the VirtIO substream + * spinlocks to be held by caller. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss) +{ + struct snd_pcm_runtime *runtime = vss->substream->runtime; + struct virtio_snd *snd = vss->snd; + struct virtio_device *vdev = snd->vdev; + struct virtqueue *vqueue = virtsnd_pcm_queue(vss)->vqueue; + int i; + int n; + bool notify = false; + + i = (vss->msg_last_enqueued + 1) % runtime->periods; + n = runtime->periods - vss->msg_count; + + for (; n; --n, i = (i + 1) % runtime->periods) { + struct virtio_pcm_msg *msg = vss->msgs[i]; + struct scatterlist *psgs[] = { + &msg->sgs[PCM_MSG_SG_XFER], + &msg->sgs[PCM_MSG_SG_DATA], + &msg->sgs[PCM_MSG_SG_STATUS] + }; + int rc; + + msg->xfer.stream_id = cpu_to_le32(vss->sid); + memset(&msg->status, 0, sizeof(msg->status)); + + if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK) + rc = virtqueue_add_sgs(vqueue, psgs, 2, 1, msg, + GFP_ATOMIC); + else + rc = virtqueue_add_sgs(vqueue, psgs, 1, 2, msg, + GFP_ATOMIC); + + if (rc) { + dev_err(&vdev->dev, + "SID %u: failed to send I/O message\n", + vss->sid); + return rc; + } + + vss->msg_last_enqueued = i; + vss->msg_count++; + } + + if (!(vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING))) + notify = virtqueue_kick_prepare(vqueue); + + if (notify) + virtqueue_notify(vqueue); + + return 0; +} + +/** + * virtsnd_pcm_msg_pending_num() - Returns the number of pending I/O messages. + * @vss: VirtIO substream. + * + * Context: Any context. + * Return: Number of messages. + */ +unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss) +{ + unsigned int num; + unsigned long flags; + + spin_lock_irqsave(&vss->lock, flags); + num = vss->msg_count; + spin_unlock_irqrestore(&vss->lock, flags); + + return num; +} + +/** + * virtsnd_pcm_msg_complete() - Complete an I/O message. + * @msg: I/O message. + * @written_bytes: Number of bytes written to the message. + * + * Completion of the message means the elapsed period. If transmission is + * allowed, then each completed message is immediately placed back at the end + * of the queue. + * + * For the playback substream, @written_bytes is equal to sizeof(msg->status). + * + * For the capture substream, @written_bytes is equal to sizeof(msg->status) + * plus the number of captured bytes. + * + * Context: Interrupt context. Takes and releases the VirtIO substream spinlock. + */ +static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg, + size_t written_bytes) +{ + struct virtio_pcm_substream *vss = msg->substream; + + /* + * hw_ptr always indicates the buffer position of the first I/O message + * in the virtqueue. Therefore, on each completion of an I/O message, + * the hw_ptr value is unconditionally advanced. + */ + spin_lock(&vss->lock); + /* + * If the capture substream returned an incorrect status, then just + * increase the hw_ptr by the message size. + */ + if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK || + written_bytes <= sizeof(msg->status)) + vss->hw_ptr += msg->length; + else + vss->hw_ptr += written_bytes - sizeof(msg->status); + + if (vss->hw_ptr >= vss->buffer_bytes) + vss->hw_ptr -= vss->buffer_bytes; + + vss->xfer_xrun = false; + vss->msg_count--; + + if (vss->xfer_enabled) { + struct snd_pcm_runtime *runtime = vss->substream->runtime; + + runtime->delay = + bytes_to_frames(runtime, + le32_to_cpu(msg->status.latency_bytes)); + + schedule_work(&vss->elapsed_period); + + virtsnd_pcm_msg_send(vss); + } else if (!vss->msg_count) { + wake_up_all(&vss->msg_empty); + } + spin_unlock(&vss->lock); +} + +/** + * virtsnd_pcm_notify_cb() - Process all completed I/O messages. + * @queue: Underlying tx/rx virtqueue. + * + * Context: Interrupt context. Takes and releases the tx/rx queue spinlock. + */ +static inline void virtsnd_pcm_notify_cb(struct virtio_snd_queue *queue) +{ + struct virtio_pcm_msg *msg; + u32 written_bytes; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + do { + virtqueue_disable_cb(queue->vqueue); + while ((msg = virtqueue_get_buf(queue->vqueue, &written_bytes))) + virtsnd_pcm_msg_complete(msg, written_bytes); + if (unlikely(virtqueue_is_broken(queue->vqueue))) + break; + } while (!virtqueue_enable_cb(queue->vqueue)); + spin_unlock_irqrestore(&queue->lock, flags); +} + +/** + * virtsnd_pcm_tx_notify_cb() - Process all completed TX messages. + * @vqueue: Underlying tx virtqueue. + * + * Context: Interrupt context. + */ +void virtsnd_pcm_tx_notify_cb(struct virtqueue *vqueue) +{ + struct virtio_snd *snd = vqueue->vdev->priv; + + virtsnd_pcm_notify_cb(virtsnd_tx_queue(snd)); +} + +/** + * virtsnd_pcm_rx_notify_cb() - Process all completed RX messages. + * @vqueue: Underlying rx virtqueue. + * + * Context: Interrupt context. + */ +void virtsnd_pcm_rx_notify_cb(struct virtqueue *vqueue) +{ + struct virtio_snd *snd = vqueue->vdev->priv; + + virtsnd_pcm_notify_cb(virtsnd_rx_queue(snd)); +} + +/** + * virtsnd_pcm_ctl_msg_alloc() - Allocate and initialize the PCM device control + * message for the specified substream. + * @vss: VirtIO PCM substream. + * @command: Control request code (VIRTIO_SND_R_PCM_XXX). + * @gfp: Kernel flags for memory allocation. + * + * Context: Any context. May sleep if @gfp flags permit. + * Return: Allocated message on success, NULL on failure. + */ +struct virtio_snd_msg * +virtsnd_pcm_ctl_msg_alloc(struct virtio_pcm_substream *vss, + unsigned int command, gfp_t gfp) +{ + size_t request_size = sizeof(struct virtio_snd_pcm_hdr); + size_t response_size = sizeof(struct virtio_snd_hdr); + struct virtio_snd_msg *msg; + + switch (command) { + case VIRTIO_SND_R_PCM_SET_PARAMS: + request_size = sizeof(struct virtio_snd_pcm_set_params); + break; + } + + msg = virtsnd_ctl_msg_alloc(request_size, response_size, gfp); + if (msg) { + struct virtio_snd_pcm_hdr *hdr = virtsnd_ctl_msg_request(msg); + + hdr->hdr.code = cpu_to_le32(command); + hdr->stream_id = cpu_to_le32(vss->sid); + } + + return msg; +} -- cgit v1.2.3-58-ga151 From da76e9f3e43a7195c69d370ee514cccae6517c76 Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:06 +0100 Subject: ALSA: virtio: PCM substream operators Introduce the operators required for the operation of substreams. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-7-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 3 +- sound/virtio/virtio_pcm.c | 2 + sound/virtio/virtio_pcm.h | 5 + sound/virtio/virtio_pcm_ops.c | 445 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 sound/virtio/virtio_pcm_ops.c (limited to 'sound') diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 626af3cc3ed7..34493226793f 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -6,5 +6,6 @@ virtio_snd-objs := \ virtio_card.o \ virtio_ctl_msg.o \ virtio_pcm.o \ - virtio_pcm_msg.o + virtio_pcm_msg.o \ + virtio_pcm_ops.o diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c index 2dcd763efa29..c10d91fff2fb 100644 --- a/sound/virtio/virtio_pcm.c +++ b/sound/virtio/virtio_pcm.c @@ -470,6 +470,8 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd) for (kss = ks->substream; kss; kss = kss->next) vs->substreams[kss->number]->substream = kss; + + snd_pcm_set_ops(vpcm->pcm, i, &virtsnd_pcm_ops); } snd_pcm_set_managed_buffer_all(vpcm->pcm, diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index 6722f1139666..efd0228746cf 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -29,6 +29,8 @@ struct virtio_pcm_msg; * @hw_ptr: Substream hardware pointer value in bytes [0 ... buffer_bytes). * @xfer_enabled: Data transfer state (0 - off, 1 - on). * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun). + * @stopped: True if the substream is stopped and must be released on the device + * side. * @msgs: Allocated I/O messages. * @nmsgs: Number of allocated I/O messages. * @msg_last_enqueued: Index of the last I/O message added to the virtqueue. @@ -49,6 +51,7 @@ struct virtio_pcm_substream { size_t hw_ptr; bool xfer_enabled; bool xfer_xrun; + bool stopped; struct virtio_pcm_msg **msgs; unsigned int nmsgs; int msg_last_enqueued; @@ -80,6 +83,8 @@ struct virtio_pcm { struct virtio_pcm_stream streams[SNDRV_PCM_STREAM_LAST + 1]; }; +extern const struct snd_pcm_ops virtsnd_pcm_ops; + int virtsnd_pcm_validate(struct virtio_device *vdev); int virtsnd_pcm_parse_cfg(struct virtio_snd *snd); diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c new file mode 100644 index 000000000000..0682a2df6c8c --- /dev/null +++ b/sound/virtio/virtio_pcm_ops.c @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include + +#include "virtio_card.h" + +/* + * I/O messages lifetime + * --------------------- + * + * Allocation: + * Messages are initially allocated in the ops->hw_params() after the size and + * number of periods have been successfully negotiated. + * + * Freeing: + * Messages can be safely freed after the queue has been successfully flushed + * (RELEASE command in the ops->sync_stop()) and the ops->hw_free() has been + * called. + * + * When the substream stops, the ops->sync_stop() waits until the device has + * completed all pending messages. This wait can be interrupted either by a + * signal or due to a timeout. In this case, the device can still access + * messages even after calling ops->hw_free(). It can also issue an interrupt, + * and the interrupt handler will also try to access message structures. + * + * Therefore, freeing of already allocated messages occurs: + * + * - in ops->hw_params(), if this operator was called several times in a row, + * or if ops->hw_free() failed to free messages previously; + * + * - in ops->hw_free(), if the queue has been successfully flushed; + * + * - in dev->release(). + */ + +/* Map for converting ALSA format to VirtIO format. */ +struct virtsnd_a2v_format { + snd_pcm_format_t alsa_bit; + unsigned int vio_bit; +}; + +static const struct virtsnd_a2v_format g_a2v_format_map[] = { + { SNDRV_PCM_FORMAT_IMA_ADPCM, VIRTIO_SND_PCM_FMT_IMA_ADPCM }, + { SNDRV_PCM_FORMAT_MU_LAW, VIRTIO_SND_PCM_FMT_MU_LAW }, + { SNDRV_PCM_FORMAT_A_LAW, VIRTIO_SND_PCM_FMT_A_LAW }, + { SNDRV_PCM_FORMAT_S8, VIRTIO_SND_PCM_FMT_S8 }, + { SNDRV_PCM_FORMAT_U8, VIRTIO_SND_PCM_FMT_U8 }, + { SNDRV_PCM_FORMAT_S16_LE, VIRTIO_SND_PCM_FMT_S16 }, + { SNDRV_PCM_FORMAT_U16_LE, VIRTIO_SND_PCM_FMT_U16 }, + { SNDRV_PCM_FORMAT_S18_3LE, VIRTIO_SND_PCM_FMT_S18_3 }, + { SNDRV_PCM_FORMAT_U18_3LE, VIRTIO_SND_PCM_FMT_U18_3 }, + { SNDRV_PCM_FORMAT_S20_3LE, VIRTIO_SND_PCM_FMT_S20_3 }, + { SNDRV_PCM_FORMAT_U20_3LE, VIRTIO_SND_PCM_FMT_U20_3 }, + { SNDRV_PCM_FORMAT_S24_3LE, VIRTIO_SND_PCM_FMT_S24_3 }, + { SNDRV_PCM_FORMAT_U24_3LE, VIRTIO_SND_PCM_FMT_U24_3 }, + { SNDRV_PCM_FORMAT_S20_LE, VIRTIO_SND_PCM_FMT_S20 }, + { SNDRV_PCM_FORMAT_U20_LE, VIRTIO_SND_PCM_FMT_U20 }, + { SNDRV_PCM_FORMAT_S24_LE, VIRTIO_SND_PCM_FMT_S24 }, + { SNDRV_PCM_FORMAT_U24_LE, VIRTIO_SND_PCM_FMT_U24 }, + { SNDRV_PCM_FORMAT_S32_LE, VIRTIO_SND_PCM_FMT_S32 }, + { SNDRV_PCM_FORMAT_U32_LE, VIRTIO_SND_PCM_FMT_U32 }, + { SNDRV_PCM_FORMAT_FLOAT_LE, VIRTIO_SND_PCM_FMT_FLOAT }, + { SNDRV_PCM_FORMAT_FLOAT64_LE, VIRTIO_SND_PCM_FMT_FLOAT64 }, + { SNDRV_PCM_FORMAT_DSD_U8, VIRTIO_SND_PCM_FMT_DSD_U8 }, + { SNDRV_PCM_FORMAT_DSD_U16_LE, VIRTIO_SND_PCM_FMT_DSD_U16 }, + { SNDRV_PCM_FORMAT_DSD_U32_LE, VIRTIO_SND_PCM_FMT_DSD_U32 }, + { SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, + VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME } +}; + +/* Map for converting ALSA frame rate to VirtIO frame rate. */ +struct virtsnd_a2v_rate { + unsigned int rate; + unsigned int vio_bit; +}; + +static const struct virtsnd_a2v_rate g_a2v_rate_map[] = { + { 5512, VIRTIO_SND_PCM_RATE_5512 }, + { 8000, VIRTIO_SND_PCM_RATE_8000 }, + { 11025, VIRTIO_SND_PCM_RATE_11025 }, + { 16000, VIRTIO_SND_PCM_RATE_16000 }, + { 22050, VIRTIO_SND_PCM_RATE_22050 }, + { 32000, VIRTIO_SND_PCM_RATE_32000 }, + { 44100, VIRTIO_SND_PCM_RATE_44100 }, + { 48000, VIRTIO_SND_PCM_RATE_48000 }, + { 64000, VIRTIO_SND_PCM_RATE_64000 }, + { 88200, VIRTIO_SND_PCM_RATE_88200 }, + { 96000, VIRTIO_SND_PCM_RATE_96000 }, + { 176400, VIRTIO_SND_PCM_RATE_176400 }, + { 192000, VIRTIO_SND_PCM_RATE_192000 } +}; + +static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream); + +/** + * virtsnd_pcm_open() - Open the PCM substream. + * @substream: Kernel ALSA substream. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_open(struct snd_pcm_substream *substream) +{ + struct virtio_pcm *vpcm = snd_pcm_substream_chip(substream); + struct virtio_pcm_stream *vs = &vpcm->streams[substream->stream]; + struct virtio_pcm_substream *vss = vs->substreams[substream->number]; + + substream->runtime->hw = vss->hw; + substream->private_data = vss; + + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + vss->stopped = !!virtsnd_pcm_msg_pending_num(vss); + + /* + * If the substream has already been used, then the I/O queue may be in + * an invalid state. Just in case, we do a check and try to return the + * queue to its original state, if necessary. + */ + return virtsnd_pcm_sync_stop(substream); +} + +/** + * virtsnd_pcm_close() - Close the PCM substream. + * @substream: Kernel ALSA substream. + * + * Context: Process context. + * Return: 0. + */ +static int virtsnd_pcm_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/** + * virtsnd_pcm_dev_set_params() - Set the parameters of the PCM substream on + * the device side. + * @vss: VirtIO PCM substream. + * @buffer_bytes: Size of the hardware buffer. + * @period_bytes: Size of the hardware period. + * @channels: Selected number of channels. + * @format: Selected sample format (SNDRV_PCM_FORMAT_XXX). + * @rate: Selected frame rate. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_dev_set_params(struct virtio_pcm_substream *vss, + unsigned int buffer_bytes, + unsigned int period_bytes, + unsigned int channels, + snd_pcm_format_t format, + unsigned int rate) +{ + struct virtio_snd_msg *msg; + struct virtio_snd_pcm_set_params *request; + unsigned int i; + int vformat = -1; + int vrate = -1; + + for (i = 0; i < ARRAY_SIZE(g_a2v_format_map); ++i) + if (g_a2v_format_map[i].alsa_bit == format) { + vformat = g_a2v_format_map[i].vio_bit; + + break; + } + + for (i = 0; i < ARRAY_SIZE(g_a2v_rate_map); ++i) + if (g_a2v_rate_map[i].rate == rate) { + vrate = g_a2v_rate_map[i].vio_bit; + + break; + } + + if (vformat == -1 || vrate == -1) + return -EINVAL; + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_SET_PARAMS, + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + request = virtsnd_ctl_msg_request(msg); + request->buffer_bytes = cpu_to_le32(buffer_bytes); + request->period_bytes = cpu_to_le32(period_bytes); + request->channels = channels; + request->format = vformat; + request->rate = vrate; + + if (vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING)) + request->features |= + cpu_to_le32(1U << VIRTIO_SND_PCM_F_MSG_POLLING); + + if (vss->features & (1U << VIRTIO_SND_PCM_F_EVT_XRUNS)) + request->features |= + cpu_to_le32(1U << VIRTIO_SND_PCM_F_EVT_XRUNS); + + return virtsnd_ctl_msg_send_sync(vss->snd, msg); +} + +/** + * virtsnd_pcm_hw_params() - Set the parameters of the PCM substream. + * @substream: Kernel ALSA substream. + * @hw_params: Hardware parameters. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + struct virtio_device *vdev = vss->snd->vdev; + int rc; + + if (virtsnd_pcm_msg_pending_num(vss)) { + dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", + vss->sid); + return -EBADFD; + } + + rc = virtsnd_pcm_dev_set_params(vss, params_buffer_bytes(hw_params), + params_period_bytes(hw_params), + params_channels(hw_params), + params_format(hw_params), + params_rate(hw_params)); + if (rc) + return rc; + + /* + * Free previously allocated messages if ops->hw_params() is called + * several times in a row, or if ops->hw_free() failed to free messages. + */ + virtsnd_pcm_msg_free(vss); + + return virtsnd_pcm_msg_alloc(vss, params_periods(hw_params), + params_period_bytes(hw_params)); +} + +/** + * virtsnd_pcm_hw_free() - Reset the parameters of the PCM substream. + * @substream: Kernel ALSA substream. + * + * Context: Process context. + * Return: 0 + */ +static int virtsnd_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + + /* If the queue is flushed, we can safely free the messages here. */ + if (!virtsnd_pcm_msg_pending_num(vss)) + virtsnd_pcm_msg_free(vss); + + return 0; +} + +/** + * virtsnd_pcm_prepare() - Prepare the PCM substream. + * @substream: Kernel ALSA substream. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + struct virtio_device *vdev = vss->snd->vdev; + struct virtio_snd_msg *msg; + + if (virtsnd_pcm_msg_pending_num(vss)) { + dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", + vss->sid); + return -EBADFD; + } + + vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + vss->hw_ptr = 0; + vss->xfer_xrun = false; + vss->msg_last_enqueued = -1; + vss->msg_count = 0; + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE, + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + return virtsnd_ctl_msg_send_sync(vss->snd, msg); +} + +/** + * virtsnd_pcm_trigger() - Process command for the PCM substream. + * @substream: Kernel ALSA substream. + * @command: Substream command (SNDRV_PCM_TRIGGER_XXX). + * + * Context: Any context. Takes and releases the VirtIO substream spinlock. + * May take and release the tx/rx queue spinlock. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + struct virtio_snd *snd = vss->snd; + struct virtio_snd_queue *queue; + struct virtio_snd_msg *msg; + unsigned long flags; + int rc; + + switch (command) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + queue = virtsnd_pcm_queue(vss); + + spin_lock_irqsave(&queue->lock, flags); + spin_lock(&vss->lock); + rc = virtsnd_pcm_msg_send(vss); + if (!rc) + vss->xfer_enabled = true; + spin_unlock(&vss->lock); + spin_unlock_irqrestore(&queue->lock, flags); + if (rc) + return rc; + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_START, + GFP_KERNEL); + if (!msg) { + spin_lock_irqsave(&vss->lock, flags); + vss->xfer_enabled = false; + spin_unlock_irqrestore(&vss->lock, flags); + + return -ENOMEM; + } + + return virtsnd_ctl_msg_send_sync(snd, msg); + case SNDRV_PCM_TRIGGER_STOP: + vss->stopped = true; + fallthrough; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock_irqsave(&vss->lock, flags); + vss->xfer_enabled = false; + spin_unlock_irqrestore(&vss->lock, flags); + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_STOP, + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + return virtsnd_ctl_msg_send_sync(snd, msg); + default: + return -EINVAL; + } +} + +/** + * virtsnd_pcm_sync_stop() - Synchronous PCM substream stop. + * @substream: Kernel ALSA substream. + * + * The function can be called both from the upper level or from the driver + * itself. + * + * Context: Process context. Takes and releases the VirtIO substream spinlock. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + struct virtio_snd *snd = vss->snd; + struct virtio_snd_msg *msg; + unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms); + int rc; + + cancel_work_sync(&vss->elapsed_period); + + if (!vss->stopped) + return 0; + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_RELEASE, + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + rc = virtsnd_ctl_msg_send_sync(snd, msg); + if (rc) + return rc; + + /* + * The spec states that upon receipt of the RELEASE command "the device + * MUST complete all pending I/O messages for the specified stream ID". + * Thus, we consider the absence of I/O messages in the queue as an + * indication that the substream has been released. + */ + rc = wait_event_interruptible_timeout(vss->msg_empty, + !virtsnd_pcm_msg_pending_num(vss), + js); + if (rc <= 0) { + dev_warn(&snd->vdev->dev, "SID %u: failed to flush I/O queue\n", + vss->sid); + + return !rc ? -ETIMEDOUT : rc; + } + + vss->stopped = false; + + return 0; +} + +/** + * virtsnd_pcm_pointer() - Get the current hardware position for the PCM + * substream. + * @substream: Kernel ALSA substream. + * + * Context: Any context. Takes and releases the VirtIO substream spinlock. + * Return: Hardware position in frames inside [0 ... buffer_size) range. + */ +static snd_pcm_uframes_t +virtsnd_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + snd_pcm_uframes_t hw_ptr = SNDRV_PCM_POS_XRUN; + unsigned long flags; + + spin_lock_irqsave(&vss->lock, flags); + if (!vss->xfer_xrun) + hw_ptr = bytes_to_frames(substream->runtime, vss->hw_ptr); + spin_unlock_irqrestore(&vss->lock, flags); + + return hw_ptr; +} + +/* PCM substream operators map. */ +const struct snd_pcm_ops virtsnd_pcm_ops = { + .open = virtsnd_pcm_open, + .close = virtsnd_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = virtsnd_pcm_hw_params, + .hw_free = virtsnd_pcm_hw_free, + .prepare = virtsnd_pcm_prepare, + .trigger = virtsnd_pcm_trigger, + .sync_stop = virtsnd_pcm_sync_stop, + .pointer = virtsnd_pcm_pointer, +}; -- cgit v1.2.3-58-ga151 From ca61a41f389c80db091db9d4ad5a651e2b4c9f70 Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:07 +0100 Subject: ALSA: virtio: introduce jack support Enumerate all available jacks and create ALSA controls. At the moment jacks have a simple implementation and can only be used to receive notifications about a plugged in/out device. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-8-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 1 + sound/virtio/virtio_card.c | 14 +++ sound/virtio/virtio_card.h | 12 +++ sound/virtio/virtio_jack.c | 233 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 260 insertions(+) create mode 100644 sound/virtio/virtio_jack.c (limited to 'sound') diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 34493226793f..09f485291285 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ virtio_card.o \ virtio_ctl_msg.o \ + virtio_jack.o \ virtio_pcm.o \ virtio_pcm_msg.o \ virtio_pcm_ops.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 57b9b7f3a9c0..89bd66c1256e 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -56,6 +56,10 @@ static void virtsnd_event_dispatch(struct virtio_snd *snd, struct virtio_snd_event *event) { switch (le32_to_cpu(event->hdr.code)) { + case VIRTIO_SND_EVT_JACK_CONNECTED: + case VIRTIO_SND_EVT_JACK_DISCONNECTED: + virtsnd_jack_event(snd, event); + break; case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED: case VIRTIO_SND_EVT_PCM_XRUN: virtsnd_pcm_event(snd, event); @@ -219,10 +223,20 @@ static int virtsnd_build_devs(struct virtio_snd *snd) VIRTIO_SND_CARD_NAME " at %s/%s", dev_name(dev->parent), dev_name(dev)); + rc = virtsnd_jack_parse_cfg(snd); + if (rc) + return rc; + rc = virtsnd_pcm_parse_cfg(snd); if (rc) return rc; + if (snd->njacks) { + rc = virtsnd_jack_build_devs(snd); + if (rc) + return rc; + } + if (snd->nsubstreams) { rc = virtsnd_pcm_build_devs(snd); if (rc) diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index c43f9744d362..f154313c79fd 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -18,6 +18,7 @@ #define VIRTIO_SND_CARD_NAME "VirtIO SoundCard" #define VIRTIO_SND_PCM_NAME "VirtIO PCM" +struct virtio_jack; struct virtio_pcm_substream; /** @@ -38,6 +39,8 @@ struct virtio_snd_queue { * @ctl_msgs: Pending control request list. * @event_msgs: Device events. * @pcm_list: VirtIO PCM device list. + * @jacks: VirtIO jacks. + * @njacks: Number of jacks. * @substreams: VirtIO PCM substreams. * @nsubstreams: Number of PCM substreams. */ @@ -48,6 +51,8 @@ struct virtio_snd { struct list_head ctl_msgs; struct virtio_snd_event *event_msgs; struct list_head pcm_list; + struct virtio_jack *jacks; + u32 njacks; struct virtio_pcm_substream *substreams; u32 nsubstreams; }; @@ -88,4 +93,11 @@ virtsnd_pcm_queue(struct virtio_pcm_substream *vss) return virtsnd_rx_queue(vss->snd); } +int virtsnd_jack_parse_cfg(struct virtio_snd *snd); + +int virtsnd_jack_build_devs(struct virtio_snd *snd); + +void virtsnd_jack_event(struct virtio_snd *snd, + struct virtio_snd_event *event); + #endif /* VIRTIO_SND_CARD_H */ diff --git a/sound/virtio/virtio_jack.c b/sound/virtio/virtio_jack.c new file mode 100644 index 000000000000..c69f1dcdcc84 --- /dev/null +++ b/sound/virtio/virtio_jack.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include +#include +#include + +#include "virtio_card.h" + +/** + * DOC: Implementation Status + * + * At the moment jacks have a simple implementation and can only be used to + * receive notifications about a plugged in/out device. + * + * VIRTIO_SND_R_JACK_REMAP + * is not supported + */ + +/** + * struct virtio_jack - VirtIO jack. + * @jack: Kernel jack control. + * @nid: Functional group node identifier. + * @features: Jack virtio feature bit map (1 << VIRTIO_SND_JACK_F_XXX). + * @defconf: Pin default configuration value. + * @caps: Pin capabilities value. + * @connected: Current jack connection status. + * @type: Kernel jack type (SND_JACK_XXX). + */ +struct virtio_jack { + struct snd_jack *jack; + u32 nid; + u32 features; + u32 defconf; + u32 caps; + bool connected; + int type; +}; + +/** + * virtsnd_jack_get_label() - Get the name string for the jack. + * @vjack: VirtIO jack. + * + * Returns the jack name based on the default pin configuration value (see HDA + * specification). + * + * Context: Any context. + * Return: Name string. + */ +static const char *virtsnd_jack_get_label(struct virtio_jack *vjack) +{ + unsigned int defconf = vjack->defconf; + unsigned int device = + (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT; + unsigned int location = + (defconf & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; + + switch (device) { + case AC_JACK_LINE_OUT: + return "Line Out"; + case AC_JACK_SPEAKER: + return "Speaker"; + case AC_JACK_HP_OUT: + return "Headphone"; + case AC_JACK_CD: + return "CD"; + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + if (location == AC_JACK_LOC_HDMI) + return "HDMI Out"; + else + return "SPDIF Out"; + case AC_JACK_LINE_IN: + return "Line"; + case AC_JACK_AUX: + return "Aux"; + case AC_JACK_MIC_IN: + return "Mic"; + case AC_JACK_SPDIF_IN: + return "SPDIF In"; + case AC_JACK_DIG_OTHER_IN: + return "Digital In"; + default: + return "Misc"; + } +} + +/** + * virtsnd_jack_get_type() - Get the type for the jack. + * @vjack: VirtIO jack. + * + * Returns the jack type based on the default pin configuration value (see HDA + * specification). + * + * Context: Any context. + * Return: SND_JACK_XXX value. + */ +static int virtsnd_jack_get_type(struct virtio_jack *vjack) +{ + unsigned int defconf = vjack->defconf; + unsigned int device = + (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT; + + switch (device) { + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + return SND_JACK_LINEOUT; + case AC_JACK_HP_OUT: + return SND_JACK_HEADPHONE; + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + return SND_JACK_AVOUT; + case AC_JACK_MIC_IN: + return SND_JACK_MICROPHONE; + default: + return SND_JACK_LINEIN; + } +} + +/** + * virtsnd_jack_parse_cfg() - Parse the jack configuration. + * @snd: VirtIO sound device. + * + * This function is called during initial device initialization. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_jack_parse_cfg(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_snd_jack_info *info; + u32 i; + int rc; + + virtio_cread_le(vdev, struct virtio_snd_config, jacks, &snd->njacks); + if (!snd->njacks) + return 0; + + snd->jacks = devm_kcalloc(&vdev->dev, snd->njacks, sizeof(*snd->jacks), + GFP_KERNEL); + if (!snd->jacks) + return -ENOMEM; + + info = kcalloc(snd->njacks, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_JACK_INFO, 0, snd->njacks, + sizeof(*info), info); + if (rc) + goto on_exit; + + for (i = 0; i < snd->njacks; ++i) { + struct virtio_jack *vjack = &snd->jacks[i]; + + vjack->nid = le32_to_cpu(info[i].hdr.hda_fn_nid); + vjack->features = le32_to_cpu(info[i].features); + vjack->defconf = le32_to_cpu(info[i].hda_reg_defconf); + vjack->caps = le32_to_cpu(info[i].hda_reg_caps); + vjack->connected = info[i].connected; + } + +on_exit: + kfree(info); + + return rc; +} + +/** + * virtsnd_jack_build_devs() - Build ALSA controls for jacks. + * @snd: VirtIO sound device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_jack_build_devs(struct virtio_snd *snd) +{ + u32 i; + int rc; + + for (i = 0; i < snd->njacks; ++i) { + struct virtio_jack *vjack = &snd->jacks[i]; + + vjack->type = virtsnd_jack_get_type(vjack); + + rc = snd_jack_new(snd->card, virtsnd_jack_get_label(vjack), + vjack->type, &vjack->jack, true, true); + if (rc) + return rc; + + if (vjack->jack) + vjack->jack->private_data = vjack; + + snd_jack_report(vjack->jack, + vjack->connected ? vjack->type : 0); + } + + return 0; +} + +/** + * virtsnd_jack_event() - Handle the jack event notification. + * @snd: VirtIO sound device. + * @event: VirtIO sound event. + * + * Context: Interrupt context. + */ +void virtsnd_jack_event(struct virtio_snd *snd, struct virtio_snd_event *event) +{ + u32 jack_id = le32_to_cpu(event->data); + struct virtio_jack *vjack; + + if (jack_id >= snd->njacks) + return; + + vjack = &snd->jacks[jack_id]; + + switch (le32_to_cpu(event->hdr.code)) { + case VIRTIO_SND_EVT_JACK_CONNECTED: + vjack->connected = true; + break; + case VIRTIO_SND_EVT_JACK_DISCONNECTED: + vjack->connected = false; + break; + default: + return; + } + + snd_jack_report(vjack->jack, vjack->connected ? vjack->type : 0); +} -- cgit v1.2.3-58-ga151 From 19325fedf245ca932c58a629d3888a9a393534ab Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:08 +0100 Subject: ALSA: virtio: introduce PCM channel map support Enumerate all available PCM channel maps and create ALSA controls. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-9-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 1 + sound/virtio/virtio_card.c | 10 ++ sound/virtio/virtio_card.h | 8 ++ sound/virtio/virtio_chmap.c | 219 ++++++++++++++++++++++++++++++++++++++++++++ sound/virtio/virtio_pcm.h | 4 + 5 files changed, 242 insertions(+) create mode 100644 sound/virtio/virtio_chmap.c (limited to 'sound') diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 09f485291285..2742bddb8874 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ virtio_card.o \ + virtio_chmap.o \ virtio_ctl_msg.o \ virtio_jack.o \ virtio_pcm.o \ diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 89bd66c1256e..1c03fcc41c3b 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -231,6 +231,10 @@ static int virtsnd_build_devs(struct virtio_snd *snd) if (rc) return rc; + rc = virtsnd_chmap_parse_cfg(snd); + if (rc) + return rc; + if (snd->njacks) { rc = virtsnd_jack_build_devs(snd); if (rc) @@ -243,6 +247,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd) return rc; } + if (snd->nchmaps) { + rc = virtsnd_chmap_build_devs(snd); + if (rc) + return rc; + } + return snd_card_register(snd->card); } diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index f154313c79fd..86ef3941895e 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -43,6 +43,8 @@ struct virtio_snd_queue { * @njacks: Number of jacks. * @substreams: VirtIO PCM substreams. * @nsubstreams: Number of PCM substreams. + * @chmaps: VirtIO channel maps. + * @nchmaps: Number of channel maps. */ struct virtio_snd { struct virtio_device *vdev; @@ -55,6 +57,8 @@ struct virtio_snd { u32 njacks; struct virtio_pcm_substream *substreams; u32 nsubstreams; + struct virtio_snd_chmap_info *chmaps; + u32 nchmaps; }; /* Message completion timeout in milliseconds (module parameter). */ @@ -100,4 +104,8 @@ int virtsnd_jack_build_devs(struct virtio_snd *snd); void virtsnd_jack_event(struct virtio_snd *snd, struct virtio_snd_event *event); +int virtsnd_chmap_parse_cfg(struct virtio_snd *snd); + +int virtsnd_chmap_build_devs(struct virtio_snd *snd); + #endif /* VIRTIO_SND_CARD_H */ diff --git a/sound/virtio/virtio_chmap.c b/sound/virtio/virtio_chmap.c new file mode 100644 index 000000000000..5bc924933a59 --- /dev/null +++ b/sound/virtio/virtio_chmap.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include + +#include "virtio_card.h" + +/* VirtIO->ALSA channel position map */ +static const u8 g_v2a_position_map[] = { + [VIRTIO_SND_CHMAP_NONE] = SNDRV_CHMAP_UNKNOWN, + [VIRTIO_SND_CHMAP_NA] = SNDRV_CHMAP_NA, + [VIRTIO_SND_CHMAP_MONO] = SNDRV_CHMAP_MONO, + [VIRTIO_SND_CHMAP_FL] = SNDRV_CHMAP_FL, + [VIRTIO_SND_CHMAP_FR] = SNDRV_CHMAP_FR, + [VIRTIO_SND_CHMAP_RL] = SNDRV_CHMAP_RL, + [VIRTIO_SND_CHMAP_RR] = SNDRV_CHMAP_RR, + [VIRTIO_SND_CHMAP_FC] = SNDRV_CHMAP_FC, + [VIRTIO_SND_CHMAP_LFE] = SNDRV_CHMAP_LFE, + [VIRTIO_SND_CHMAP_SL] = SNDRV_CHMAP_SL, + [VIRTIO_SND_CHMAP_SR] = SNDRV_CHMAP_SR, + [VIRTIO_SND_CHMAP_RC] = SNDRV_CHMAP_RC, + [VIRTIO_SND_CHMAP_FLC] = SNDRV_CHMAP_FLC, + [VIRTIO_SND_CHMAP_FRC] = SNDRV_CHMAP_FRC, + [VIRTIO_SND_CHMAP_RLC] = SNDRV_CHMAP_RLC, + [VIRTIO_SND_CHMAP_RRC] = SNDRV_CHMAP_RRC, + [VIRTIO_SND_CHMAP_FLW] = SNDRV_CHMAP_FLW, + [VIRTIO_SND_CHMAP_FRW] = SNDRV_CHMAP_FRW, + [VIRTIO_SND_CHMAP_FLH] = SNDRV_CHMAP_FLH, + [VIRTIO_SND_CHMAP_FCH] = SNDRV_CHMAP_FCH, + [VIRTIO_SND_CHMAP_FRH] = SNDRV_CHMAP_FRH, + [VIRTIO_SND_CHMAP_TC] = SNDRV_CHMAP_TC, + [VIRTIO_SND_CHMAP_TFL] = SNDRV_CHMAP_TFL, + [VIRTIO_SND_CHMAP_TFR] = SNDRV_CHMAP_TFR, + [VIRTIO_SND_CHMAP_TFC] = SNDRV_CHMAP_TFC, + [VIRTIO_SND_CHMAP_TRL] = SNDRV_CHMAP_TRL, + [VIRTIO_SND_CHMAP_TRR] = SNDRV_CHMAP_TRR, + [VIRTIO_SND_CHMAP_TRC] = SNDRV_CHMAP_TRC, + [VIRTIO_SND_CHMAP_TFLC] = SNDRV_CHMAP_TFLC, + [VIRTIO_SND_CHMAP_TFRC] = SNDRV_CHMAP_TFRC, + [VIRTIO_SND_CHMAP_TSL] = SNDRV_CHMAP_TSL, + [VIRTIO_SND_CHMAP_TSR] = SNDRV_CHMAP_TSR, + [VIRTIO_SND_CHMAP_LLFE] = SNDRV_CHMAP_LLFE, + [VIRTIO_SND_CHMAP_RLFE] = SNDRV_CHMAP_RLFE, + [VIRTIO_SND_CHMAP_BC] = SNDRV_CHMAP_BC, + [VIRTIO_SND_CHMAP_BLC] = SNDRV_CHMAP_BLC, + [VIRTIO_SND_CHMAP_BRC] = SNDRV_CHMAP_BRC +}; + +/** + * virtsnd_chmap_parse_cfg() - Parse the channel map configuration. + * @snd: VirtIO sound device. + * + * This function is called during initial device initialization. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_chmap_parse_cfg(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + u32 i; + int rc; + + virtio_cread_le(vdev, struct virtio_snd_config, chmaps, &snd->nchmaps); + if (!snd->nchmaps) + return 0; + + snd->chmaps = devm_kcalloc(&vdev->dev, snd->nchmaps, + sizeof(*snd->chmaps), GFP_KERNEL); + if (!snd->chmaps) + return -ENOMEM; + + rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_CHMAP_INFO, 0, + snd->nchmaps, sizeof(*snd->chmaps), + snd->chmaps); + if (rc) + return rc; + + /* Count the number of channel maps per each PCM device/stream. */ + for (i = 0; i < snd->nchmaps; ++i) { + struct virtio_snd_chmap_info *info = &snd->chmaps[i]; + u32 nid = le32_to_cpu(info->hdr.hda_fn_nid); + struct virtio_pcm *vpcm; + struct virtio_pcm_stream *vs; + + vpcm = virtsnd_pcm_find_or_create(snd, nid); + if (IS_ERR(vpcm)) + return PTR_ERR(vpcm); + + switch (info->direction) { + case VIRTIO_SND_D_OUTPUT: + vs = &vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; + break; + case VIRTIO_SND_D_INPUT: + vs = &vpcm->streams[SNDRV_PCM_STREAM_CAPTURE]; + break; + default: + dev_err(&vdev->dev, + "chmap #%u: unknown direction (%u)\n", i, + info->direction); + return -EINVAL; + } + + vs->nchmaps++; + } + + return 0; +} + +/** + * virtsnd_chmap_add_ctls() - Create an ALSA control for channel maps. + * @pcm: ALSA PCM device. + * @direction: PCM stream direction (SNDRV_PCM_STREAM_XXX). + * @vs: VirtIO PCM stream. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_chmap_add_ctls(struct snd_pcm *pcm, int direction, + struct virtio_pcm_stream *vs) +{ + u32 i; + int max_channels = 0; + + for (i = 0; i < vs->nchmaps; i++) + if (max_channels < vs->chmaps[i].channels) + max_channels = vs->chmaps[i].channels; + + return snd_pcm_add_chmap_ctls(pcm, direction, vs->chmaps, max_channels, + 0, NULL); +} + +/** + * virtsnd_chmap_build_devs() - Build ALSA controls for channel maps. + * @snd: VirtIO sound device. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_chmap_build_devs(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_pcm *vpcm; + struct virtio_pcm_stream *vs; + u32 i; + int rc; + + /* Allocate channel map elements per each PCM device/stream. */ + list_for_each_entry(vpcm, &snd->pcm_list, list) { + for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { + vs = &vpcm->streams[i]; + + if (!vs->nchmaps) + continue; + + vs->chmaps = devm_kcalloc(&vdev->dev, vs->nchmaps + 1, + sizeof(*vs->chmaps), + GFP_KERNEL); + if (!vs->chmaps) + return -ENOMEM; + + vs->nchmaps = 0; + } + } + + /* Initialize channel maps per each PCM device/stream. */ + for (i = 0; i < snd->nchmaps; ++i) { + struct virtio_snd_chmap_info *info = &snd->chmaps[i]; + unsigned int channels = info->channels; + unsigned int ch; + struct snd_pcm_chmap_elem *chmap; + + vpcm = virtsnd_pcm_find(snd, le32_to_cpu(info->hdr.hda_fn_nid)); + if (IS_ERR(vpcm)) + return PTR_ERR(vpcm); + + if (info->direction == VIRTIO_SND_D_OUTPUT) + vs = &vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; + else + vs = &vpcm->streams[SNDRV_PCM_STREAM_CAPTURE]; + + chmap = &vs->chmaps[vs->nchmaps++]; + + if (channels > ARRAY_SIZE(chmap->map)) + channels = ARRAY_SIZE(chmap->map); + + chmap->channels = channels; + + for (ch = 0; ch < channels; ++ch) { + u8 position = info->positions[ch]; + + if (position >= ARRAY_SIZE(g_v2a_position_map)) + return -EINVAL; + + chmap->map[ch] = g_v2a_position_map[position]; + } + } + + /* Create an ALSA control per each PCM device/stream. */ + list_for_each_entry(vpcm, &snd->pcm_list, list) { + if (!vpcm->pcm) + continue; + + for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { + vs = &vpcm->streams[i]; + + if (!vs->nchmaps) + continue; + + rc = virtsnd_chmap_add_ctls(vpcm->pcm, i, vs); + if (rc) + return rc; + } + } + + return 0; +} diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index efd0228746cf..1353fdc9bd69 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -63,10 +63,14 @@ struct virtio_pcm_substream { * struct virtio_pcm_stream - VirtIO PCM stream. * @substreams: VirtIO substreams belonging to the stream. * @nsubstreams: Number of substreams. + * @chmaps: Kernel channel maps belonging to the stream. + * @nchmaps: Number of channel maps. */ struct virtio_pcm_stream { struct virtio_pcm_substream **substreams; u32 nsubstreams; + struct snd_pcm_chmap_elem *chmaps; + u32 nchmaps; }; /** -- cgit v1.2.3-58-ga151 From 575483e90a3292c2afceb7161732046e411d6fdd Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:09 +0100 Subject: ALSA: virtio: introduce device suspend/resume support All running PCM substreams are stopped on device suspend and restarted on device resume. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-10-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/virtio_card.c | 56 +++++++++++++++++++++++++++++++++++++++++++ sound/virtio/virtio_pcm.h | 3 +++ sound/virtio/virtio_pcm_ops.c | 33 +++++++++++++++++++------ 3 files changed, 85 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 1c03fcc41c3b..ae9128063917 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -362,6 +362,58 @@ static void virtsnd_remove(struct virtio_device *vdev) kfree(snd->event_msgs); } +#ifdef CONFIG_PM_SLEEP +/** + * virtsnd_freeze() - Suspend device. + * @vdev: VirtIO parent device. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_freeze(struct virtio_device *vdev) +{ + struct virtio_snd *snd = vdev->priv; + unsigned int i; + + virtsnd_disable_event_vq(snd); + virtsnd_ctl_msg_cancel_all(snd); + + vdev->config->del_vqs(vdev); + vdev->config->reset(vdev); + + for (i = 0; i < snd->nsubstreams; ++i) + cancel_work_sync(&snd->substreams[i].elapsed_period); + + kfree(snd->event_msgs); + snd->event_msgs = NULL; + + return 0; +} + +/** + * virtsnd_restore() - Resume device. + * @vdev: VirtIO parent device. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_restore(struct virtio_device *vdev) +{ + struct virtio_snd *snd = vdev->priv; + int rc; + + rc = virtsnd_find_vqs(snd); + if (rc) + return rc; + + virtio_device_ready(vdev); + + virtsnd_enable_event_vq(snd); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + static const struct virtio_device_id id_table[] = { { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID }, { 0 }, @@ -374,6 +426,10 @@ static struct virtio_driver virtsnd_driver = { .validate = virtsnd_validate, .probe = virtsnd_probe, .remove = virtsnd_remove, +#ifdef CONFIG_PM_SLEEP + .freeze = virtsnd_freeze, + .restore = virtsnd_restore, +#endif }; static int __init init(void) diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index 1353fdc9bd69..062eb8e8f2cf 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -31,6 +31,8 @@ struct virtio_pcm_msg; * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun). * @stopped: True if the substream is stopped and must be released on the device * side. + * @suspended: True if the substream is suspended and must be reconfigured on + * the device side at resume. * @msgs: Allocated I/O messages. * @nmsgs: Number of allocated I/O messages. * @msg_last_enqueued: Index of the last I/O message added to the virtqueue. @@ -52,6 +54,7 @@ struct virtio_pcm_substream { bool xfer_enabled; bool xfer_xrun; bool stopped; + bool suspended; struct virtio_pcm_msg **msgs; unsigned int nmsgs; int msg_last_enqueued; diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c index 0682a2df6c8c..f8bfb87624be 100644 --- a/sound/virtio/virtio_pcm_ops.c +++ b/sound/virtio/virtio_pcm_ops.c @@ -115,6 +115,7 @@ static int virtsnd_pcm_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_PERIODS); vss->stopped = !!virtsnd_pcm_msg_pending_num(vss); + vss->suspended = false; /* * If the substream has already been used, then the I/O queue may be in @@ -272,16 +273,31 @@ static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream) struct virtio_device *vdev = vss->snd->vdev; struct virtio_snd_msg *msg; - if (virtsnd_pcm_msg_pending_num(vss)) { - dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", - vss->sid); - return -EBADFD; + if (!vss->suspended) { + if (virtsnd_pcm_msg_pending_num(vss)) { + dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", + vss->sid); + return -EBADFD; + } + + vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + vss->hw_ptr = 0; + vss->msg_last_enqueued = -1; + } else { + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + unsigned int period_bytes = snd_pcm_lib_period_bytes(substream); + int rc; + + rc = virtsnd_pcm_dev_set_params(vss, buffer_bytes, period_bytes, + runtime->channels, + runtime->format, runtime->rate); + if (rc) + return rc; } - vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream); - vss->hw_ptr = 0; vss->xfer_xrun = false; - vss->msg_last_enqueued = -1; + vss->suspended = false; vss->msg_count = 0; msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE, @@ -336,6 +352,9 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command) } return virtsnd_ctl_msg_send_sync(snd, msg); + case SNDRV_PCM_TRIGGER_SUSPEND: + vss->suspended = true; + fallthrough; case SNDRV_PCM_TRIGGER_STOP: vss->stopped = true; fallthrough; -- cgit v1.2.3-58-ga151 From b95a913cb368edcb606d844a6dc6240093d87020 Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Sat, 6 Mar 2021 11:19:31 +0000 Subject: ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18 In preparation to support Cirrus Logic CS8409 HDA bridge on new Dell platforms it is nessasary to increase AUTO_CFG_MAX_INS and AUTO_CFG_NUM_INPUTS values. Currently AUTO_CFG_MAX_INS is limited to 8, but Cirrus Logic HDA bridge CS8409 has 18 input pins, 16 ASP receivers and 2 DMIC inputs. We have to increase this value to 18, so generic code can handle this correctly. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210306111934.4832-2-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.h | 2 +- sound/pci/hda/hda_local.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index a22ca0e17a08..df63d66af1ab 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -27,7 +27,7 @@ enum { }; #define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS -#define AUTO_CFG_MAX_INS 8 +#define AUTO_CFG_MAX_INS 18 struct auto_pin_cfg_item { hda_nid_t pin; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5beb8aa44ecd..317245a5585d 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -180,7 +180,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); /* * input MUX helper */ -#define HDA_MAX_NUM_INPUTS 16 +#define HDA_MAX_NUM_INPUTS 36 struct hda_input_mux_item { char label[32]; unsigned int index; -- cgit v1.2.3-58-ga151 From 6cc7e93f46a5ce9f65ad3c6c6f645f1d831a8fa4 Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Sat, 6 Mar 2021 11:19:32 +0000 Subject: ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec. Dell's laptops Inspiron 3500, Inspiron 3501, Inspiron 3505 are using Cirrus Logic CS8409 HDA bridge with CS42L42 companion codec. The CS8409 is a multichannel HD audio routing controller. CS8409 includes support for four channels of digital microphone data and two bidirectional ASPs for up to 32 channels of TDM data or 4 channels of I2S data. The CS8409 is intended to be used with a remote companion codec that implements high performance analog functions in close physical proximity to the end-equipment audio port or speaker driver. The CS42L42 is a low-power audio codec with integrated MIPI SoundWire interface or I2C/I2S/TDM interfaces designed for portable applications. It provides a high-dynamic range, stereo DAC for audio playback and a mono high-dynamic-range ADC for audio capture CS42L42 is connected to CS8409 HDA bridge via I2C and I2S. CS8409 CS42L42 ------- -------- ASP1.A TX --> ASP_SDIN ASP1.A RX <-- ASP_SDOUT GPIO5 --> RST# GPIO4 <-- INT# GPIO3 <-- WAKE# GPIO7 <-> I2C SDA GPIO6 --> I2C CLK Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3505 This patch will register CS8409 with sound card and create input/output paths and two input devices, initialise CS42L42 companion codec and configure it for ASP TX/RX TDM mode, 24bit, 48kHz. cat /proc/asound/pcm 00-00: CS8409 Analog : CS8409 Analog : playback 1 : capture 1 00-03: HDMI 0 : HDMI 0 : playback 1 dmesg snd_hda_codec_cirrus hdaudioC0D0: autoconfig for CS8409: line_outs=1 (0x2c/0x0/0x0/0x0/0x0) type:speaker snd_hda_codec_cirrus hdaudioC0D0: speaker_outs=0 (0x0/0x0/0x0/0x0/0x0) snd_hda_codec_cirrus hdaudioC0D0: hp_outs=1 (0x24/0x0/0x0/0x0/0x0) snd_hda_codec_cirrus hdaudioC0D0: mono: mono_out=0x0 snd_hda_codec_cirrus hdaudioC0D0: inputs: snd_hda_codec_cirrus hdaudioC0D0: Internal Mic=0x44 snd_hda_codec_cirrus hdaudioC0D0: Mic=0x34 input: HDA Intel PCH Headphone as /devices/pci0000:00/0000:00:1f.3/sound/card0/input8 input: HDA Intel PCH Headset Mic as /devices/pci0000:00/0000:00:1f.3/sound/card0/input9 Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210306111934.4832-3-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 576 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 576 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index f46204ab0b90..d664eed5c3cf 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "hda_local.h" @@ -1219,6 +1220,580 @@ static int patch_cs4213(struct hda_codec *codec) return err; } +/* Cirrus Logic CS8409 HDA bridge with + * companion codec CS42L42 + */ +#define CS8409_VENDOR_NID 0x47 + +#define CS8409_CS42L42_HP_PIN_NID 0x24 +#define CS8409_CS42L42_SPK_PIN_NID 0x2c +#define CS8409_CS42L42_AMIC_PIN_NID 0x34 +#define CS8409_CS42L42_DMIC_PIN_NID 0x44 + +#define GPIO3_INT (1 << 3) +#define GPIO4_INT (1 << 4) +#define GPIO5_INT (1 << 5) + +#define CS42L42_I2C_ADDR (0x48 << 1) + +#define CIR_I2C_ADDR 0x0059 +#define CIR_I2C_DATA 0x005A +#define CIR_I2C_CTRL 0x005B +#define CIR_I2C_STATUS 0x005C +#define CIR_I2C_QWRITE 0x005D +#define CIR_I2C_QREAD 0x005E + +struct cs8409_i2c_param { + unsigned int addr; + unsigned int reg; +}; + +struct cs8409_cir_param { + unsigned int nid; + unsigned int cir; + unsigned int coeff; +}; + +enum { + CS8409_BULLSEYE, + CS8409_WARLOCK, + CS8409_CYBORG, + CS8409_VERBS, +}; + +/* Dell Inspiron models with cs8409/cs42l42 */ +static const struct hda_model_fixup cs8409_models[] = { + { .id = CS8409_BULLSEYE, .name = "bullseye" }, + { .id = CS8409_WARLOCK, .name = "warlock" }, + { .id = CS8409_CYBORG, .name = "cyborg" }, + {} +}; + +/* Dell Inspiron platforms + * with cs8409 bridge and cs42l42 codec + */ +static const struct snd_pci_quirk cs8409_fixup_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG), + {} /* terminator */ +}; + +static const struct hda_verb cs8409_cs42l42_init_verbs[] = { + { 0x01, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 }, /* WAKE from GPIO 3,4 */ + { 0x47, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing */ + { 0x47, AC_VERB_SET_COEF_INDEX, 0x0002 }, /* Configure GPIO 6,7 */ + { 0x47, AC_VERB_SET_PROC_COEF, 0x0080 }, /* I2C mode */ + { 0x47, AC_VERB_SET_COEF_INDEX, 0x005b }, /* Set I2C bus speed */ + { 0x47, AC_VERB_SET_PROC_COEF, 0x0200 }, /* 100kHz I2C_STO = 2 */ + {} /* terminator */ +}; + +static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = { + { 0x24, 0x042120f0 }, /* ASP-1-TX */ + { 0x34, 0x04a12050 }, /* ASP-1-RX */ + { 0x2c, 0x901000f0 }, /* ASP-2-TX */ + { 0x44, 0x90a00090 }, /* DMIC-1 */ + {} /* terminator */ +}; + +static const struct hda_verb cs8409_cs42l42_add_verbs[] = { + { 0x24, 0x71c, 0xF0 }, /* Widget node ASP-1-TX */ + { 0x24, 0x71d, 0x20 }, + { 0x24, 0x71e, 0x21 }, + { 0x24, 0x71f, 0x04 }, + { 0x34, 0x71c, 0x50 }, /* Widget node ASP-1-RX0 */ + { 0x34, 0x71d, 0x20 }, + { 0x34, 0x71e, 0xa1 }, + { 0x34, 0x71f, 0x04 }, + { 0x2C, 0x71c, 0xF0 }, /* Widget node ASP-2-TX */ + { 0x2C, 0x71d, 0x00 }, + { 0x2C, 0x71e, 0x10 }, + { 0x2C, 0x71f, 0x90 }, + { 0x44, 0x71c, 0x90 }, /* Widget node DMIC-1 */ + { 0x44, 0x71d, 0x00 }, + { 0x44, 0x71e, 0xA0 }, + { 0x44, 0x71f, 0x90 }, + {} /* terminator */ +}; + +static const struct hda_fixup cs8409_fixups[] = { + [CS8409_BULLSEYE] = { + .type = HDA_FIXUP_PINS, + .v.pins = cs8409_cs42l42_pincfgs, + .chained = true, + .chain_id = CS8409_VERBS, + }, + [CS8409_WARLOCK] = { + .type = HDA_FIXUP_PINS, + .v.pins = cs8409_cs42l42_pincfgs, + .chained = true, + .chain_id = CS8409_VERBS, + }, + [CS8409_CYBORG] = { + .type = HDA_FIXUP_PINS, + .v.pins = cs8409_cs42l42_pincfgs, + .chained = true, + .chain_id = CS8409_VERBS, + }, + [CS8409_VERBS] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = cs8409_cs42l42_add_verbs, + }, +}; + +/* Vendor specific HW configuration for CS42L42 */ +static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = { + { 0x1010, 0xB0 }, + { 0x1D01, 0x00 }, + { 0x1D02, 0x06 }, + { 0x1D03, 0x00 }, + { 0x1107, 0x01 }, + { 0x1009, 0x02 }, + { 0x1007, 0x03 }, + { 0x1201, 0x00 }, + { 0x1208, 0x13 }, + { 0x1205, 0xFF }, + { 0x1206, 0x00 }, + { 0x1207, 0x20 }, + { 0x1202, 0x0D }, + { 0x2A02, 0x02 }, + { 0x2A03, 0x00 }, + { 0x2A04, 0x00 }, + { 0x2A05, 0x02 }, + { 0x2A06, 0x00 }, + { 0x2A07, 0x20 }, + { 0x2A08, 0x02 }, + { 0x2A09, 0x00 }, + { 0x2A0A, 0x80 }, + { 0x2A0B, 0x02 }, + { 0x2A0C, 0x00 }, + { 0x2A0D, 0xA0 }, + { 0x2A01, 0x0C }, + { 0x2902, 0x01 }, + { 0x2903, 0x02 }, + { 0x2904, 0x00 }, + { 0x2905, 0x00 }, + { 0x2901, 0x01 }, + { 0x1101, 0x0A }, + { 0x1102, 0x84 }, + { 0x2301, 0x00 }, + { 0x2303, 0x00 }, + { 0x2302, 0x3f }, + { 0x2001, 0x03 }, + { 0x1B75, 0xB6 }, + { 0x1B73, 0xC2 }, + { 0x1129, 0x01 }, + { 0x1121, 0xF3 }, + { 0x1103, 0x20 }, + { 0x1105, 0x00 }, + { 0x1112, 0xC0 }, + { 0x1113, 0x80 }, + { 0x1C03, 0xC0 }, + { 0x1105, 0x00 }, + { 0x1112, 0xC0 }, + {} /* Terminator */ +}; + +/* Vendor specific hw configuration for CS8409 */ +static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = { + { 0x47, 0x00, 0xb008 }, /* +PLL1/2_EN, +I2C_EN */ + { 0x47, 0x01, 0x0002 }, /* ASP1/2_EN=0, ASP1_STP=1 */ + { 0x47, 0x02, 0x0a80 }, /* ASP1/2_BUS_IDLE=10, +GPIO_I2C */ + { 0x47, 0x19, 0x0800 }, /* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */ + { 0x47, 0x1a, 0x0820 }, /* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */ + { 0x47, 0x29, 0x0800 }, /* ASP2.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */ + { 0x47, 0x2a, 0x2800 }, /* ASP2.A: TX.RAP=1, TX.RSZ=24 bits, TX.RCS=0 */ + { 0x47, 0x39, 0x0800 }, /* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */ + { 0x47, 0x3a, 0x0800 }, /* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */ + { 0x47, 0x03, 0x8000 }, /* ASP1: LCHI = 00h */ + { 0x47, 0x04, 0x28ff }, /* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */ + { 0x47, 0x05, 0x0062 }, /* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */ + { 0x47, 0x06, 0x801f }, /* ASP2: LCHI=1Fh */ + { 0x47, 0x07, 0x283f }, /* ASP2: MC/SC_SRCSEL=PLL1, LCPR=3Fh */ + { 0x47, 0x08, 0x805c }, /* ASP2: 5050=1, MCEN=0, FSD=010, SCPOL_IN/OUT=1, SCDIV=1:16 */ + { 0x47, 0x09, 0x0023 }, /* DMIC1_MO=10b, DMIC1/2_SR=1 */ + { 0x47, 0x0a, 0x0000 }, /* ASP1/2_BEEP=0 */ + { 0x47, 0x01, 0x0062 }, /* ASP1/2_EN=1, ASP1_STP=1 */ + { 0x47, 0x00, 0x9008 }, /* -PLL2_EN */ + { 0x47, 0x68, 0x0000 }, /* TX2.A: pre-scale att.=0 dB */ + { 0x47, 0x82, 0xfc03 }, /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=1 */ + { 0x47, 0xc0, 0x9999 }, /* test mode on */ + { 0x47, 0xc5, 0x0000 }, /* GPIO hysteresis = 30 us */ + { 0x47, 0xc0, 0x0000 }, /* test mode off */ + {} /* Terminator */ +}; + +/* Enable I2C clocks */ +static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int flag) +{ + unsigned int retval = 0; + unsigned int newval = 0; + + retval = cs_vendor_coef_get(codec, 0x0); + newval = (flag) ? (retval | 0x8) : (retval & 0xfffffff7); + cs_vendor_coef_set(codec, 0x0, newval); +} + +/* Wait I2C transaction */ +static int cs8409_i2c_wait_complete(struct hda_codec *codec) +{ + int repeat = 5; + unsigned int retval = 0; + + do { + retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS); + if ((retval & 0x18) != 0x18) { + usleep_range(2000, 4000); + --repeat; + } else + break; + + } while (repeat); + + return repeat > 0 ? 0 : -1; +} + +/* CS8409 slave i2cRead */ +static unsigned int cs8409_i2c_read(struct hda_codec *codec, + unsigned int i2c_address, + unsigned int i2c_reg, + unsigned int paged) +{ + unsigned int i2c_reg_data; + unsigned int retval = 0; + + cs8409_enable_i2c_clock(codec, 1); + cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address); + + if (paged) { + cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8); + if (cs8409_i2c_wait_complete(codec) == -1) { + codec_err(codec, + "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", + __func__, i2c_address, i2c_reg, retval); + } + } + + i2c_reg_data = (i2c_reg << 8) & 0x0ffff; + cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data); + if (cs8409_i2c_wait_complete(codec) == -1) { + codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", + __func__, i2c_address, i2c_reg, retval); + } + + /* Register in bits 15-8 and the data in 7-0 */ + retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD); + retval &= 0x0ff; + + cs8409_enable_i2c_clock(codec, 0); + + return retval; +} + +/* CS8409 slave i2cWrite */ +static unsigned int cs8409_i2c_write(struct hda_codec *codec, + unsigned int i2c_address, unsigned int i2c_reg, + unsigned int i2c_data, + unsigned int paged) +{ + unsigned int retval = 0; + unsigned int i2c_reg_data = 0; + + cs8409_enable_i2c_clock(codec, 1); + cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address); + + if (paged) { + cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8); + if (cs8409_i2c_wait_complete(codec) == -1) { + codec_err(codec, + "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", + __func__, i2c_address, i2c_reg, retval); + } + } + + i2c_reg_data = ((i2c_reg << 8) & 0x0ff00) | (i2c_data & 0x0ff); + cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg_data); + + if (cs8409_i2c_wait_complete(codec) == -1) { + codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", + __func__, i2c_address, i2c_reg, retval); + } + + cs8409_enable_i2c_clock(codec, 0); + + return retval; +} + +/* Assert/release RTS# line to CS42L42 */ +static void cs8409_cs42l42_reset(struct hda_codec *codec) +{ + /* Assert RTS# line */ + snd_hda_codec_write(codec, + codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0); + /* wait ~10ms */ + usleep_range(10000, 15000); + /* Release RTS# line */ + snd_hda_codec_write(codec, + codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, GPIO5_INT); + /* wait ~10ms */ + usleep_range(10000, 15000); + + /* Clear interrupts status */ + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1); + +} + +static void cs8409_cs42l42_reg_setup(struct hda_codec *codec) +{ + const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq; + + for (; seq->addr; seq++) + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1); + +} + +static int cs8409_cs42l42_build_controls(struct hda_codec *codec) +{ + int err; + + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); + + return 0; +} + +#ifdef CONFIG_PM +/* Manage PDREF, when transition to D3hot */ +static int cs8409_suspend(struct hda_codec *codec) +{ + /* Assert CS42L42 RTS# line */ + snd_hda_codec_write(codec, + codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0); + snd_hda_shutup_pins(codec); + return 0; +} +#endif + +/* Vendor specific HW configuration + * PLL, ASP, I2C, SPI, GPIOs, DMIC etc... + */ +static int cs8409_cs42l42_hw_init(struct hda_codec *codec) +{ + const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg; + struct cs_spec *spec = codec->spec; + + if (spec->gpio_mask) { + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, + spec->gpio_mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, + spec->gpio_dir); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_data); + } + + for (; seq->nid; seq++) + cs_vendor_coef_set(codec, seq->cir, seq->coeff); + + /* Reset CS42L42 */ + cs8409_cs42l42_reset(codec); + + /* Initialise CS42L42 companion codec */ + cs8409_cs42l42_reg_setup(codec); + + if (codec->fixup_id == CS8409_WARLOCK || + codec->fixup_id == CS8409_CYBORG) { + /* FULL_SCALE_VOL = 0 for Warlock / Cyborg */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1); + /* DMIC1_MO=00b, DMIC1/2_SR=1 */ + cs_vendor_coef_set(codec, 0x09, 0x0003); + } + + return 1; +} + +static int cs8409_cs42l42_init(struct hda_codec *codec) +{ + int ret = 0; + + ret = snd_hda_gen_init(codec); + + if (!ret) { + /* On Dell platforms with suspend D3 mode support we + * have to re-initialise cs8409 bridge and companion + * cs42l42 codec + */ + snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); + snd_hda_sequence_write(codec, cs8409_cs42l42_add_verbs); + + cs8409_cs42l42_hw_init(codec); + + } + + return ret; +} + +static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { + .build_controls = cs8409_cs42l42_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = cs8409_cs42l42_init, + .free = cs_free, + .unsol_event = snd_hda_jack_unsol_event, +#ifdef CONFIG_PM + .suspend = cs8409_suspend, +#endif +}; + +static int cs8409_cs42l42_fixup(struct hda_codec *codec) +{ + int err = 0; + struct cs_spec *spec = codec->spec; + unsigned int pincap = 0; + + /* Basic initial sequence for specific hw configuration */ + snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); + + /* CS8409 is simple HDA bridge and intended to be used with a remote + * companion codec. Most of input/output PIN(s) have only basic + * capabilities. NID(s) 0x24 and 0x34 have only OUTC and INC + * capabilities and no presence detect capable (PDC) and call to + * snd_hda_gen_build_controls() will mark them as non detectable + * phantom jacks. However, in this configuration companion codec + * CS42L42 is connected to these pins and it has jack detect + * capabilities. We have to override pin capabilities, + * otherwise they will not be created as input devices. + */ + _snd_hdac_read_parm(&codec->core, + CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, &pincap); + + snd_hdac_override_parm(&codec->core, + CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, + (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + + _snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, + AC_PAR_PIN_CAP, &pincap); + + snd_hdac_override_parm(&codec->core, + CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP, + (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + + snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID, + (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); + + snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID, + (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, 0, 0); + if (err < 0) + return err; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + return err; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return err; +} + +static int patch_cs8409(struct hda_codec *codec) +{ + struct cs_spec *spec; + int err = -EINVAL; + + spec = cs_alloc_spec(codec, CS8409_VENDOR_NID); + if (!spec) + return -ENOMEM; + + snd_hda_pick_fixup(codec, + cs8409_models, cs8409_fixup_tbl, cs8409_fixups); + + codec_dbg(codec, "Picked ID=%d, VID=%08x, DEV=%08x\n", + codec->fixup_id, + codec->bus->pci->subsystem_vendor, + codec->bus->pci->subsystem_device); + + switch (codec->fixup_id) { + /* Dell platforms with CS42L42 companion codec */ + case CS8409_BULLSEYE: + case CS8409_WARLOCK: + case CS8409_CYBORG: + + snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs); + + codec->patch_ops = cs8409_cs42l42_patch_ops; + + spec->gen.suppress_auto_mute = 1; + spec->gen.no_primary_hp = 1; + /* GPIO 5 out, 3,4 in */ + spec->gpio_dir = GPIO5_INT; + spec->gpio_data = 0; + spec->gpio_mask = 0x03f; + + err = cs8409_cs42l42_fixup(codec); + + if (err > 0) + err = cs8409_cs42l42_hw_init(codec); + break; + + default: + codec_err(codec, "VID=%08x, DEV=%08x not supported\n", + codec->bus->pci->subsystem_vendor, + codec->bus->pci->subsystem_device); + break; + } + if (err < 0) + cs_free(codec); + else + snd_hda_codec_set_name(codec, "CS8409/CS42L42"); + + return err; +} /* * patch entries @@ -1229,6 +1804,7 @@ static const struct hda_device_id snd_hda_id_cirrus[] = { HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208), HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210), HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213), + HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus); -- cgit v1.2.3-58-ga151 From b73df04187ebb52edf3f7e502bb245c5ccab2763 Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Sat, 6 Mar 2021 11:19:33 +0000 Subject: ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec. In the case of CS8409 we do not have unsol events from NID's 0x24 and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will generate interrupt via gpio 4 to notify jack events. We have to overwrite standard snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers and then notify status via generic snd_hda_jack_unsol_event() call. Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3505. Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210306111934.4832-4-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 309 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 307 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d664eed5c3cf..1d2f6a1224e6 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,15 @@ struct cs_spec { /* for MBP SPDIF control */ int (*spdif_sw_put)(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); + + unsigned int cs42l42_hp_jack_in:1; + unsigned int cs42l42_mic_jack_in:1; + + struct mutex cs8409_i2c_mux; + + /* verb exec op override */ + int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, + unsigned int flags, unsigned int *res); }; /* available models with CS420x */ @@ -1229,6 +1239,13 @@ static int patch_cs4213(struct hda_codec *codec) #define CS8409_CS42L42_SPK_PIN_NID 0x2c #define CS8409_CS42L42_AMIC_PIN_NID 0x34 #define CS8409_CS42L42_DMIC_PIN_NID 0x44 +#define CS8409_CS42L42_DMIC_ADC_PIN_NID 0x22 + +#define CS42L42_HSDET_AUTO_DONE 0x02 +#define CS42L42_HSTYPE_MASK 0x03 + +#define CS42L42_JACK_INSERTED 0x0C +#define CS42L42_JACK_REMOVED 0x00 #define GPIO3_INT (1 << 3) #define GPIO4_INT (1 << 4) @@ -1429,6 +1446,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = { { 0x1C03, 0xC0 }, { 0x1105, 0x00 }, { 0x1112, 0xC0 }, + { 0x1101, 0x02 }, {} /* Terminator */ }; @@ -1565,6 +1583,8 @@ static unsigned int cs8409_i2c_write(struct hda_codec *codec, /* Assert/release RTS# line to CS42L42 */ static void cs8409_cs42l42_reset(struct hda_codec *codec) { + struct cs_spec *spec = codec->spec; + /* Assert RTS# line */ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0); @@ -1576,21 +1596,190 @@ static void cs8409_cs42l42_reset(struct hda_codec *codec) /* wait ~10ms */ usleep_range(10000, 15000); - /* Clear interrupts status */ + mutex_lock(&spec->cs8409_i2c_mux); + + /* Clear interrupts, by reading interrupt status registers */ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1); cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1); cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1); + mutex_unlock(&spec->cs8409_i2c_mux); + +} + +/* Configure CS42L42 slave codec for jack autodetect */ +static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); + + /* Set TIP_SENSE_EN for analog front-end of tip sense. */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x0020, 1); + /* Clear WAKE# */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0001, 1); + /* Wait ~2.5ms */ + usleep_range(2500, 3000); + /* Set mode WAKE# output follows the combination logic directly */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0020, 1); + /* Clear interrupts status */ + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1); + /* Enable interrupt */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0x03, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b79, 0x00, 1); + + mutex_unlock(&spec->cs8409_i2c_mux); + + return 0; +} + +/* Enable and run CS42L42 slave codec jack auto detect */ +static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); + + /* Clear interrupts */ + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77, 1); + + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1102, 0x87, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1f06, 0x86, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b74, 0x07, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0x01, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80, 1); + /* Wait ~110ms*/ + usleep_range(110000, 200000); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1); + /* Wait ~10ms */ + usleep_range(10000, 25000); + + mutex_unlock(&spec->cs8409_i2c_mux); + } static void cs8409_cs42l42_reg_setup(struct hda_codec *codec) { const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq; + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); for (; seq->addr; seq++) cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1); + mutex_unlock(&spec->cs8409_i2c_mux); + +} + +/* + * In the case of CS8409 we do not have unsolicited events from NID's 0x24 + * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will + * generate interrupt via gpio 4 to notify jack events. We have to overwrite + * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers + * and then notify status via generic snd_hda_jack_unsol_event() call. + */ +static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct cs_spec *spec = codec->spec; + int status_changed = 0; + unsigned int reg_cdc_status = 0; + unsigned int reg_hs_status = 0; + unsigned int reg_ts_status = 0; + int type = 0; + struct hda_jack_tbl *jk; + + /* jack_unsol_event() will be called every time gpio line changing state. + * In this case gpio4 line goes up as a result of reading interrupt status + * registers in previous cs8409_jack_unsol_event() call. + * We don't need to handle this event, ignoring... + */ + if ((res & (1 << 4))) + return; + + mutex_lock(&spec->cs8409_i2c_mux); + + /* Read jack detect status registers */ + reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); + reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1); + reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); + + /* Clear interrupts */ + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); + + mutex_unlock(&spec->cs8409_i2c_mux); + + /* HSDET_AUTO_DONE */ + if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) { + + type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1); + /* CS42L42 reports optical jack as type 4 + * We don't handle optical jack + */ + if (type != 4) { + if (!spec->cs42l42_hp_jack_in) { + status_changed = 1; + spec->cs42l42_hp_jack_in = 1; + } + /* type = 3 has no mic */ + if ((!spec->cs42l42_mic_jack_in) && (type != 3)) { + status_changed = 1; + spec->cs42l42_mic_jack_in = 1; + } + } else { + if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) { + status_changed = 1; + spec->cs42l42_hp_jack_in = 0; + spec->cs42l42_mic_jack_in = 0; + } + } + + } else { + /* TIP_SENSE INSERT/REMOVE */ + switch (reg_ts_status) { + case CS42L42_JACK_INSERTED: + cs8409_cs42l42_run_jack_detect(codec); + break; + + case CS42L42_JACK_REMOVED: + if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) { + status_changed = 1; + spec->cs42l42_hp_jack_in = 0; + spec->cs42l42_mic_jack_in = 0; + } + break; + + default: + /* jack in transition */ + status_changed = 0; + break; + } + } + + if (status_changed) { + + snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID, + (spec->cs42l42_hp_jack_in)?0 : PIN_OUT); + + /* Report jack*/ + jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0); + if (jk) { + snd_hda_jack_unsol_event(codec, + (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG); + } + /* Report jack*/ + jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0); + if (jk) { + snd_hda_jack_unsol_event(codec, + (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG); + } + } } static int cs8409_cs42l42_build_controls(struct hda_codec *codec) @@ -1603,6 +1792,13 @@ static int cs8409_cs42l42_build_controls(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); + /* Run jack auto detect first time on boot + * after controls have been added, to check if jack has + * been already plugged in + */ + cs8409_cs42l42_run_jack_detect(codec); + usleep_range(100000, 150000); + return 0; } @@ -1610,14 +1806,61 @@ static int cs8409_cs42l42_build_controls(struct hda_codec *codec) /* Manage PDREF, when transition to D3hot */ static int cs8409_suspend(struct hda_codec *codec) { + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); + /* Power down CS42L42 ASP/EQ/MIX/HP */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1101, 0xfe, 1); + mutex_unlock(&spec->cs8409_i2c_mux); /* Assert CS42L42 RTS# line */ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0); + snd_hda_shutup_pins(codec); + return 0; } #endif +static void cs8409_cs42l42_cap_sync_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs_spec *spec = codec->spec; + unsigned int curval, expval; + /* CS8409 DMIC Pin only allows the setting of the Stream Parameters in + * Power State D0. When a headset is unplugged, and the path is switched to + * the DMIC, the Stream is restarted with the new ADC, but this is done in + * Power State D3. Restart the Stream now DMIC is in D0. + */ + if (spec->gen.cur_adc == CS8409_CS42L42_DMIC_ADC_PIN_NID) { + curval = snd_hda_codec_read(codec, spec->gen.cur_adc, + 0, AC_VERB_GET_CONV, 0); + expval = (spec->gen.cur_adc_stream_tag << 4) | 0; + if (curval != expval) { + codec_dbg(codec, "%s Restarting Stream after DMIC switch\n", __func__); + __snd_hda_codec_cleanup_stream(codec, spec->gen.cur_adc, 1); + snd_hda_codec_setup_stream(codec, spec->gen.cur_adc, + spec->gen.cur_adc_stream_tag, 0, + spec->gen.cur_adc_format); + } + } +} + +/* Enable/Disable Unsolicited Response for gpio(s) 3,4 */ +static void cs8409_enable_ur(struct hda_codec *codec, int flag) +{ + /* GPIO4 INT# and GPIO3 WAKE# */ + snd_hda_codec_write(codec, codec->core.afg, + 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, + flag?(GPIO3_INT | GPIO4_INT) : 0); + + snd_hda_codec_write(codec, codec->core.afg, + 0, AC_VERB_SET_UNSOLICITED_ENABLE, + flag?AC_UNSOL_ENABLED : 0); + +} + /* Vendor specific HW configuration * PLL, ASP, I2C, SPI, GPIOs, DMIC etc... */ @@ -1638,6 +1881,9 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) for (; seq->nid; seq++) cs_vendor_coef_set(codec, seq->cir, seq->coeff); + /* Disable Unsolicited Response during boot */ + cs8409_enable_ur(codec, 0); + /* Reset CS42L42 */ cs8409_cs42l42_reset(codec); @@ -1647,11 +1893,18 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) if (codec->fixup_id == CS8409_WARLOCK || codec->fixup_id == CS8409_CYBORG) { /* FULL_SCALE_VOL = 0 for Warlock / Cyborg */ + mutex_lock(&spec->cs8409_i2c_mux); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1); + mutex_unlock(&spec->cs8409_i2c_mux); /* DMIC1_MO=00b, DMIC1/2_SR=1 */ cs_vendor_coef_set(codec, 0x09, 0x0003); } + cs8409_cs42l42_enable_jack_detect(codec); + + /* Enable Unsolicited Response */ + cs8409_enable_ur(codec, 1); + return 1; } @@ -1671,6 +1924,8 @@ static int cs8409_cs42l42_init(struct hda_codec *codec) cs8409_cs42l42_hw_init(codec); + cs8409_cs42l42_run_jack_detect(codec); + usleep_range(100000, 150000); } return ret; @@ -1681,7 +1936,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { .build_pcms = snd_hda_gen_build_pcms, .init = cs8409_cs42l42_init, .free = cs_free, - .unsol_event = snd_hda_jack_unsol_event, + .unsol_event = cs8409_jack_unsol_event, #ifdef CONFIG_PM .suspend = cs8409_suspend, #endif @@ -1741,6 +1996,45 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec) return err; } +static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, + unsigned int cmd, unsigned int flags, unsigned int *res) +{ + struct hda_codec *codec = container_of(dev, struct hda_codec, core); + struct cs_spec *spec = codec->spec; + + unsigned int nid = 0; + unsigned int verb = 0; + + nid = ((cmd >> 20) & 0x07f); + verb = ((cmd >> 8) & 0x0fff); + + /* CS8409 pins have no AC_PINSENSE_PRESENCE + * capabilities. We have to intercept 2 calls for pins 0x24 and 0x34 + * and return correct pin sense values for read_pin_sense() call from + * hda_jack based on CS42L42 jack detect status. + */ + switch (nid) { + case CS8409_CS42L42_HP_PIN_NID: + if (verb == AC_VERB_GET_PIN_SENSE) { + *res = (spec->cs42l42_hp_jack_in) ? AC_PINSENSE_PRESENCE : 0; + return 0; + } + break; + + case CS8409_CS42L42_AMIC_PIN_NID: + if (verb == AC_VERB_GET_PIN_SENSE) { + *res = (spec->cs42l42_mic_jack_in) ? AC_PINSENSE_PRESENCE : 0; + return 0; + } + break; + + default: + break; + } + + return spec->exec_verb(dev, cmd, flags, res); +} + static int patch_cs8409(struct hda_codec *codec) { struct cs_spec *spec; @@ -1766,8 +2060,16 @@ static int patch_cs8409(struct hda_codec *codec) snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs); + /* verb exec op override */ + spec->exec_verb = codec->core.exec_verb; + codec->core.exec_verb = cs8409_cs42l42_exec_verb; + + mutex_init(&spec->cs8409_i2c_mux); + codec->patch_ops = cs8409_cs42l42_patch_ops; + spec->gen.cap_sync_hook = cs8409_cs42l42_cap_sync_hook; + spec->gen.suppress_auto_mute = 1; spec->gen.no_primary_hp = 1; /* GPIO 5 out, 3,4 in */ @@ -1775,6 +2077,9 @@ static int patch_cs8409(struct hda_codec *codec) spec->gpio_data = 0; spec->gpio_mask = 0x03f; + spec->cs42l42_hp_jack_in = 0; + spec->cs42l42_mic_jack_in = 0; + err = cs8409_cs42l42_fixup(codec); if (err > 0) -- cgit v1.2.3-58-ga151 From b9dd23bb03fe241ccb774c59b05d5cbac07895dc Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Sat, 6 Mar 2021 11:19:34 +0000 Subject: ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control CS8409 does not support Volume Control for NIDs 0x24 (the Headphones), or 0x34 (The Headset Mic). However, CS42L42 codec does support gain control for both. We can add support for Volume Controls, by writing the the CS42L42 regmap via i2c commands, using custom info, get and put volume functions, saved in the control. Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210306111934.4832-5-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 200 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 1d2f6a1224e6..6a9e5c803977 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -21,6 +21,9 @@ /* */ +#define CS42L42_HP_CH (2U) +#define CS42L42_HS_MIC_CH (1U) + struct cs_spec { struct hda_gen_spec gen; @@ -42,6 +45,9 @@ struct cs_spec { unsigned int cs42l42_hp_jack_in:1; unsigned int cs42l42_mic_jack_in:1; + unsigned int cs42l42_volume_init:1; + char cs42l42_hp_volume[CS42L42_HP_CH]; + char cs42l42_hs_mic_volume[CS42L42_HS_MIC_CH]; struct mutex cs8409_i2c_mux; @@ -1260,6 +1266,14 @@ static int patch_cs4213(struct hda_codec *codec) #define CIR_I2C_QWRITE 0x005D #define CIR_I2C_QREAD 0x005E +#define CS8409_CS42L42_HP_VOL_REAL_MIN (-63) +#define CS8409_CS42L42_HP_VOL_REAL_MAX (0) +#define CS8409_CS42L42_AMIC_VOL_REAL_MIN (-97) +#define CS8409_CS42L42_AMIC_VOL_REAL_MAX (12) +#define CS8409_CS42L42_REG_HS_VOLUME_CHA (0x2301) +#define CS8409_CS42L42_REG_HS_VOLUME_CHB (0x2303) +#define CS8409_CS42L42_REG_AMIC_VOLUME (0x1D03) + struct cs8409_i2c_param { unsigned int addr; unsigned int reg; @@ -1580,6 +1594,165 @@ static unsigned int cs8409_i2c_write(struct hda_codec *codec, return retval; } +static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + u16 nid = get_amp_nid(kcontrol); + u8 chs = get_amp_channels(kcontrol); + + codec_dbg(codec, "%s() nid: %d\n", __func__, nid); + switch (nid) { + case CS8409_CS42L42_HP_PIN_NID: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = CS8409_CS42L42_HP_VOL_REAL_MIN; + uinfo->value.integer.max = CS8409_CS42L42_HP_VOL_REAL_MAX; + break; + case CS8409_CS42L42_AMIC_PIN_NID: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = CS8409_CS42L42_AMIC_VOL_REAL_MIN; + uinfo->value.integer.max = CS8409_CS42L42_AMIC_VOL_REAL_MAX; + break; + default: + break; + } + return 0; +} + +static void cs8409_cs42l42_update_volume(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); + spec->cs42l42_hp_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHA, 1)); + spec->cs42l42_hp_volume[1] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHB, 1)); + spec->cs42l42_hs_mic_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, 1)); + mutex_unlock(&spec->cs8409_i2c_mux); + spec->cs42l42_volume_init = 1; +} + +static int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int chs = get_amp_channels(kcontrol); + long *valp = ucontrol->value.integer.value; + + if (!spec->cs42l42_volume_init) { + snd_hda_power_up(codec); + cs8409_cs42l42_update_volume(codec); + snd_hda_power_down(codec); + } + switch (nid) { + case CS8409_CS42L42_HP_PIN_NID: + if (chs & 1) + *valp++ = spec->cs42l42_hp_volume[0]; + if (chs & 2) + *valp++ = spec->cs42l42_hp_volume[1]; + break; + case CS8409_CS42L42_AMIC_PIN_NID: + if (chs & 1) + *valp++ = spec->cs42l42_hs_mic_volume[0]; + break; + default: + break; + } + return 0; +} + +static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int chs = get_amp_channels(kcontrol); + long *valp = ucontrol->value.integer.value; + int change = 0; + char vol = 0; + + snd_hda_power_up(codec); + switch (nid) { + case CS8409_CS42L42_HP_PIN_NID: + mutex_lock(&spec->cs8409_i2c_mux); + if (chs & 1) { + vol = -(*valp); + change = cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHA, vol, 1); + valp++; + } + if (chs & 2) { + vol = -(*valp); + change |= cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHB, vol, 1); + } + mutex_unlock(&spec->cs8409_i2c_mux); + break; + case CS8409_CS42L42_AMIC_PIN_NID: + mutex_lock(&spec->cs8409_i2c_mux); + if (chs & 1) { + change = cs8409_i2c_write( + codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, (char)*valp, 1); + valp++; + } + mutex_unlock(&spec->cs8409_i2c_mux); + break; + default: + break; + } + cs8409_cs42l42_update_volume(codec); + snd_hda_power_down(codec); + return change; +} + +static const DECLARE_TLV_DB_SCALE( + cs8409_cs42l42_hp_db_scale, + CS8409_CS42L42_HP_VOL_REAL_MIN * 100, 100, 1); + +static const DECLARE_TLV_DB_SCALE( + cs8409_cs42l42_amic_db_scale, + CS8409_CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1); + +static const struct snd_kcontrol_new cs8409_cs42l42_hp_volume_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .name = "Headphone Playback Volume", + .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG), + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE + | SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .info = cs8409_cs42l42_volume_info, + .get = cs8409_cs42l42_volume_get, + .put = cs8409_cs42l42_volume_put, + .tlv = { .p = cs8409_cs42l42_hp_db_scale }, + .private_value = HDA_COMPOSE_AMP_VAL( + CS8409_CS42L42_HP_PIN_NID, 3, 0, HDA_OUTPUT) + | HDA_AMP_VAL_MIN_MUTE +}; + +static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .name = "Headset Mic Capture Volume", + .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG), + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE + | SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .info = cs8409_cs42l42_volume_info, + .get = cs8409_cs42l42_volume_get, + .put = cs8409_cs42l42_volume_put, + .tlv = { .p = cs8409_cs42l42_amic_db_scale }, + .private_value = HDA_COMPOSE_AMP_VAL( + CS8409_CS42L42_AMIC_PIN_NID, 1, 0, HDA_INPUT) + | HDA_AMP_VAL_MIN_MUTE +}; + /* Assert/release RTS# line to CS42L42 */ static void cs8409_cs42l42_reset(struct hda_codec *codec) { @@ -1900,6 +2073,24 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) cs_vendor_coef_set(codec, 0x09, 0x0003); } + /* Restore Volumes after Resume */ + if (spec->cs42l42_volume_init) { + mutex_lock(&spec->cs8409_i2c_mux); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHA, -spec->cs42l42_hp_volume[0], + 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHB, -spec->cs42l42_hp_volume[1], + 1); + cs8409_i2c_write( + codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, spec->cs42l42_hs_mic_volume[0], + 1); + mutex_unlock(&spec->cs8409_i2c_mux); + } + + cs8409_cs42l42_update_volume(codec); + cs8409_cs42l42_enable_jack_detect(codec); /* Enable Unsolicited Response */ @@ -1991,6 +2182,14 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec) if (err < 0) return err; + if (!snd_hda_gen_add_kctl( + &spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer)) + return -1; + + if (!snd_hda_gen_add_kctl( + &spec->gen, NULL, &cs8409_cs42l42_amic_volume_mixer)) + return -1; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return err; @@ -2072,6 +2271,7 @@ static int patch_cs8409(struct hda_codec *codec) spec->gen.suppress_auto_mute = 1; spec->gen.no_primary_hp = 1; + spec->gen.suppress_vmaster = 1; /* GPIO 5 out, 3,4 in */ spec->gpio_dir = GPIO5_INT; spec->gpio_data = 0; -- cgit v1.2.3-58-ga151 From 981b22b8777df7de070be1803f6d7ed4f634a43c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:38 +0100 Subject: tty: remove TTY_LDISC_MAGIC First, it is never checked. Second, use of it as a debugging aid is at least questionable. With the current tools, I don't think anyone used this kind of thing for debugging purposes for years. On the top of that, e.g. serdev does not set this field of tty_ldisc_ops at all. So get rid of this legacy. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/process/magic-number.rst | 1 - Documentation/translations/it_IT/process/magic-number.rst | 1 - Documentation/translations/zh_CN/process/magic-number.rst | 1 - drivers/accessibility/speakup/spk_ttyio.c | 1 - drivers/bluetooth/hci_ldisc.c | 1 - drivers/misc/ti-st/st_core.c | 1 - drivers/net/caif/caif_serial.c | 1 - drivers/net/can/slcan.c | 1 - drivers/net/hamradio/6pack.c | 1 - drivers/net/hamradio/mkiss.c | 1 - drivers/net/ppp/ppp_async.c | 1 - drivers/net/ppp/ppp_synctty.c | 1 - drivers/net/slip/slip.c | 1 - drivers/pps/clients/pps-ldisc.c | 3 --- drivers/tty/n_gsm.c | 1 - drivers/tty/n_hdlc.c | 1 - drivers/tty/n_null.c | 1 - drivers/tty/n_r3964.c | 1 - drivers/tty/n_tty.c | 1 - include/linux/tty_ldisc.h | 3 --- net/nfc/nci/uart.c | 1 - sound/soc/codecs/cx20442.c | 1 - sound/soc/ti/ams-delta.c | 1 - 23 files changed, 27 deletions(-) (limited to 'sound') diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst index 89992fe4863f..f5ba36e96461 100644 --- a/Documentation/process/magic-number.rst +++ b/Documentation/process/magic-number.rst @@ -88,7 +88,6 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst index 9be170ec0d02..e8c782d155a3 100644 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ b/Documentation/translations/it_IT/process/magic-number.rst @@ -94,7 +94,6 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 191d705349ef..42f0635ca70a 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -77,7 +77,6 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c index 9af1d4c124d3..2e39fcf492d8 100644 --- a/drivers/accessibility/speakup/spk_ttyio.c +++ b/drivers/accessibility/speakup/spk_ttyio.c @@ -104,7 +104,6 @@ static int spk_ttyio_receive_buf2(struct tty_struct *tty, static struct tty_ldisc_ops spk_ttyio_ldisc_ops = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "speakup_ldisc", .open = spk_ttyio_ldisc_open, .close = spk_ttyio_ldisc_close, diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 637c5b8c2aa1..71a4ca505e09 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -821,7 +821,6 @@ static __poll_t hci_uart_tty_poll(struct tty_struct *tty, static struct tty_ldisc_ops hci_uart_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_hci", .open = hci_uart_tty_open, .close = hci_uart_tty_close, diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 5a0a5fc3d3ab..071844b58073 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -845,7 +845,6 @@ static void st_tty_flush_buffer(struct tty_struct *tty) } static struct tty_ldisc_ops st_ldisc_ops = { - .magic = TTY_LDISC_MAGIC, .name = "n_st", .open = st_tty_open, .close = st_tty_close, diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 8215cd77301f..675c374b32ee 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -382,7 +382,6 @@ static void ldisc_close(struct tty_struct *tty) /* The line discipline structure. */ static struct tty_ldisc_ops caif_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_caif", .open = ldisc_open, .close = ldisc_close, diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 30c8d53c9745..31ba6664503d 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -697,7 +697,6 @@ static int slcan_ioctl(struct tty_struct *tty, struct file *file, static struct tty_ldisc_ops slc_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "slcan", .open = slcan_open, .close = slcan_close, diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 71d6629e65c9..6f71eff9c52e 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -749,7 +749,6 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, static struct tty_ldisc_ops sp_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "6pack", .open = sixpack_open, .close = sixpack_close, diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 17be2bb2985c..65154224d5b8 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -933,7 +933,6 @@ out: static struct tty_ldisc_ops ax_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "mkiss", .open = mkiss_open, .close = mkiss_close, diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 2a91caa4f37b..8b41aa3fb64e 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -372,7 +372,6 @@ ppp_asynctty_wakeup(struct tty_struct *tty) static struct tty_ldisc_ops ppp_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "ppp", .open = ppp_asynctty_open, .close = ppp_asynctty_close, diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index d8890923a9e3..576b6a93bf23 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -365,7 +365,6 @@ ppp_sync_wakeup(struct tty_struct *tty) static struct tty_ldisc_ops ppp_sync_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "pppsync", .open = ppp_sync_open, .close = ppp_sync_close, diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index f81fb0b13a94..1ab124eba8eb 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -1263,7 +1263,6 @@ static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static struct tty_ldisc_ops sl_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "slip", .open = slip_open, .close = slip_close, diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c index 4fd0cbf7f931..bf26cc56b863 100644 --- a/drivers/pps/clients/pps-ldisc.c +++ b/drivers/pps/clients/pps-ldisc.c @@ -13,8 +13,6 @@ #include #include -#define PPS_TTY_MAGIC 0x0001 - static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status) { struct pps_device *pps; @@ -114,7 +112,6 @@ static int __init pps_tty_init(void) /* Init PPS_TTY data */ pps_ldisc_ops.owner = THIS_MODULE; - pps_ldisc_ops.magic = PPS_TTY_MAGIC; pps_ldisc_ops.name = "pps_tty"; pps_ldisc_ops.dcd_change = pps_tty_dcd_change; pps_ldisc_ops.open = pps_tty_open; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 51dafc06f541..b063bc608a8c 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2849,7 +2849,6 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) /* Line discipline for real tty */ static struct tty_ldisc_ops tty_ldisc_packet = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_gsm", .open = gsmld_open, .close = gsmld_close, diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 1363e659dc1d..290c757db1b9 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -787,7 +787,6 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list) static struct tty_ldisc_ops n_hdlc_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "hdlc", .open = n_hdlc_tty_open, .close = n_hdlc_tty_close, diff --git a/drivers/tty/n_null.c b/drivers/tty/n_null.c index ce03ae78f5c6..b8f67b5f1ef8 100644 --- a/drivers/tty/n_null.c +++ b/drivers/tty/n_null.c @@ -40,7 +40,6 @@ static void n_null_receivebuf(struct tty_struct *tty, static struct tty_ldisc_ops null_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_null", .open = n_null_open, .close = n_null_close, diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 3161f0a535e3..2eb76ea1d88d 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -146,7 +146,6 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, static struct tty_ldisc_ops tty_ldisc_N_R3964 = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "R3964", .open = r3964_open, .close = r3964_close, diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 87ec15dbe10d..7c53185bce57 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2488,7 +2488,6 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, } static struct tty_ldisc_ops n_tty_ops = { - .magic = TTY_LDISC_MAGIC, .name = "n_tty", .open = n_tty_open, .close = n_tty_close, diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 572a07976116..31284b55bd4f 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -173,7 +173,6 @@ extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, struct tty_ldisc_ops { - int magic; char *name; int num; int flags; @@ -218,8 +217,6 @@ struct tty_ldisc { struct tty_struct *tty; }; -#define TTY_LDISC_MAGIC 0x5403 - #define LDISC_FLAG_DEFINED 0x00000001 #define MODULE_ALIAS_LDISC(ldisc) \ diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 1204c438e87d..16d009c9b6a0 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -453,7 +453,6 @@ void nci_uart_set_config(struct nci_uart *nu, int baudrate, int flow_ctrl) EXPORT_SYMBOL_GPL(nci_uart_set_config); static struct tty_ldisc_ops nci_uart_ldisc = { - .magic = TTY_LDISC_MAGIC, .owner = THIS_MODULE, .name = "n_nci", .open = nci_uart_tty_open, diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 161be8b7d131..61dfa86d444d 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -285,7 +285,6 @@ static void v253_wakeup(struct tty_struct *tty) } struct tty_ldisc_ops v253_ops = { - .magic = TTY_LDISC_MAGIC, .name = "cx20442", .owner = THIS_MODULE, .open = v253_open, diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 57feb473a579..98198c7cc872 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -395,7 +395,6 @@ static void cx81801_wakeup(struct tty_struct *tty) } static struct tty_ldisc_ops cx81801_ops = { - .magic = TTY_LDISC_MAGIC, .name = "cx81801", .owner = THIS_MODULE, .open = cx81801_open, -- cgit v1.2.3-58-ga151 From 9c896eeca4578507faa067d62daa2d66b1541bc8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Mar 2021 20:32:27 +0100 Subject: ALSA: ppc: keywest: remove outdated comment The I2C attach_adapter callback is gone. Remove this reference. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20210310193227.333140-1-wsa@kernel.org Signed-off-by: Takashi Iwai --- sound/ppc/keywest.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index a6c1905039de..a8915100d6bb 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -13,12 +13,7 @@ #include #include "pmac.h" -/* - * we have to keep a static variable here since i2c attach_adapter - * callback cannot pass a private data. - */ static struct pmac_keywest *keywest_ctx; - static bool keywest_probed; static int keywest_probe(struct i2c_client *client, -- cgit v1.2.3-58-ga151 From fb3447d5842b71ec960da1b8a3ca5ee5f46a5327 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 15 Mar 2021 19:07:13 +0000 Subject: ALSA: hda/cirrus: Add error handling into CS8409 I2C functions Also removing 2 redundant cs8409_i2c_read() calls, as we already did read them in a code above. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210315190716.47686-2-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 136 +++++++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 6a9e5c803977..d95478ea2fb2 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1493,22 +1493,34 @@ static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = { {} /* Terminator */ }; -/* Enable I2C clocks */ -static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int flag) +/** + * cs8409_enable_i2c_clock - Enable I2C clocks + * @codec: the codec instance + * @enable: Enable or disable I2C clocks + * + * Enable or Disable I2C clocks. + */ +static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int enable) { unsigned int retval = 0; unsigned int newval = 0; retval = cs_vendor_coef_get(codec, 0x0); - newval = (flag) ? (retval | 0x8) : (retval & 0xfffffff7); + newval = (enable) ? (retval | 0x8) : (retval & 0xfffffff7); cs_vendor_coef_set(codec, 0x0, newval); } -/* Wait I2C transaction */ +/** + * cs8409_i2c_wait_complete - Wait for I2C transaction + * @codec: the codec instance + * + * Wait for I2C transaction to complete. + * Return -1 if transaction wait times out. + */ static int cs8409_i2c_wait_complete(struct hda_codec *codec) { int repeat = 5; - unsigned int retval = 0; + unsigned int retval; do { retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS); @@ -1516,82 +1528,103 @@ static int cs8409_i2c_wait_complete(struct hda_codec *codec) usleep_range(2000, 4000); --repeat; } else - break; + return 0; } while (repeat); - return repeat > 0 ? 0 : -1; + return -1; } -/* CS8409 slave i2cRead */ -static unsigned int cs8409_i2c_read(struct hda_codec *codec, +/** + * cs8409_i2c_read - CS8409 I2C Read. + * @codec: the codec instance + * @i2c_address: I2C Address + * @i2c_reg: Register to read + * @paged: Is a paged transaction + * + * CS8409 I2C Read. + * Returns negative on error, otherwise returns read value in bits 0-7. + */ +static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, unsigned int i2c_reg, unsigned int paged) { unsigned int i2c_reg_data; - unsigned int retval = 0; + unsigned int read_data; cs8409_enable_i2c_clock(codec, 1); cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address); if (paged) { cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8); - if (cs8409_i2c_wait_complete(codec) == -1) { + if (cs8409_i2c_wait_complete(codec) < 0) { codec_err(codec, - "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", - __func__, i2c_address, i2c_reg, retval); + "%s() Paged Transaction Failed 0x%02x : 0x%04x\n", + __func__, i2c_address, i2c_reg); + return -EIO; } } i2c_reg_data = (i2c_reg << 8) & 0x0ffff; cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data); - if (cs8409_i2c_wait_complete(codec) == -1) { - codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", - __func__, i2c_address, i2c_reg, retval); + if (cs8409_i2c_wait_complete(codec) < 0) { + codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n", + __func__, i2c_address, i2c_reg); + return -EIO; } /* Register in bits 15-8 and the data in 7-0 */ - retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD); - retval &= 0x0ff; + read_data = cs_vendor_coef_get(codec, CIR_I2C_QREAD); cs8409_enable_i2c_clock(codec, 0); - return retval; + return read_data & 0x0ff; } -/* CS8409 slave i2cWrite */ -static unsigned int cs8409_i2c_write(struct hda_codec *codec, +/** + * cs8409_i2c_write - CS8409 I2C Write. + * @codec: the codec instance + * @i2c_address: I2C Address + * @i2c_reg: Register to write to + * @i2c_data: Data to write + * @paged: Is a paged transaction + * + * CS8409 I2C Write. + * Returns negative on error, otherwise returns 0. + */ +static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, unsigned int i2c_reg, unsigned int i2c_data, unsigned int paged) { - unsigned int retval = 0; - unsigned int i2c_reg_data = 0; + unsigned int i2c_reg_data; cs8409_enable_i2c_clock(codec, 1); cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address); if (paged) { cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8); - if (cs8409_i2c_wait_complete(codec) == -1) { + if (cs8409_i2c_wait_complete(codec) < 0) { codec_err(codec, - "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", - __func__, i2c_address, i2c_reg, retval); + "%s() Paged Transaction Failed 0x%02x : 0x%04x\n", + __func__, i2c_address, i2c_reg); + return -EIO; } } i2c_reg_data = ((i2c_reg << 8) & 0x0ff00) | (i2c_data & 0x0ff); cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg_data); - if (cs8409_i2c_wait_complete(codec) == -1) { - codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", - __func__, i2c_address, i2c_reg, retval); + if (cs8409_i2c_wait_complete(codec) < 0) { + codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n", + __func__, i2c_address, i2c_reg); + return -EIO; } cs8409_enable_i2c_clock(codec, 0); - return retval; + return 0; } static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kcontrol, @@ -1624,14 +1657,27 @@ static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kcontrol, static void cs8409_cs42l42_update_volume(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; + int data; mutex_lock(&spec->cs8409_i2c_mux); - spec->cs42l42_hp_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_HS_VOLUME_CHA, 1)); - spec->cs42l42_hp_volume[1] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_HS_VOLUME_CHB, 1)); - spec->cs42l42_hs_mic_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_AMIC_VOLUME, 1)); + data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHA, 1); + if (data >= 0) + spec->cs42l42_hp_volume[0] = -data; + else + spec->cs42l42_hp_volume[0] = CS8409_CS42L42_HP_VOL_REAL_MIN; + data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHB, 1); + if (data >= 0) + spec->cs42l42_hp_volume[1] = -data; + else + spec->cs42l42_hp_volume[1] = CS8409_CS42L42_HP_VOL_REAL_MIN; + data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, 1); + if (data >= 0) + spec->cs42l42_hs_mic_volume[0] = -data; + else + spec->cs42l42_hs_mic_volume[0] = CS8409_CS42L42_AMIC_VOL_REAL_MIN; mutex_unlock(&spec->cs8409_i2c_mux); spec->cs42l42_volume_init = 1; } @@ -1782,7 +1828,7 @@ static void cs8409_cs42l42_reset(struct hda_codec *codec) } /* Configure CS42L42 slave codec for jack autodetect */ -static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec) +static void cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -1804,8 +1850,6 @@ static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec) cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b79, 0x00, 1); mutex_unlock(&spec->cs8409_i2c_mux); - - return 0; } /* Enable and run CS42L42 slave codec jack auto detect */ @@ -1860,9 +1904,9 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) { struct cs_spec *spec = codec->spec; int status_changed = 0; - unsigned int reg_cdc_status = 0; - unsigned int reg_hs_status = 0; - unsigned int reg_ts_status = 0; + int reg_cdc_status; + int reg_hs_status; + int reg_ts_status; int type = 0; struct hda_jack_tbl *jk; @@ -1881,13 +1925,15 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1); reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); - /* Clear interrupts */ + /* Clear interrupts, by reading interrupt status registers */ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1); - cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); - cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); mutex_unlock(&spec->cs8409_i2c_mux); + /* If status values are < 0, read error has occurred. */ + if (reg_cdc_status < 0 || reg_hs_status < 0 || reg_ts_status < 0) + return; + /* HSDET_AUTO_DONE */ if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) { -- cgit v1.2.3-58-ga151 From 61a9aba19f4482984dc7ec5c04c54bf51166cff2 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 15 Mar 2021 19:07:14 +0000 Subject: ALSA: hda/cirrus: Cleanup patch_cirrus.c code. Minor changes, clean up code, remove unnecessary initialization of variables, reduced number of warnings from ./scripts/checkpatch.pl from 19 to 0 Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210315190716.47686-3-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 147 +++++++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 75 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d95478ea2fb2..275bba02cc05 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -127,7 +127,7 @@ enum { * 1 DAC => HP(sense) / Speakers, * 1 ADC <= LineIn(sense) / MicIn / DMicIn, * 1 SPDIF OUT => SPDIF Trasmitter(sense) -*/ + */ #define CS4210_DAC_NID 0x02 #define CS4210_ADC_NID 0x03 #define CS4210_VENDOR_NID 0x0B @@ -146,6 +146,7 @@ enum { static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) { struct cs_spec *spec = codec->spec; + snd_hda_codec_write(codec, spec->vendor_nid, 0, AC_VERB_SET_COEF_INDEX, idx); return snd_hda_codec_read(codec, spec->vendor_nid, 0, @@ -156,6 +157,7 @@ static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, unsigned int coef) { struct cs_spec *spec = codec->spec; + snd_hda_codec_write(codec, spec->vendor_nid, 0, AC_VERB_SET_COEF_INDEX, idx); snd_hda_codec_write(codec, spec->vendor_nid, 0, @@ -192,6 +194,7 @@ static void cs_automute(struct hda_codec *codec) static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid) { unsigned int val; + val = snd_hda_codec_get_pincfg(codec, nid); return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); } @@ -210,7 +213,7 @@ static void init_input_coef(struct hda_codec *codec) coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off * No effect if SPDIF_OUT2 is * selected in IDX_SPDIF_CTL. - */ + */ cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef); } @@ -284,13 +287,6 @@ static const struct hda_verb cs_errata_init_verbs[] = { {0x11, AC_VERB_SET_COEF_INDEX, 0x0001}, {0x11, AC_VERB_SET_PROC_COEF, 0x0008}, {0x11, AC_VERB_SET_PROC_STATE, 0x00}, - -#if 0 /* Don't to set to D3 as we are in power-up sequence */ - {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */ - {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */ - /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */ -#endif - {} /* terminator */ }; @@ -378,8 +374,10 @@ static int cs_parse_auto_config(struct hda_codec *codec) /* keep the ADCs powered up when it's dynamically switchable */ if (spec->gen.dyn_adc_switch) { unsigned int done = 0; + for (i = 0; i < spec->gen.input_mux.num_items; i++) { int idx = spec->gen.dyn_adc_idx[i]; + if (done & (1 << idx)) continue; snd_hda_gen_fix_pin_power(codec, @@ -513,6 +511,7 @@ static void cs420x_fixup_gpio_13(struct hda_codec *codec, { if (action == HDA_FIXUP_ACT_PRE_PROBE) { struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */ spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ spec->gpio_mask = spec->gpio_dir = @@ -525,6 +524,7 @@ static void cs420x_fixup_gpio_23(struct hda_codec *codec, { if (action == HDA_FIXUP_ACT_PRE_PROBE) { struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */ spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ spec->gpio_mask = spec->gpio_dir = @@ -669,6 +669,7 @@ static void cs4208_fixup_gpio0(struct hda_codec *codec, { if (action == HDA_FIXUP_ACT_PRE_PROBE) { struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 0; spec->gpio_eapd_speaker = 1; spec->gpio_mask = spec->gpio_dir = @@ -823,7 +824,7 @@ static int patch_cs4208(struct hda_codec *codec) * 1 DAC => HP(sense) / Speakers, * 1 ADC <= LineIn(sense) / MicIn / DMicIn, * 1 SPDIF OUT => SPDIF Trasmitter(sense) -*/ + */ /* CS4210 board names */ static const struct hda_model_fixup cs421x_models[] = { @@ -866,6 +867,7 @@ static void cs421x_fixup_sense_b(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct cs_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) spec->sense_b = 1; } @@ -891,9 +893,9 @@ static const struct hda_verb cs421x_coef_init_verbs[] = { {0x0B, AC_VERB_SET_PROC_STATE, 1}, {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG}, /* - Disable Coefficient Index Auto-Increment(DAI)=1, - PDREF=0 - */ + * Disable Coefficient Index Auto-Increment(DAI)=1, + * PDREF=0 + */ {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 }, {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG}, @@ -980,12 +982,12 @@ static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, coef &= ~0x0003; coef |= (vol & 0x0003); - if (original_coef == coef) - return 0; - else { + if (original_coef != coef) { cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef); return 1; } + + return 0; } static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = { @@ -1024,8 +1026,8 @@ static void cs4210_pinmux_init(struct hda_codec *codec) is_active_pin(codec, CS421X_DMIC_PIN_NID)) { /* - GPIO or SENSE_B forced - disconnect the DMIC pin. - */ + * GPIO or SENSE_B forced - disconnect the DMIC pin. + */ def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID); def_conf &= ~AC_DEFCFG_PORT_CONN; def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT); @@ -1064,6 +1066,7 @@ static void parse_cs421x_digital(struct hda_codec *codec) for (i = 0; i < cfg->dig_outs; i++) { hda_nid_t nid = cfg->dig_out_pins[i]; + if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { spec->spdif_detect = 1; snd_hda_jack_detect_enable_callback(codec, nid, @@ -1142,9 +1145,9 @@ static int cs421x_parse_auto_config(struct hda_codec *codec) #ifdef CONFIG_PM /* - Manage PDREF, when transitioning to D3hot - (DAC,ADC) -> D3, PDREF=1, AFG->D3 -*/ + * Manage PDREF, when transitioning to D3hot + * (DAC,ADC) -> D3, PDREF=1, AFG->D3 + */ static int cs421x_suspend(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -1195,10 +1198,10 @@ static int patch_cs4210(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* - Update the GPIO/DMIC/SENSE_B pinmux before the configuration - is auto-parsed. If GPIO or SENSE_B is forced, DMIC input - is disabled. - */ + * Update the GPIO/DMIC/SENSE_B pinmux before the configuration + * is auto-parsed. If GPIO or SENSE_B is forced, DMIC input + * is disabled. + */ cs4210_pinmux_init(codec); err = cs421x_parse_auto_config(codec); @@ -1502,8 +1505,8 @@ static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = { */ static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int enable) { - unsigned int retval = 0; - unsigned int newval = 0; + unsigned int retval; + unsigned int newval; retval = cs_vendor_coef_get(codec, 0x0); newval = (enable) ? (retval | 0x8) : (retval & 0xfffffff7); @@ -1698,13 +1701,13 @@ static int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol, } switch (nid) { case CS8409_CS42L42_HP_PIN_NID: - if (chs & 1) + if (chs & BIT(0)) *valp++ = spec->cs42l42_hp_volume[0]; - if (chs & 2) + if (chs & BIT(1)) *valp++ = spec->cs42l42_hp_volume[1]; break; case CS8409_CS42L42_AMIC_PIN_NID: - if (chs & 1) + if (chs & BIT(0)) *valp++ = spec->cs42l42_hs_mic_volume[0]; break; default: @@ -1722,19 +1725,19 @@ static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kcontrol, int chs = get_amp_channels(kcontrol); long *valp = ucontrol->value.integer.value; int change = 0; - char vol = 0; + char vol; snd_hda_power_up(codec); switch (nid) { case CS8409_CS42L42_HP_PIN_NID: mutex_lock(&spec->cs8409_i2c_mux); - if (chs & 1) { + if (chs & BIT(0)) { vol = -(*valp); change = cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOLUME_CHA, vol, 1); valp++; } - if (chs & 2) { + if (chs & BIT(1)) { vol = -(*valp); change |= cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOLUME_CHB, vol, 1); @@ -1743,7 +1746,7 @@ static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kcontrol, break; case CS8409_CS42L42_AMIC_PIN_NID: mutex_lock(&spec->cs8409_i2c_mux); - if (chs & 1) { + if (chs & BIT(0)) { change = cs8409_i2c_write( codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_AMIC_VOLUME, (char)*valp, 1); @@ -1907,7 +1910,7 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) int reg_cdc_status; int reg_hs_status; int reg_ts_status; - int type = 0; + int type; struct hda_jack_tbl *jk; /* jack_unsol_event() will be called every time gpio line changing state. @@ -1984,7 +1987,7 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) if (status_changed) { snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID, - (spec->cs42l42_hp_jack_in)?0 : PIN_OUT); + spec->cs42l42_hp_jack_in ? 0 : PIN_OUT); /* Report jack*/ jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0); @@ -2072,18 +2075,18 @@ static void cs8409_enable_ur(struct hda_codec *codec, int flag) /* GPIO4 INT# and GPIO3 WAKE# */ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, - flag?(GPIO3_INT | GPIO4_INT) : 0); + flag ? (GPIO3_INT | GPIO4_INT) : 0); snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - flag?AC_UNSOL_ENABLED : 0); + flag ? AC_UNSOL_ENABLED : 0); } /* Vendor specific HW configuration * PLL, ASP, I2C, SPI, GPIOs, DMIC etc... */ -static int cs8409_cs42l42_hw_init(struct hda_codec *codec) +static void cs8409_cs42l42_hw_init(struct hda_codec *codec) { const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg; struct cs_spec *spec = codec->spec; @@ -2123,14 +2126,16 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) if (spec->cs42l42_volume_init) { mutex_lock(&spec->cs8409_i2c_mux); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_HS_VOLUME_CHA, -spec->cs42l42_hp_volume[0], + CS8409_CS42L42_REG_HS_VOLUME_CHA, + -spec->cs42l42_hp_volume[0], 1); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_HS_VOLUME_CHB, -spec->cs42l42_hp_volume[1], + CS8409_CS42L42_REG_HS_VOLUME_CHB, + -spec->cs42l42_hp_volume[1], 1); - cs8409_i2c_write( - codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_AMIC_VOLUME, spec->cs42l42_hs_mic_volume[0], + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, + spec->cs42l42_hs_mic_volume[0], 1); mutex_unlock(&spec->cs8409_i2c_mux); } @@ -2141,15 +2146,11 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) /* Enable Unsolicited Response */ cs8409_enable_ur(codec, 1); - - return 1; } static int cs8409_cs42l42_init(struct hda_codec *codec) { - int ret = 0; - - ret = snd_hda_gen_init(codec); + int ret = snd_hda_gen_init(codec); if (!ret) { /* On Dell platforms with suspend D3 mode support we @@ -2181,9 +2182,9 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { static int cs8409_cs42l42_fixup(struct hda_codec *codec) { - int err = 0; + int err; struct cs_spec *spec = codec->spec; - unsigned int pincap = 0; + int caps; /* Basic initial sequence for specific hw configuration */ snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); @@ -2198,25 +2199,25 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec) * capabilities. We have to override pin capabilities, * otherwise they will not be created as input devices. */ - _snd_hdac_read_parm(&codec->core, - CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, &pincap); - - snd_hdac_override_parm(&codec->core, + caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_HP_PIN_NID, + AC_PAR_PIN_CAP); + if (caps >= 0) + snd_hdac_override_parm(&codec->core, CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, - (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); - _snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, - AC_PAR_PIN_CAP, &pincap); - - snd_hdac_override_parm(&codec->core, + caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, + AC_PAR_PIN_CAP); + if (caps >= 0) + snd_hdac_override_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP, - (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID, - (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); + (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID, - (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); + (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -2238,7 +2239,7 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - return err; + return 0; } static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, @@ -2247,11 +2248,8 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, struct hda_codec *codec = container_of(dev, struct hda_codec, core); struct cs_spec *spec = codec->spec; - unsigned int nid = 0; - unsigned int verb = 0; - - nid = ((cmd >> 20) & 0x07f); - verb = ((cmd >> 8) & 0x0fff); + unsigned int nid = ((cmd >> 20) & 0x07f); + unsigned int verb = ((cmd >> 8) & 0x0fff); /* CS8409 pins have no AC_PINSENSE_PRESENCE * capabilities. We have to intercept 2 calls for pins 0x24 and 0x34 @@ -2327,9 +2325,6 @@ static int patch_cs8409(struct hda_codec *codec) spec->cs42l42_mic_jack_in = 0; err = cs8409_cs42l42_fixup(codec); - - if (err > 0) - err = cs8409_cs42l42_hw_init(codec); break; default: @@ -2338,10 +2333,12 @@ static int patch_cs8409(struct hda_codec *codec) codec->bus->pci->subsystem_device); break; } - if (err < 0) - cs_free(codec); - else + + if (!err) { + cs8409_cs42l42_hw_init(codec); snd_hda_codec_set_name(codec, "CS8409/CS42L42"); + } else + cs_free(codec); return err; } -- cgit v1.2.3-58-ga151 From 9f8de3b7d789693008b65a4849bc444e81fcfe5a Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 15 Mar 2021 19:07:15 +0000 Subject: ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name Existing name "Headset Mic Volume Control" causes multiple Microphone entries to appear in UI. Using name "Mic Volume Control" ensures only a single Microphone entry exists when the Headset is connected. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov BugLink: https://bugs.launchpad.net/bugs/1918378 Reported-and-tested-by: You-Sheng Yang Link: https://lore.kernel.org/r/20210315190716.47686-4-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 275bba02cc05..c99ec5e485af 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1789,7 +1789,7 @@ static const struct snd_kcontrol_new cs8409_cs42l42_hp_volume_mixer = { static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .index = 0, - .name = "Headset Mic Capture Volume", + .name = "Mic Capture Volume", .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG), .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), -- cgit v1.2.3-58-ga151 From 7a114444af813ee35dbe0ef6d26ffb56b309549b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 15 Mar 2021 19:07:16 +0000 Subject: ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups. CS8409/CS42L42 Driver currently does most of the platform specific setup inside the main body of the code, however, this setup can be moved into fixup functions, to make the driver more generic. Making the driver more generic, allows the driver to use the cs_parse_auto_config function in the patch function. This function forces all of the ADCs to be permanently powered, which means the cap_sync_hook function is no longer needed to restart the stream, when the jack has been ejected. Since the codec is re-initialized on every init/resume, there is no need to add specific verbs to be run on init, and instead these can be combined with the initialization verbs, which are run on init. In addition, the extra fixup verbs are no longer required, since this is taken care of elsewhere. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 [ Use fallthrough macro instead of comment -- tiwai ] Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210315190716.47686-5-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 280 +++++++++++++++---------------------------- 1 file changed, 98 insertions(+), 182 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index c99ec5e485af..5d57096b3a95 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1292,9 +1292,14 @@ enum { CS8409_BULLSEYE, CS8409_WARLOCK, CS8409_CYBORG, - CS8409_VERBS, + CS8409_FIXUPS, }; +static void cs8409_cs42l42_fixups(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, + unsigned int cmd, unsigned int flags, unsigned int *res); + /* Dell Inspiron models with cs8409/cs42l42 */ static const struct hda_model_fixup cs8409_models[] = { { .id = CS8409_BULLSEYE, .name = "bullseye" }, @@ -1368,48 +1373,28 @@ static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = { {} /* terminator */ }; -static const struct hda_verb cs8409_cs42l42_add_verbs[] = { - { 0x24, 0x71c, 0xF0 }, /* Widget node ASP-1-TX */ - { 0x24, 0x71d, 0x20 }, - { 0x24, 0x71e, 0x21 }, - { 0x24, 0x71f, 0x04 }, - { 0x34, 0x71c, 0x50 }, /* Widget node ASP-1-RX0 */ - { 0x34, 0x71d, 0x20 }, - { 0x34, 0x71e, 0xa1 }, - { 0x34, 0x71f, 0x04 }, - { 0x2C, 0x71c, 0xF0 }, /* Widget node ASP-2-TX */ - { 0x2C, 0x71d, 0x00 }, - { 0x2C, 0x71e, 0x10 }, - { 0x2C, 0x71f, 0x90 }, - { 0x44, 0x71c, 0x90 }, /* Widget node DMIC-1 */ - { 0x44, 0x71d, 0x00 }, - { 0x44, 0x71e, 0xA0 }, - { 0x44, 0x71f, 0x90 }, - {} /* terminator */ -}; - static const struct hda_fixup cs8409_fixups[] = { [CS8409_BULLSEYE] = { .type = HDA_FIXUP_PINS, .v.pins = cs8409_cs42l42_pincfgs, .chained = true, - .chain_id = CS8409_VERBS, + .chain_id = CS8409_FIXUPS, }, [CS8409_WARLOCK] = { .type = HDA_FIXUP_PINS, .v.pins = cs8409_cs42l42_pincfgs, .chained = true, - .chain_id = CS8409_VERBS, + .chain_id = CS8409_FIXUPS, }, [CS8409_CYBORG] = { .type = HDA_FIXUP_PINS, .v.pins = cs8409_cs42l42_pincfgs, .chained = true, - .chain_id = CS8409_VERBS, + .chain_id = CS8409_FIXUPS, }, - [CS8409_VERBS] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = cs8409_cs42l42_add_verbs, + [CS8409_FIXUPS] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs8409_cs42l42_fixups, }, }; @@ -2004,26 +1989,6 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) } } -static int cs8409_cs42l42_build_controls(struct hda_codec *codec) -{ - int err; - - err = snd_hda_gen_build_controls(codec); - if (err < 0) - return err; - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); - - /* Run jack auto detect first time on boot - * after controls have been added, to check if jack has - * been already plugged in - */ - cs8409_cs42l42_run_jack_detect(codec); - usleep_range(100000, 150000); - - return 0; -} - #ifdef CONFIG_PM /* Manage PDREF, when transition to D3hot */ static int cs8409_suspend(struct hda_codec *codec) @@ -2044,31 +2009,6 @@ static int cs8409_suspend(struct hda_codec *codec) } #endif -static void cs8409_cs42l42_cap_sync_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct cs_spec *spec = codec->spec; - unsigned int curval, expval; - /* CS8409 DMIC Pin only allows the setting of the Stream Parameters in - * Power State D0. When a headset is unplugged, and the path is switched to - * the DMIC, the Stream is restarted with the new ADC, but this is done in - * Power State D3. Restart the Stream now DMIC is in D0. - */ - if (spec->gen.cur_adc == CS8409_CS42L42_DMIC_ADC_PIN_NID) { - curval = snd_hda_codec_read(codec, spec->gen.cur_adc, - 0, AC_VERB_GET_CONV, 0); - expval = (spec->gen.cur_adc_stream_tag << 4) | 0; - if (curval != expval) { - codec_dbg(codec, "%s Restarting Stream after DMIC switch\n", __func__); - __snd_hda_codec_cleanup_stream(codec, spec->gen.cur_adc, 1); - snd_hda_codec_setup_stream(codec, spec->gen.cur_adc, - spec->gen.cur_adc_stream_tag, 0, - spec->gen.cur_adc_format); - } - } -} - /* Enable/Disable Unsolicited Response for gpio(s) 3,4 */ static void cs8409_enable_ur(struct hda_codec *codec, int flag) { @@ -2152,25 +2092,14 @@ static int cs8409_cs42l42_init(struct hda_codec *codec) { int ret = snd_hda_gen_init(codec); - if (!ret) { - /* On Dell platforms with suspend D3 mode support we - * have to re-initialise cs8409 bridge and companion - * cs42l42 codec - */ - snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); - snd_hda_sequence_write(codec, cs8409_cs42l42_add_verbs); - - cs8409_cs42l42_hw_init(codec); - - cs8409_cs42l42_run_jack_detect(codec); - usleep_range(100000, 150000); - } + if (!ret) + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); return ret; } static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { - .build_controls = cs8409_cs42l42_build_controls, + .build_controls = cs_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = cs8409_cs42l42_init, .free = cs_free, @@ -2180,66 +2109,91 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { #endif }; -static int cs8409_cs42l42_fixup(struct hda_codec *codec) +static void cs8409_cs42l42_fixups(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - int err; struct cs_spec *spec = codec->spec; int caps; - /* Basic initial sequence for specific hw configuration */ - snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); - - /* CS8409 is simple HDA bridge and intended to be used with a remote - * companion codec. Most of input/output PIN(s) have only basic - * capabilities. NID(s) 0x24 and 0x34 have only OUTC and INC - * capabilities and no presence detect capable (PDC) and call to - * snd_hda_gen_build_controls() will mark them as non detectable - * phantom jacks. However, in this configuration companion codec - * CS42L42 is connected to these pins and it has jack detect - * capabilities. We have to override pin capabilities, - * otherwise they will not be created as input devices. - */ - caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_HP_PIN_NID, - AC_PAR_PIN_CAP); - if (caps >= 0) - snd_hdac_override_parm(&codec->core, - CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, - (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); - - caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, - AC_PAR_PIN_CAP); - if (caps >= 0) - snd_hdac_override_parm(&codec->core, - CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP, - (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); - - snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID, - (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); - - snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID, - (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_add_verbs(codec, cs8409_cs42l42_init_verbs); + /* verb exec op override */ + spec->exec_verb = codec->core.exec_verb; + codec->core.exec_verb = cs8409_cs42l42_exec_verb; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + mutex_init(&spec->cs8409_i2c_mux); - err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, 0, 0); - if (err < 0) - return err; + codec->patch_ops = cs8409_cs42l42_patch_ops; - err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); - if (err < 0) - return err; + spec->gen.suppress_auto_mute = 1; + spec->gen.no_primary_hp = 1; + spec->gen.suppress_vmaster = 1; - if (!snd_hda_gen_add_kctl( - &spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer)) - return -1; + /* GPIO 5 out, 3,4 in */ + spec->gpio_dir = GPIO5_INT; + spec->gpio_data = 0; + spec->gpio_mask = 0x03f; - if (!snd_hda_gen_add_kctl( - &spec->gen, NULL, &cs8409_cs42l42_amic_volume_mixer)) - return -1; + spec->cs42l42_hp_jack_in = 0; + spec->cs42l42_mic_jack_in = 0; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + /* Basic initial sequence for specific hw configuration */ + snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); - return 0; + /* CS8409 is simple HDA bridge and intended to be used with a remote + * companion codec. Most of input/output PIN(s) have only basic + * capabilities. NID(s) 0x24 and 0x34 have only OUTC and INC + * capabilities and no presence detect capable (PDC) and call to + * snd_hda_gen_build_controls() will mark them as non detectable + * phantom jacks. However, in this configuration companion codec + * CS42L42 is connected to these pins and it has jack detect + * capabilities. We have to override pin capabilities, + * otherwise they will not be created as input devices. + */ + caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_HP_PIN_NID, + AC_PAR_PIN_CAP); + if (caps >= 0) + snd_hdac_override_parm(&codec->core, + CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, + (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + + caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, + AC_PAR_PIN_CAP); + if (caps >= 0) + snd_hdac_override_parm(&codec->core, + CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP, + (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + + snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID, + (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); + + snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID, + (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); + break; + case HDA_FIXUP_ACT_PROBE: + snd_hda_gen_add_kctl(&spec->gen, + NULL, &cs8409_cs42l42_hp_volume_mixer); + snd_hda_gen_add_kctl(&spec->gen, + NULL, &cs8409_cs42l42_amic_volume_mixer); + cs8409_cs42l42_hw_init(codec); + snd_hda_codec_set_name(codec, "CS8409/CS42L42"); + break; + case HDA_FIXUP_ACT_INIT: + cs8409_cs42l42_hw_init(codec); + fallthrough; + case HDA_FIXUP_ACT_BUILD: + /* Run jack auto detect first time on boot + * after controls have been added, to check if jack has + * been already plugged in. + * Run immediately after init. + */ + cs8409_cs42l42_run_jack_detect(codec); + usleep_range(100000, 150000); + break; + default: + break; + } } static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, @@ -2280,11 +2234,9 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, static int patch_cs8409(struct hda_codec *codec) { - struct cs_spec *spec; - int err = -EINVAL; + int err; - spec = cs_alloc_spec(codec, CS8409_VENDOR_NID); - if (!spec) + if (!cs_alloc_spec(codec, CS8409_VENDOR_NID)) return -ENOMEM; snd_hda_pick_fixup(codec, @@ -2295,52 +2247,16 @@ static int patch_cs8409(struct hda_codec *codec) codec->bus->pci->subsystem_vendor, codec->bus->pci->subsystem_device); - switch (codec->fixup_id) { - /* Dell platforms with CS42L42 companion codec */ - case CS8409_BULLSEYE: - case CS8409_WARLOCK: - case CS8409_CYBORG: - - snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs); - - /* verb exec op override */ - spec->exec_verb = codec->core.exec_verb; - codec->core.exec_verb = cs8409_cs42l42_exec_verb; - - mutex_init(&spec->cs8409_i2c_mux); - - codec->patch_ops = cs8409_cs42l42_patch_ops; - - spec->gen.cap_sync_hook = cs8409_cs42l42_cap_sync_hook; - - spec->gen.suppress_auto_mute = 1; - spec->gen.no_primary_hp = 1; - spec->gen.suppress_vmaster = 1; - /* GPIO 5 out, 3,4 in */ - spec->gpio_dir = GPIO5_INT; - spec->gpio_data = 0; - spec->gpio_mask = 0x03f; - - spec->cs42l42_hp_jack_in = 0; - spec->cs42l42_mic_jack_in = 0; - - err = cs8409_cs42l42_fixup(codec); - break; - - default: - codec_err(codec, "VID=%08x, DEV=%08x not supported\n", - codec->bus->pci->subsystem_vendor, - codec->bus->pci->subsystem_device); - break; - } + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - if (!err) { - cs8409_cs42l42_hw_init(codec); - snd_hda_codec_set_name(codec, "CS8409/CS42L42"); - } else + err = cs_parse_auto_config(codec); + if (err < 0) { cs_free(codec); + return err; + } - return err; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } /* -- cgit v1.2.3-58-ga151 From cbdce7a3620c7daff6b8a2cb27b41bb0a2e6f78d Mon Sep 17 00:00:00 2001 From: Aditya Srivastava Date: Thu, 18 Mar 2021 01:51:44 +0530 Subject: ALSA: asihpi: fix comment syntax in file headers The opening comment mark '/**' is used for highlighting the beginning of kernel-doc comments. There are files in sound/pci/asihpi which follow this syntax in their file headers, i.e. start with '/**' like comments, which causes unexpected warnings from kernel-doc. E.g., running scripts/kernel-doc -none on sound/pci/asihpi/hpidspcd.h causes this warning: "warning: Cannot understand on line 4 - I thought it was a doc line" Provide a simple fix by replacing the kernel-doc like comment syntax with general format, i.e. "/*", to prevent kernel-doc from parsing it. Signed-off-by: Aditya Srivastava Acked-by: Randy Dunlap Link: https://lore.kernel.org/r/20210317202144.20290-1-yashsri421@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpicmn.h | 2 +- sound/pci/asihpi/hpidspcd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h index de3bedd29d94..8ec656cf8848 100644 --- a/sound/pci/asihpi/hpicmn.h +++ b/sound/pci/asihpi/hpicmn.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* AudioScience HPI driver Copyright (C) 1997-2014 AudioScience Inc. diff --git a/sound/pci/asihpi/hpidspcd.h b/sound/pci/asihpi/hpidspcd.h index a01e8c6092bd..9f1468ed7096 100644 --- a/sound/pci/asihpi/hpidspcd.h +++ b/sound/pci/asihpi/hpidspcd.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /***********************************************************************/ -/** +/* AudioScience HPI driver Copyright (C) 1997-2011 AudioScience Inc. -- cgit v1.2.3-58-ga151 From a08b9f2f2267421092bf4b882a9461858216ed47 Mon Sep 17 00:00:00 2001 From: Aditya Srivastava Date: Thu, 18 Mar 2021 02:09:32 +0530 Subject: ALSA: ctxfi: fix comment syntax in file headers The opening comment mark '/**' is used for highlighting the beginning of kernel-doc comments. There are files in sound/pci/ctxfi which follow this syntax in their file headers, i.e. start with '/**' like comments, which causes unexpected warnings from kernel-doc. E.g., running scripts/kernel-doc -none on sound/pci/ctxfi/ctresource.c causes this warning: "warning: wrong kernel-doc identifier on line: * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved." Similarly for other files too. Provide a simple fix by replacing the kernel-doc like comment syntax with general format, i.e. "/*", to prevent kernel-doc from parsing it. Signed-off-by: Aditya Srivastava Acked-by: Randy Dunlap Link: https://lore.kernel.org/r/20210317203932.23993-1-yashsri421@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ct20k1reg.h | 2 +- sound/pci/ctxfi/ct20k2reg.h | 2 +- sound/pci/ctxfi/ctamixer.c | 2 +- sound/pci/ctxfi/ctamixer.h | 2 +- sound/pci/ctxfi/ctatc.c | 2 +- sound/pci/ctxfi/ctatc.h | 2 +- sound/pci/ctxfi/ctdaio.c | 2 +- sound/pci/ctxfi/ctdaio.h | 2 +- sound/pci/ctxfi/cthardware.h | 2 +- sound/pci/ctxfi/cthw20k1.h | 2 +- sound/pci/ctxfi/cthw20k2.h | 2 +- sound/pci/ctxfi/ctimap.h | 2 +- sound/pci/ctxfi/ctmixer.h | 2 +- sound/pci/ctxfi/ctpcm.h | 2 +- sound/pci/ctxfi/ctresource.c | 2 +- sound/pci/ctxfi/ctresource.h | 2 +- sound/pci/ctxfi/ctsrc.c | 2 +- sound/pci/ctxfi/ctsrc.h | 2 +- sound/pci/ctxfi/ctvmem.c | 2 +- sound/pci/ctxfi/ctvmem.h | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h index d4bfee499fb1..05bb006c0f4c 100644 --- a/sound/pci/ctxfi/ct20k1reg.h +++ b/sound/pci/ctxfi/ct20k1reg.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. */ diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h index af94ea66fdda..02f67828eabe 100644 --- a/sound/pci/ctxfi/ct20k2reg.h +++ b/sound/pci/ctxfi/ct20k2reg.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. */ diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index d4ff377eb3a3..da6e6350ceaf 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctamixer.c diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h index 4fafb397abed..4498e6139d0e 100644 --- a/sound/pci/ctxfi/ctamixer.h +++ b/sound/pci/ctxfi/ctamixer.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctamixer.h diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index f8ac96cf38a4..78f35e88aed6 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctatc.c diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index ac31b32b277b..0bc7b71d910b 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctatc.h diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 4cb47b5a792c..f589da045342 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctdaio.c diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h index 431583bb0a3e..bd6310f48013 100644 --- a/sound/pci/ctxfi/ctdaio.h +++ b/sound/pci/ctxfi/ctdaio.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctdaio.h diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h index 9e6b83bd432d..f406b626a28c 100644 --- a/sound/pci/ctxfi/cthardware.h +++ b/sound/pci/ctxfi/cthardware.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File cthardware.h diff --git a/sound/pci/ctxfi/cthw20k1.h b/sound/pci/ctxfi/cthw20k1.h index b7cbe82d71bd..ffb019abf651 100644 --- a/sound/pci/ctxfi/cthw20k1.h +++ b/sound/pci/ctxfi/cthw20k1.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File cthw20k1.h diff --git a/sound/pci/ctxfi/cthw20k2.h b/sound/pci/ctxfi/cthw20k2.h index 797b13dcd84c..6993a3d5277a 100644 --- a/sound/pci/ctxfi/cthw20k2.h +++ b/sound/pci/ctxfi/cthw20k2.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File cthw20k2.h diff --git a/sound/pci/ctxfi/ctimap.h b/sound/pci/ctxfi/ctimap.h index 79bc94bce4d5..49b1bb831410 100644 --- a/sound/pci/ctxfi/ctimap.h +++ b/sound/pci/ctxfi/ctimap.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctimap.h diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h index 770dc18a85e8..e812f6c93b41 100644 --- a/sound/pci/ctxfi/ctmixer.h +++ b/sound/pci/ctxfi/ctmixer.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctmixer.h diff --git a/sound/pci/ctxfi/ctpcm.h b/sound/pci/ctxfi/ctpcm.h index dfa1c62f7d1e..8b39bdd262b4 100644 --- a/sound/pci/ctxfi/ctpcm.h +++ b/sound/pci/ctxfi/ctpcm.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctpcm.h diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index 6d0a01b189e1..81ad26934518 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctresource.c diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h index 93e47488a1c1..fdbfd808816d 100644 --- a/sound/pci/ctxfi/ctresource.h +++ b/sound/pci/ctxfi/ctresource.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctresource.h diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 37c18ce84974..bd4697b44233 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctsrc.c diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h index 1204962280c8..1124daf50c9b 100644 --- a/sound/pci/ctxfi/ctsrc.h +++ b/sound/pci/ctxfi/ctsrc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctsrc.h diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index bde28aa9e139..7a805c4a58e1 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctvmem.c diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h index 54818a3c245d..da54cbcdb0be 100644 --- a/sound/pci/ctxfi/ctvmem.h +++ b/sound/pci/ctxfi/ctvmem.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctvmem.h -- cgit v1.2.3-58-ga151 From 8518c6486c2b8355e0781f8ee53c3c3f8427d96c Mon Sep 17 00:00:00 2001 From: huangjianghui Date: Fri, 19 Mar 2021 09:38:54 +0800 Subject: ALSA: hda: Fix spelling mistakes Signed-off-by: huangjianghui Link: https://lore.kernel.org/r/20210319013854.48830-1-huangjianghui@uniontech.com Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index a6ed3dc35f7e..1eb8563db2df 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -618,7 +618,7 @@ void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set, EXPORT_SYMBOL_GPL(snd_hdac_stream_sync_trigger); /** - * snd_hdac_stream_sync - sync with start/strop trigger operation + * snd_hdac_stream_sync - sync with start/stop trigger operation * @azx_dev: HD-audio core stream (master stream) * @start: true = start, false = stop * @streams: bit flags of streams to sync -- cgit v1.2.3-58-ga151 From dc85fc9d05d23591ddfde400c817413765611ec7 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Thu, 18 Mar 2021 17:06:16 +0100 Subject: ALSA: pcm: Add debug print on memory allocation failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add debug prints after calls of do_alloc_pages. One simplification would be to move print into do_alloc_pages, however it would cause spam in logs, as preallocate_pcm_pages loops over do_alloc_pages trying lower values in case of failures. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20210318160618.2504068-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/core/pcm_memory.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 289dd1fd8fe7..2878c4c23583 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -176,6 +176,10 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, substream->dma_buffer.dev.dev, size, &new_dmab) < 0) { buffer->error = -ENOMEM; + pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", + substream->pcm->card->number, substream->pcm->device, + substream->stream ? 'c' : 'p', substream->number, + substream->pcm->name, size); return; } substream->buffer_bytes_max = size; @@ -400,6 +404,10 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) substream->dma_buffer.dev.dev, size, dmab) < 0) { kfree(dmab); + pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", + substream->pcm->card->number, substream->pcm->device, + substream->stream ? 'c' : 'p', substream->number, + substream->pcm->name, size); return -ENOMEM; } } -- cgit v1.2.3-58-ga151 From f4b4bdf29ace71475b18aae9377402a534f09a72 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Thu, 18 Mar 2021 17:06:18 +0100 Subject: ALSA: hda: Revert "ALSA: hda: Allow setting preallocation again for x86" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f8e4ae10de43 ("ALSA: hda: Allow setting preallocation again for x86"). The reverted commit itself is a revert of c31427d0d21e ("ALSA: hda: No preallocation on x86 platforms"). It was needed because HDA allowed very big allocations, up to 1GB per stream. However as previous commit in this series changes maximum allowed allocation per stream to 4MB, we can safely revert it back. On systems where there are a lot of FrontEnds, when CONFIG_SND_HDA_PREALLOC_SIZE != 0 ALSA core allocates memory for each FE, which may cause out of memory problems due to per card limit. Force config to 0 on X86, so memory will be allocated on as needed basis. Bug: https://bugzilla.kernel.org/show_bug.cgi?id=201251#c322 Suggested-by: Takashi Iwai Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20210318160618.2504068-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/Kconfig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 57595f1552c9..741179ccbd4e 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -21,17 +21,16 @@ config SND_HDA_EXT_CORE select SND_HDA_CORE config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" + int "Pre-allocated buffer size for HD-audio driver" if !SND_DMA_SGBUF range 0 32768 - default 2048 if SND_DMA_SGBUF + default 0 if SND_DMA_SGBUF default 64 if !SND_DMA_SGBUF help Specifies the default pre-allocated buffer-size in kB for the HD-audio driver. A larger buffer (e.g. 2048) is preferred for systems using PulseAudio. The default 64 is chosen just for compatibility reasons. - On x86 systems, the default is 2048 as a reasonable value for - most of modern systems. + On x86 systems, the default is zero as we need no preallocation. Note that the pre-allocation size can be changed dynamically via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. -- cgit v1.2.3-58-ga151 From febf22565549ea7111e7d45e8f2d64373cc66b11 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Sat, 20 Mar 2021 17:15:41 +0800 Subject: ALSA: hda/realtek: fix a determine_headset_type issue for a Dell AIO We found a recording issue on a Dell AIO, users plug a headset-mic and select headset-mic from UI, but can't record any sound from headset-mic. The root cause is the determine_headset_type() returns a wrong type, e.g. users plug a ctia type headset, but that function returns omtp type. On this machine, the internal mic is not connected to the codec, the "Input Source" is headset mic by default. And when users plug a headset, the determine_headset_type() will be called immediately, the codec on this AIO is alc274, the delay time for this codec in the determine_headset_type() is only 80ms, the delay is too short to correctly determine the headset type, the fail rate is nearly 99% when users plug the headset with the normal speed. Other codecs set several hundred ms delay time, so here I change the delay time to 850ms for alc2x4 series, after this change, the fail rate is zero unless users plug the headset slowly on purpose. Cc: Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20210320091542.6748-1-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 316b9b4ccb32..8935bbe411a2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5256,7 +5256,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) case 0x10ec0274: case 0x10ec0294: alc_process_coef_fw(codec, coef0274); - msleep(80); + msleep(850); val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x00f0) == 0x00f0; break; -- cgit v1.2.3-58-ga151 From e54f30befa7990b897189b44a56c1138c6bfdbb5 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Sat, 20 Mar 2021 17:15:42 +0800 Subject: ALSA: hda/realtek: call alc_update_headset_mode() in hp_automute_hook We found the alc_update_headset_mode() is not called on some machines when unplugging the headset, as a result, the mode of the ALC_HEADSET_MODE_UNPLUGGED can't be set, then the current_headset_type is not cleared, if users plug a differnt type of headset next time, the determine_headset_type() will not be called and the audio jack is set to the headset type of previous time. On the Dell machines which connect the dmic to the PCH, if we open the gnome-sound-setting and unplug the headset, this issue will happen. Those machines disable the auto-mute by ucm and has no internal mic in the input source, so the update_headset_mode() will not be called by cap_sync_hook or automute_hook when unplugging, and because the gnome-sound-setting is opened, the codec will not enter the runtime_suspend state, so the update_headset_mode() will not be called by alc_resume when unplugging. In this case the hp_automute_hook is called when unplugging, so add update_headset_mode() calling to this function. Cc: Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20210320091542.6748-2-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8935bbe411a2..fc2f60c58ad8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5440,6 +5440,7 @@ static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_callback *jack) { snd_hda_gen_hp_automute(codec, jack); + alc_update_headset_mode(codec); } static void alc_probe_headset_mode(struct hda_codec *codec) -- cgit v1.2.3-58-ga151 From 507cdb9adba006a7798c358456426e1aea3d9c4f Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Sun, 21 Mar 2021 11:38:38 -0400 Subject: ALSA: hdsp: don't disable if not enabled hdsp wants to disable a not enabled pci device, which makes kernel throw a warning. Make sure the device is enabled before calling disable. [ 1.758292] snd_hdsp 0000:00:03.0: disabling already-disabled device [ 1.758327] WARNING: CPU: 0 PID: 180 at drivers/pci/pci.c:2146 pci_disable_device+0x91/0xb0 [ 1.766985] Call Trace: [ 1.767121] snd_hdsp_card_free+0x94/0xf0 [snd_hdsp] [ 1.767388] release_card_device+0x4b/0x80 [snd] [ 1.767639] device_release+0x3b/0xa0 [ 1.767838] kobject_put+0x94/0x1b0 [ 1.768027] put_device+0x13/0x20 [ 1.768207] snd_card_free+0x61/0x90 [snd] [ 1.768430] snd_hdsp_probe+0x524/0x5e0 [snd_hdsp] Suggested-by: Takashi Iwai Signed-off-by: Tong Zhang Link: https://lore.kernel.org/r/20210321153840.378226-2-ztong0001@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 6d9029333a12..ab9a32a2f5bb 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -5393,7 +5393,8 @@ static int snd_hdsp_free(struct hdsp *hdsp) if (hdsp->port) pci_release_regions(hdsp->pci); - pci_disable_device(hdsp->pci); + if (pci_is_enabled(hdsp->pci)) + pci_disable_device(hdsp->pci); return 0; } -- cgit v1.2.3-58-ga151 From 790f5719b85e12e10c41753b864e74249585ed08 Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Sun, 21 Mar 2021 11:38:39 -0400 Subject: ALSA: hdspm: don't disable if not enabled hdspm wants to disable a not enabled pci device, which makes kernel throw a warning. Make sure the device is enabled before calling disable. [ 1.786391] snd_hdspm 0000:00:03.0: disabling already-disabled device [ 1.786400] WARNING: CPU: 0 PID: 182 at drivers/pci/pci.c:2146 pci_disable_device+0x91/0xb0 [ 1.795181] Call Trace: [ 1.795320] snd_hdspm_card_free+0x58/0xa0 [snd_hdspm] [ 1.795595] release_card_device+0x4b/0x80 [snd] [ 1.795860] device_release+0x3b/0xa0 [ 1.796072] kobject_put+0x94/0x1b0 [ 1.796260] put_device+0x13/0x20 [ 1.796438] snd_card_free+0x61/0x90 [snd] [ 1.796659] snd_hdspm_probe+0x97b/0x1440 [snd_hdspm] Suggested-by: Takashi Iwai Signed-off-by: Tong Zhang Link: https://lore.kernel.org/r/20210321153840.378226-3-ztong0001@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index b66711574b1a..6edc31b44b22 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6884,7 +6884,8 @@ static int snd_hdspm_free(struct hdspm * hdspm) if (hdspm->port) pci_release_regions(hdspm->pci); - pci_disable_device(hdspm->pci); + if (pci_is_enabled(hdspm->pci)) + pci_disable_device(hdspm->pci); return 0; } -- cgit v1.2.3-58-ga151 From f57a741874bb6995089020e97a1dcdf9b165dcbe Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Sun, 21 Mar 2021 11:38:40 -0400 Subject: ALSA: rme9652: don't disable if not enabled rme9652 wants to disable a not enabled pci device, which makes kernel throw a warning. Make sure the device is enabled before calling disable. [ 1.751595] snd_rme9652 0000:00:03.0: disabling already-disabled device [ 1.751605] WARNING: CPU: 0 PID: 174 at drivers/pci/pci.c:2146 pci_disable_device+0x91/0xb0 [ 1.759968] Call Trace: [ 1.760145] snd_rme9652_card_free+0x76/0xa0 [snd_rme9652] [ 1.760434] release_card_device+0x4b/0x80 [snd] [ 1.760679] device_release+0x3b/0xa0 [ 1.760874] kobject_put+0x94/0x1b0 [ 1.761059] put_device+0x13/0x20 [ 1.761235] snd_card_free+0x61/0x90 [snd] [ 1.761454] snd_rme9652_probe+0x3be/0x700 [snd_rme9652] Suggested-by: Takashi Iwai Signed-off-by: Tong Zhang Link: https://lore.kernel.org/r/20210321153840.378226-4-ztong0001@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/rme9652/rme9652.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 012fbec5e6a7..0f4ab86a29f6 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1733,7 +1733,8 @@ static int snd_rme9652_free(struct snd_rme9652 *rme9652) if (rme9652->port) pci_release_regions(rme9652->pci); - pci_disable_device(rme9652->pci); + if (pci_is_enabled(rme9652->pci)) + pci_disable_device(rme9652->pci); return 0; } -- cgit v1.2.3-58-ga151 From caa271510687f3ce3eed3a120cd2a6f71bc49223 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 21 Mar 2021 12:28:29 +0900 Subject: ALSA: bebob: code refactoring for stream format detection ALSA bebob driver scans supported formats of packet for each direction when probing the target device. Some helper functions are used for the scanning, however its implementation is not necessarily irredundant. This commit refactors the helper functions to remove redundant codes. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210321032831.340278-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_stream.c | 68 +++++++++++++------------------------ 1 file changed, 24 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index bbae04793c50..d96d2feb15a8 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -796,42 +796,42 @@ parse_stream_formation(u8 *buf, unsigned int len, return 0; } -static int -fill_stream_formations(struct snd_bebob *bebob, enum avc_bridgeco_plug_dir dir, - unsigned short pid) +static int fill_stream_formations(struct snd_bebob *bebob, u8 addr[AVC_BRIDGECO_ADDR_BYTES], + enum avc_bridgeco_plug_dir plug_dir, unsigned int plug_id, + struct snd_bebob_stream_formation *formations) { + enum avc_bridgeco_plug_type plug_type; u8 *buf; - struct snd_bebob_stream_formation *formations; unsigned int len, eid; - u8 addr[AVC_BRIDGECO_ADDR_BYTES]; int err; + avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, plug_id); + + err = avc_bridgeco_get_plug_type(bebob->unit, addr, &plug_type); + if (err < 0) { + dev_err(&bebob->unit->device, + "Fail to get type for isoc %d plug 0: %d\n", plug_dir, err); + return err; + } else if (plug_type != AVC_BRIDGECO_PLUG_TYPE_ISOC) + return -ENXIO; + buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - if (dir == AVC_BRIDGECO_PLUG_DIR_IN) - formations = bebob->rx_stream_formations; - else - formations = bebob->tx_stream_formations; + for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; ++eid) { + avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, plug_id); - for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; eid++) { len = FORMAT_MAXIMUM_LENGTH; - avc_bridgeco_fill_unit_addr(addr, dir, - AVC_BRIDGECO_PLUG_UNIT_ISOC, pid); - err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf, - &len, eid); - /* No entries remained. */ + err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf, &len, eid); + // No entries remained. if (err == -EINVAL && eid > 0) { err = 0; break; } else if (err < 0) { dev_err(&bebob->unit->device, - "fail to get stream format %d for isoc %s plug %d:%d\n", - eid, - (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : - "out", - pid, err); + "fail to get stream format %d for isoc %d plug %d:%d\n", + eid, plug_dir, plug_id, err); break; } @@ -908,33 +908,13 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob) goto end; } - avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, - AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); - err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get type for isoc in plug 0: %d\n", err); - goto end; - } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { - err = -ENOSYS; - goto end; - } - err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_IN, 0); + err = fill_stream_formations(bebob, addr, AVC_BRIDGECO_PLUG_DIR_IN, 0, + bebob->rx_stream_formations); if (err < 0) goto end; - avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, - AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); - err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get type for isoc out plug 0: %d\n", err); - goto end; - } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { - err = -ENOSYS; - goto end; - } - err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_OUT, 0); + err = fill_stream_formations(bebob, addr, AVC_BRIDGECO_PLUG_DIR_OUT, 0, + bebob->tx_stream_formations); if (err < 0) goto end; -- cgit v1.2.3-58-ga151 From 5c6ea94f2b7c5ce4c012ac8c23fd35588f69c4c7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 21 Mar 2021 12:28:30 +0900 Subject: ALSA: bebob: detect the number of available MIDI ports Current implementation counts the number of input/output plugs for MIDI type and uses the count as the number of physical MIDI ports. However, the number of channels of the port represents the count. This commit fixes the bug by additional vendor-specific AVC command extension. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210321032831.340278-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.h | 2 + sound/firewire/bebob/bebob_command.c | 36 ++++++++++++++++ sound/firewire/bebob/bebob_stream.c | 83 ++++++++++++++++++++++-------------- 3 files changed, 89 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index d1ad9a8451bc..4e0ed84adbee 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -200,6 +200,8 @@ int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, int avc_bridgeco_get_plug_type(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], enum avc_bridgeco_plug_type *type); +int avc_bridgeco_get_plug_ch_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], + unsigned int *ch_count); int avc_bridgeco_get_plug_section_type(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], unsigned int id, u8 *type); diff --git a/sound/firewire/bebob/bebob_command.c b/sound/firewire/bebob/bebob_command.c index e276ab8f9006..022df09c68ff 100644 --- a/sound/firewire/bebob/bebob_command.c +++ b/sound/firewire/bebob/bebob_command.c @@ -143,6 +143,42 @@ end: return err; } +int avc_bridgeco_get_plug_ch_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], + unsigned int *ch_count) +{ + u8 *buf; + int err; + + buf = kzalloc(12, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + // Info type is 'plug type'. + avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x02); + + err = fcp_avc_transaction(unit, buf, 12, buf, 12, + BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | + BIT(6) | BIT(7) | BIT(9)); + if (err < 0) + ; + else if (err < 11) + err = -EIO; + else if (buf[0] == 0x08) // NOT IMPLEMENTED + err = -ENOSYS; + else if (buf[0] == 0x0a) // REJECTED + err = -EINVAL; + else if (buf[0] == 0x0b) // IN TRANSITION + err = -EAGAIN; + if (err < 0) + goto end; + + *ch_count = buf[10]; + err = 0; +end: + kfree(buf); + return err; +} + int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf, unsigned int len) diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index d96d2feb15a8..23579a73e038 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -844,6 +844,49 @@ static int fill_stream_formations(struct snd_bebob *bebob, u8 addr[AVC_BRIDGECO_ return err; } +static int detect_midi_ports(struct snd_bebob *bebob, + const struct snd_bebob_stream_formation *formats, + u8 addr[AVC_BRIDGECO_ADDR_BYTES], enum avc_bridgeco_plug_dir plug_dir, + unsigned int plug_count, unsigned int *midi_ports) +{ + int i; + int err = 0; + + *midi_ports = 0; + + /// Detect the number of available MIDI ports when packet has MIDI conformant data channel. + for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; ++i) { + if (formats[i].midi > 0) + break; + } + if (i >= SND_BEBOB_STRM_FMT_ENTRIES) + return 0; + + for (i = 0; i < plug_count; ++i) { + enum avc_bridgeco_plug_type plug_type; + unsigned int ch_count; + + avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_EXT, i); + + err = avc_bridgeco_get_plug_type(bebob->unit, addr, &plug_type); + if (err < 0) { + dev_err(&bebob->unit->device, + "fail to get type for external %d plug %d: %d\n", + plug_dir, i, err); + break; + } else if (plug_type != AVC_BRIDGECO_PLUG_TYPE_MIDI) { + continue; + } + + err = avc_bridgeco_get_plug_ch_count(bebob->unit, addr, &ch_count); + if (err < 0) + break; + *midi_ports += ch_count; + } + + return err; +} + static int seek_msu_sync_input_plug(struct snd_bebob *bebob) { @@ -886,8 +929,6 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob) { const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock; u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES]; - enum avc_bridgeco_plug_type type; - unsigned int i; int err; /* the number of plugs for isoc in/out, ext in/out */ @@ -918,37 +959,15 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob) if (err < 0) goto end; - /* count external input plugs for MIDI */ - bebob->midi_input_ports = 0; - for (i = 0; i < plugs[2]; i++) { - avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, - AVC_BRIDGECO_PLUG_UNIT_EXT, i); - err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get type for external in plug %d: %d\n", - i, err); - goto end; - } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { - bebob->midi_input_ports++; - } - } + err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN, + plugs[2], &bebob->midi_input_ports); + if (err < 0) + goto end; - /* count external output plugs for MIDI */ - bebob->midi_output_ports = 0; - for (i = 0; i < plugs[3]; i++) { - avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, - AVC_BRIDGECO_PLUG_UNIT_EXT, i); - err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get type for external out plug %d: %d\n", - i, err); - goto end; - } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { - bebob->midi_output_ports++; - } - } + err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT, + plugs[3], &bebob->midi_output_ports); + if (err < 0) + goto end; /* for check source of clock later */ if (!clk_spec) -- cgit v1.2.3-58-ga151 From d2b6f15bc18ac8fbce25398290774c21f5b2cd44 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 21 Mar 2021 12:28:31 +0900 Subject: ALSA: bebob: enable to deliver MIDI messages for multiple ports Current implementation of bebob driver doesn't correctly handle the case that the device has multiple MIDI ports. The cause is the number of MIDI conformant data channels is passed to AM824 data block processing layer. This commit fixes the bug. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210321032831.340278-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_stream.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 23579a73e038..b612ee3e33b6 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -517,20 +517,22 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, unsigned int rate, unsigned int index) { - struct snd_bebob_stream_formation *formation; + unsigned int pcm_channels; + unsigned int midi_ports; struct cmp_connection *conn; int err; if (stream == &bebob->tx_stream) { - formation = bebob->tx_stream_formations + index; + pcm_channels = bebob->tx_stream_formations[index].pcm; + midi_ports = bebob->midi_input_ports; conn = &bebob->out_conn; } else { - formation = bebob->rx_stream_formations + index; + pcm_channels = bebob->rx_stream_formations[index].pcm; + midi_ports = bebob->midi_output_ports; conn = &bebob->in_conn; } - err = amdtp_am824_set_parameters(stream, rate, formation->pcm, - formation->midi, false); + err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports, false); if (err < 0) return err; -- cgit v1.2.3-58-ga151 From 940ba1f5e18d4411c4e87ef902dc811a10d341d0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Mar 2021 11:31:10 +0100 Subject: ALSA: core: avoid -Wempty-body warnings Building with 'make W=1' shows some warnings about empty function-style macros: sound/core/pcm_memory.c: In function 'preallocate_pages': sound/core/pcm_memory.c:236:49: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body] 236 | preallocate_info_init(substream); sound/core/seq_device.c: In function 'snd_seq_device_dev_register': sound/core/seq_device.c:163:41: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body] 163 | queue_autoload_drivers(); Change them to empty inline functions, which are more robust here. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20210322103128.547199-1-arnd@kernel.org Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 8 ++++++-- sound/core/pcm_memory.c | 4 +++- sound/core/seq_device.c | 15 ++++++++++++--- 3 files changed, 21 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 142fc751a847..86c39ee01aaa 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -3069,8 +3069,12 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm) } } #else /* !CONFIG_SND_VERBOSE_PROCFS */ -#define snd_pcm_oss_proc_init(pcm) -#define snd_pcm_oss_proc_done(pcm) +static inline void snd_pcm_oss_proc_init(struct snd_pcm *pcm) +{ +} +static inline void snd_pcm_oss_proc_done(struct snd_pcm *pcm) +{ +} #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 2878c4c23583..542a75babdee 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -214,7 +214,9 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) } #else /* !CONFIG_SND_VERBOSE_PROCFS */ -#define preallocate_info_init(s) +static inline void preallocate_info_init(struct snd_pcm_substream *substream) +{ +} #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* diff --git a/sound/core/seq_device.c b/sound/core/seq_device.c index 7ed13cb32ef8..382275c5b193 100644 --- a/sound/core/seq_device.c +++ b/sound/core/seq_device.c @@ -133,10 +133,19 @@ void snd_seq_device_load_drivers(void) flush_work(&autoload_work); } EXPORT_SYMBOL(snd_seq_device_load_drivers); -#define cancel_autoload_drivers() cancel_work_sync(&autoload_work) + +static inline void cancel_autoload_drivers(void) +{ + cancel_work_sync(&autoload_work); +} #else -#define queue_autoload_drivers() /* NOP */ -#define cancel_autoload_drivers() /* NOP */ +static inline void queue_autoload_drivers(void) +{ +} + +static inline void cancel_autoload_drivers(void) +{ +} #endif /* -- cgit v1.2.3-58-ga151 From 927280909fa7d8e61596800d82f18047c6cfbbe4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 22 Mar 2021 11:37:21 -0500 Subject: ASoC: SOF: Intel: HDA: fix core status verification When checking for enabled cores it isn't enough to check that some of the requested cores are running, we have to check that all of them are. Fixes: 747503b1813a ("ASoC: SOF: Intel: Add Intel specific HDA DSP HW operations") Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210322163728.16616-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index c3b757cf01a0..2543ef1b5098 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -226,10 +226,17 @@ bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); - is_enable = (val & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) && - (val & HDA_DSP_ADSPCS_SPA_MASK(core_mask)) && - !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) && - !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); +#define MASK_IS_EQUAL(v, m, field) ({ \ + u32 _m = field(m); \ + ((v) & _m) == _m; \ +}) + + is_enable = MASK_IS_EQUAL(val, core_mask, HDA_DSP_ADSPCS_CPA_MASK) && + MASK_IS_EQUAL(val, core_mask, HDA_DSP_ADSPCS_SPA_MASK) && + !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) && + !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); + +#undef MASK_IS_EQUAL dev_dbg(sdev->dev, "DSP core(s) enabled? %d : core_mask %x\n", is_enable, core_mask); -- cgit v1.2.3-58-ga151 From 91ec48f540f83022377723a774a0a37a630801af Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Mar 2021 11:37:22 -0500 Subject: ASoC: SOF: core: harden shutdown helper When the probe is handled in a workqueue, we must use cancel_work_sync() in the shutdown helper to avoid possible race conditions. We must also take care of possible errors happening in a probe workqueue or during pm_runtime resume (called e.g. before shutdown for PCI devices). We should really only try to access hardware registers and initiate IPCs if the DSP is fully booted. Fixes: daff7f1478e12 ("ASoC: SOF: add snd_sof_device_shutdown() helper for shutdown") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Libin Yang Link: https://lore.kernel.org/r/20210322163728.16616-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 6d8f7d9fd192..4a3d522f612b 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -399,7 +399,13 @@ int snd_sof_device_shutdown(struct device *dev) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - return snd_sof_shutdown(sdev); + if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) + cancel_work_sync(&sdev->probe_work); + + if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) + return snd_sof_shutdown(sdev); + + return 0; } EXPORT_SYMBOL(snd_sof_device_shutdown); -- cgit v1.2.3-58-ga151 From 3c429f861ed483517a0a352281a16503bcc60b55 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 22 Mar 2021 11:37:23 -0500 Subject: ASoC: SOF: Intel: TGL: fix EHL ops EHL is derived from TGL, not CNL, so we shall use the TGL ops. Fixes: 8d4ba1be3d22 ("ASoC: SOF: pci: split PCI into different drivers") Reviewed-by: Ranjani Sridharan Signed-off-by: Libin Yang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210322163728.16616-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/pci-tgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 485607471181..38bc353f7313 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -65,7 +65,7 @@ static const struct sof_dev_desc ehl_desc = { .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-ehl.ri", .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", - .ops = &sof_cnl_ops, + .ops = &sof_tgl_ops, }; static const struct sof_dev_desc adls_desc = { -- cgit v1.2.3-58-ga151 From 22aa9e021ad1ee7ce640270e75f4bdccff65d287 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 22 Mar 2021 11:37:24 -0500 Subject: ASoC: SOF: Intel: TGL: set shutdown callback to hda_dsp_shutdown According to hardware spec and PMC FW requirement, the DSP must be in D3 state before entering S5. Define the shutdown function to use snd_sof_suspend as shutdown callback to make sure DSP is in D3 state. Fixes: 44a4cfad8d78 ("ASoC: SOF: Intel: tgl: do thorough remove at .shutdown() callback") Reviewed-by: Ranjani Sridharan Signed-off-by: Pan Xiuli Signed-off-by: Libin Yang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210322163728.16616-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 6 ++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/tgl.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 2543ef1b5098..736a54beca23 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -892,6 +892,12 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); } +int hda_dsp_shutdown(struct snd_sof_dev *sdev) +{ + sdev->system_suspend_target = SOF_SUSPEND_S3; + return snd_sof_suspend(sdev->dev); +} + int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 7c7579daee7f..ae80725b0e33 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -517,6 +517,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_idle(struct snd_sof_dev *sdev); +int hda_dsp_shutdown(struct snd_sof_dev *sdev); int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); void hda_ipc_dump(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 419f05ba1920..3e46fac53f78 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -25,7 +25,7 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { /* probe/remove/shutdown */ .probe = hda_dsp_probe, .remove = hda_dsp_remove, - .shutdown = hda_dsp_remove, + .shutdown = hda_dsp_shutdown, /* Register IO */ .write = sof_io_write, -- cgit v1.2.3-58-ga151 From 4939e49ea5804f89941df86d35f1a1e1cd8b435b Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 22 Mar 2021 11:37:25 -0500 Subject: ASoC: SOF: Intel: ICL: set shutdown callback to hda_dsp_shutdown According to hardware spec and PMC FW requirement, the DSP must be in D3 state before entering S5. Set shutdown call to hda_dsp_shutdown. Reviewed-by: Ranjani Sridharan Signed-off-by: Libin Yang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210322163728.16616-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/icl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index e9d5a0a58504..88a74be8a0c1 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -26,9 +26,10 @@ static const struct snd_sof_debugfs_map icl_dsp_debugfs[] = { /* Icelake ops */ const struct snd_sof_dsp_ops sof_icl_ops = { - /* probe and remove */ + /* probe/remove/shutdown */ .probe = hda_dsp_probe, .remove = hda_dsp_remove, + .shutdown = hda_dsp_shutdown, /* Register IO */ .write = sof_io_write, -- cgit v1.2.3-58-ga151 From b0503e8410e5ee43da116772576dbdeb2a414e0b Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 22 Mar 2021 11:37:26 -0500 Subject: ASoC: SOF: Intel: CNL: set shutdown callback to hda_dsp_shutdown According to hardware spec and PMC FW requirement, the DSP must be in D3 state before entering S5. Set shutdown call to hda_dsp_shutdown. Reviewed-by: Ranjani Sridharan Signed-off-by: Libin Yang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210322163728.16616-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/cnl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index e38db519f38d..094cde17a1b7 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -232,9 +232,10 @@ void cnl_ipc_dump(struct snd_sof_dev *sdev) /* cannonlake ops */ const struct snd_sof_dsp_ops sof_cnl_ops = { - /* probe and remove */ + /* probe/remove/shutdown */ .probe = hda_dsp_probe, .remove = hda_dsp_remove, + .shutdown = hda_dsp_shutdown, /* Register IO */ .write = sof_io_write, -- cgit v1.2.3-58-ga151 From d3aa96bf349882763b9903e5800d2e83fc086886 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 22 Mar 2021 11:37:27 -0500 Subject: ASoC: SOF: Intel: APL: set shutdown callback to hda_dsp_shutdown According to hardware spec and PMC FW requirement, the DSP must be in D3 state before entering S5. Set shutdown call to hda_dsp_shutdown. Reviewed-by: Ranjani Sridharan Signed-off-by: Libin Yang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210322163728.16616-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index fc29b91b8932..c7ed2b3d6abc 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -27,9 +27,10 @@ static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = { /* apollolake ops */ const struct snd_sof_dsp_ops sof_apl_ops = { - /* probe and remove */ + /* probe/remove/shutdown */ .probe = hda_dsp_probe, .remove = hda_dsp_remove, + .shutdown = hda_dsp_shutdown, /* Register IO */ .write = sof_io_write, -- cgit v1.2.3-58-ga151 From 8bb84ca873d2222ca220e58a097090775b1fd8df Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Mar 2021 11:37:28 -0500 Subject: ASoC: SOF: Intel: move ELH chip info ELH is a derivative of TGL, so it should be exposed in tgl.c for consistency. No functional change. Reviewed-by: Rander Wang Reviewed-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210322163728.16616-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/cnl.c | 16 ---------------- sound/soc/sof/intel/tgl.c | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 094cde17a1b7..821f25fbcf08 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -350,22 +350,6 @@ const struct sof_intel_dsp_desc cnl_chip_info = { }; EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -const struct sof_intel_dsp_desc ehl_chip_info = { - /* Elkhartlake */ - .cores_num = 4, - .init_core_mask = 1, - .host_managed_cores_mask = BIT(0), - .ipc_req = CNL_DSP_REG_HIPCIDR, - .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, - .ipc_ack = CNL_DSP_REG_HIPCIDA, - .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, - .ipc_ctl = CNL_DSP_REG_HIPCCTL, - .rom_init_timeout = 300, - .ssp_count = ICL_SSP_COUNT, - .ssp_base_offset = CNL_SSP_BASE_OFFSET, -}; -EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); - const struct sof_intel_dsp_desc jsl_chip_info = { /* Jasperlake */ .cores_num = 2, diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 3e46fac53f78..54ba1b88ba86 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -156,6 +156,22 @@ const struct sof_intel_dsp_desc tglh_chip_info = { }; EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); +const struct sof_intel_dsp_desc ehl_chip_info = { + /* Elkhartlake */ + .cores_num = 4, + .init_core_mask = 1, + .host_managed_cores_mask = BIT(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); + const struct sof_intel_dsp_desc adls_chip_info = { /* Alderlake-S */ .cores_num = 2, -- cgit v1.2.3-58-ga151 From 16b82e75c15a7dbd564ea3654f3feb61df9e1e6f Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 19 Mar 2021 18:48:46 +0800 Subject: ASoC: wm8960: Fix wrong bclk and lrclk with pll enabled for some chips The input MCLK is 12.288MHz, the desired output sysclk is 11.2896MHz and sample rate is 44100Hz, with the configuration pllprescale=2, postscale=sysclkdiv=1, some chip may have wrong bclk and lrclk output with pll enabled in master mode, but with the configuration pllprescale=1, postscale=2, the output clock is correct. >From Datasheet, the PLL performs best when f2 is between 90MHz and 100MHz when the desired sysclk output is 11.2896MHz or 12.288MHz, so sysclkdiv = 2 (f2/8) is the best choice. So search available sysclk_divs from 2 to 1 other than from 1 to 2. Fixes: 84fdc00d519f ("ASoC: codec: wm9860: Refactor PLL out freq search") Signed-off-by: Shengjiu Wang Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1616150926-22892-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index df351519a3a6..cda9cd935d4f 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -707,7 +707,13 @@ int wm8960_configure_pll(struct snd_soc_component *component, int freq_in, best_freq_out = -EINVAL; *sysclk_idx = *dac_idx = *bclk_idx = -1; - for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { + /* + * From Datasheet, the PLL performs best when f2 is between + * 90MHz and 100MHz, the desired sysclk output is 11.2896MHz + * or 12.288MHz, then sysclkdiv = 2 is the best choice. + * So search sysclk_divs from 2 to 1 other than from 1 to 2. + */ + for (i = ARRAY_SIZE(sysclk_divs) - 1; i >= 0; --i) { if (sysclk_divs[i] == -1) continue; for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { -- cgit v1.2.3-58-ga151 From aa65bacdb70e549a81de03ec72338e1047842883 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 24 Mar 2021 14:27:10 +0100 Subject: ASoC: intel: atom: Stop advertising non working S24LE support The SST firmware's media and deep-buffer inputs are hardcoded to S16LE, the corresponding DAIs don't have a hw_params callback and their prepare callback also does not take the format into account. So far the advertising of non working S24LE support has not caused issues because pulseaudio defaults to S16LE, but changing pulse-audio's config to use S24LE will result in broken sound. Pipewire is replacing pulse now and pipewire prefers S24LE over S16LE when available, causing the problem of the broken S24LE support to come to the surface now. Cc: stable@vger.kernel.org BugLink: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/866 Fixes: 098c2cd281409 ("ASoC: Intel: Atom: add 24-bit support for media playback and capture") Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210324132711.216152-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 9e9b05883557..aa5dd590ddd5 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -488,14 +488,14 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .channels_min = SST_STEREO, .channels_max = SST_STEREO, .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { .stream_name = "Headset Capture", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }, { @@ -506,7 +506,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .channels_min = SST_STEREO, .channels_max = SST_STEREO, .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }, { -- cgit v1.2.3-58-ga151 From 632aeebe1b7a3a8b193d71942a10e66919bebfb8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 24 Mar 2021 14:27:11 +0100 Subject: ASoC: intel: atom: Remove 44100 sample-rate from the media and deep-buffer DAI descriptions The media and deep-buffer DAIs only support 48000 Hz samplerate, remove the 44100 sample-rate from their descriptions. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210324132711.216152-3-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index aa5dd590ddd5..4124aa2fc247 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -487,14 +487,14 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .stream_name = "Headset Playback", .channels_min = SST_STEREO, .channels_max = SST_STEREO, - .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, + .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { .stream_name = "Headset Capture", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, + .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }, @@ -505,7 +505,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .stream_name = "Deepbuffer Playback", .channels_min = SST_STEREO, .channels_max = SST_STEREO, - .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, + .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }, -- cgit v1.2.3-58-ga151 From e839fbed26e8b8713803b8ac73da92fd2b0c7594 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 24 Mar 2021 19:23:37 +0200 Subject: ALSA: hda/hdmi: fix max DP-MST dev_num for Intel TGL+ platforms Increase the device select range to 4 on platforms supporting 4 concurrent displays. This fixes a problem in scenario where total of 4 displays are active, and 3 of these are audio capable DP receivers and connected to a DP-MST hub. Due to incorrect range for device select, audio could not be played to the 3rd monitor in DP-MST hub. BugLink: https://github.com/thesofproject/linux/issues/2798 Signed-off-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210324172337.51730-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index e6d0843ee9df..76d8f6c6060a 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1848,16 +1848,12 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) */ if (spec->intel_hsw_fixup) { /* - * On Intel platforms, device entries number is - * changed dynamically. If there is a DP MST - * hub connected, the device entries number is 3. - * Otherwise, it is 1. - * Here we manually set dev_num to 3, so that - * we can initialize all the device entries when - * bootup statically. + * On Intel platforms, device entries count returned + * by AC_PAR_DEVLIST_LEN is dynamic, and depends on + * the type of receiver that is connected. Allocate pin + * structures based on worst case. */ - dev_num = 3; - spec->dev_num = 3; + dev_num = spec->dev_num; } else if (spec->dyn_pcm_assign && codec->dp_mst) { dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1; /* @@ -2929,7 +2925,7 @@ static int parse_intel_hdmi(struct hda_codec *codec) /* Intel Haswell and onwards; audio component with eld notifier */ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, - const int *port_map, int port_num) + const int *port_map, int port_num, int dev_num) { struct hdmi_spec *spec; int err; @@ -2944,6 +2940,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, spec->port_map = port_map; spec->port_num = port_num; spec->intel_hsw_fixup = true; + spec->dev_num = dev_num; intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); @@ -2969,12 +2966,12 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, static int patch_i915_hsw_hdmi(struct hda_codec *codec) { - return intel_hsw_common_init(codec, 0x08, NULL, 0); + return intel_hsw_common_init(codec, 0x08, NULL, 0, 3); } static int patch_i915_glk_hdmi(struct hda_codec *codec) { - return intel_hsw_common_init(codec, 0x0b, NULL, 0); + return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3); } static int patch_i915_icl_hdmi(struct hda_codec *codec) @@ -2985,7 +2982,7 @@ static int patch_i915_icl_hdmi(struct hda_codec *codec) */ static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb}; - return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); + return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3); } static int patch_i915_tgl_hdmi(struct hda_codec *codec) @@ -2997,7 +2994,7 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec) static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; int ret; - ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); + ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4); if (!ret) { struct hdmi_spec *spec = codec->spec; -- cgit v1.2.3-58-ga151 From a23f9099ff1541f15704e96b784d3846d2a4483d Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 24 Mar 2021 20:35:53 -0700 Subject: ASoC: max98373: Changed amp shutdown register as volatile 0x20FF(amp global enable) register was defined as non-volatile, but it is not. Overheating, overcurrent can cause amp shutdown in hardware. 'regmap_write' compare register readback value before writing to avoid same value writing. 'regmap_read' just read cache not actual hardware value for the non-volatile register. When amp is internally shutdown by some reason, next 'AMP ON' command can be ignored because regmap think amp is already ON. Signed-off-by: Ryan Lee Link: https://lore.kernel.org/r/20210325033555.29377-1-ryans.lee@maximintegrated.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98373-i2c.c | 1 + sound/soc/codecs/max98373-sdw.c | 1 + 2 files changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index 85f6865019d4..ddb6436835d7 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -446,6 +446,7 @@ static bool max98373_volatile_reg(struct device *dev, unsigned int reg) case MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK: case MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK: case MAX98373_R20B6_BDE_CUR_STATE_READBACK: + case MAX98373_R20FF_GLOBAL_SHDN: case MAX98373_R21FF_REV_ID: return true; default: diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index d8c47667a9ea..f3a12205cd48 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -220,6 +220,7 @@ static bool max98373_volatile_reg(struct device *dev, unsigned int reg) case MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK: case MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK: case MAX98373_R20B6_BDE_CUR_STATE_READBACK: + case MAX98373_R20FF_GLOBAL_SHDN: case MAX98373_R21FF_REV_ID: /* SoundWire Control Port Registers */ case MAX98373_R0040_SCP_INIT_STAT_1 ... MAX98373_R0070_SCP_FRAME_CTLR: -- cgit v1.2.3-58-ga151 From 3a27875e91fb9c29de436199d20b33f9413aea77 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 24 Mar 2021 20:35:54 -0700 Subject: ASoC: max98373: Added 30ms turn on/off time delay Amp requires 10 ~ 30ms for the power ON and OFF. Added 30ms delay for stability. Signed-off-by: Ryan Lee Link: https://lore.kernel.org/r/20210325033555.29377-2-ryans.lee@maximintegrated.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 746c829312b8..1346a98ce8a1 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -28,11 +28,13 @@ static int max98373_dac_event(struct snd_soc_dapm_widget *w, regmap_update_bits(max98373->regmap, MAX98373_R20FF_GLOBAL_SHDN, MAX98373_GLOBAL_EN_MASK, 1); + usleep_range(30000, 31000); break; case SND_SOC_DAPM_POST_PMD: regmap_update_bits(max98373->regmap, MAX98373_R20FF_GLOBAL_SHDN, MAX98373_GLOBAL_EN_MASK, 0); + usleep_range(30000, 31000); max98373->tdm_mode = false; break; default: -- cgit v1.2.3-58-ga151 From 69644fca2716699cc6896aff51d37b1e886c94d2 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 26 Mar 2021 00:59:12 +0800 Subject: ALSA: usb-audio: Carve out connector value checking into a helper This is preparation for next patch, no functional change intended. Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20210325165918.22593-1-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index b004b2e63a5d..5a2d9a768f70 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1446,13 +1446,11 @@ static int mixer_ctl_master_bool_get(struct snd_kcontrol *kcontrol, return 0; } -/* get the connectors status and report it as boolean type */ -static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int get_connector_value(struct usb_mixer_elem_info *cval, + char *name, int *val) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; struct snd_usb_audio *chip = cval->head.mixer->chip; - int idx = 0, validx, ret, val; + int idx = 0, validx, ret; validx = cval->control << 8 | 0; @@ -1467,21 +1465,24 @@ static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, &uac2_conn, sizeof(uac2_conn)); - val = !!uac2_conn.bNrChannels; + if (val) + *val = !!uac2_conn.bNrChannels; } else { /* UAC_VERSION_3 */ struct uac3_insertion_ctl_blk uac3_conn; ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, &uac3_conn, sizeof(uac3_conn)); - val = !!uac3_conn.bmConInserted; + if (val) + *val = !!uac3_conn.bmConInserted; } snd_usb_unlock_shutdown(chip); if (ret < 0) { - if (strstr(kcontrol->id.name, "Speaker")) { - ucontrol->value.integer.value[0] = 1; + if (name && strstr(name, "Speaker")) { + if (val) + *val = 1; return 0; } error: @@ -1491,6 +1492,21 @@ error: return filter_error(cval, ret); } + return ret; +} + +/* get the connectors status and report it as boolean type */ +static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *cval = kcontrol->private_data; + int ret, val; + + ret = get_connector_value(cval, kcontrol->id.name, &val); + + if (ret < 0) + return ret; + ucontrol->value.integer.value[0] = val; return 0; } -- cgit v1.2.3-58-ga151 From 44609fc01f280d6b4067262ecbb00e3128d718ae Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 26 Mar 2021 00:59:13 +0800 Subject: ALSA: usb-audio: Check connector value on resume Rear Mic on Lenovo P620 cannot record after S3, despite that there's no error and the other two functions of the USB audio, Line In and Line Out, work just fine. The mic starts to work again after running userspace app like "alsactl store". Following the lead, the evidence shows that as soon as connector status is queried, the mic can work again. So also check connector value on resume to "wake up" the USB audio to make it functional. This can be device specific, however I think this generic approach may benefit more than one device. Now the resume callback checks connector, and a new callback, reset_resume, to also restore switches and volumes. Suggested-by: Takashi Iwai Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20210325165918.22593-2-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 44 ++++++++++++++++++++++++++++++++++---------- sound/usb/mixer.h | 1 + sound/usb/mixer_quirks.c | 2 +- 3 files changed, 36 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 5a2d9a768f70..2faf5767c7f8 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -3631,20 +3631,43 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list) return 0; } +static int default_mixer_resume(struct usb_mixer_elem_list *list) +{ + struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); + + /* get connector value to "wake up" the USB audio */ + if (cval->val_type == USB_MIXER_BOOLEAN && cval->channels == 1) + get_connector_value(cval, NULL, NULL); + + return 0; +} + +static int default_mixer_reset_resume(struct usb_mixer_elem_list *list) +{ + int err = default_mixer_resume(list); + + if (err < 0) + return err; + return restore_mixer_value(list); +} + int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) { struct usb_mixer_elem_list *list; + usb_mixer_elem_resume_func_t f; int id, err; - if (reset_resume) { - /* restore cached mixer values */ - for (id = 0; id < MAX_ID_ELEMS; id++) { - for_each_mixer_elem(list, mixer, id) { - if (list->resume) { - err = list->resume(list); - if (err < 0) - return err; - } + /* restore cached mixer values */ + for (id = 0; id < MAX_ID_ELEMS; id++) { + for_each_mixer_elem(list, mixer, id) { + if (reset_resume) + f = list->reset_resume; + else + f = list->resume; + if (f) { + err = f(list); + if (err < 0) + return err; } } } @@ -3663,6 +3686,7 @@ void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list, list->id = unitid; list->dump = snd_usb_mixer_dump_cval; #ifdef CONFIG_PM - list->resume = restore_mixer_value; + list->resume = default_mixer_resume; + list->reset_resume = default_mixer_reset_resume; #endif } diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index c29e27ac43a7..e5a01f17bf3c 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -69,6 +69,7 @@ struct usb_mixer_elem_list { bool is_std_info; usb_mixer_elem_dump_func_t dump; usb_mixer_elem_resume_func_t resume; + usb_mixer_elem_resume_func_t reset_resume; }; /* iterate over mixer element list of the given unit id */ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 5b77e8140ba6..e64cd4b11fc6 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -151,7 +151,7 @@ static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer, *listp = list; list->mixer = mixer; list->id = id; - list->resume = resume; + list->reset_resume = resume; kctl = snd_ctl_new1(knew, list); if (!kctl) { kfree(list); -- cgit v1.2.3-58-ga151 From 583770e84a44c4e4ea206546ea07cc534fcd6d58 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Fri, 26 Mar 2021 12:12:11 +0530 Subject: ALSA: pcm: Fix couple of typos s/unconditonally/unconditionally/ s/succesful/successful/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210326064211.6509-1-unixbhaskar@gmail.com Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 17a85f4815d5..8dbe86cf2e4f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1425,7 +1425,7 @@ static int snd_pcm_do_stop(struct snd_pcm_substream *substream, substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); substream->runtime->stop_operating = true; } - return 0; /* unconditonally stop all substreams */ + return 0; /* unconditionally stop all substreams */ } static void snd_pcm_post_stop(struct snd_pcm_substream *substream, @@ -1469,7 +1469,7 @@ EXPORT_SYMBOL(snd_pcm_stop); * After stopping, the state is changed to SETUP. * Unlike snd_pcm_stop(), this affects only the given stream. * - * Return: Zero if succesful, or a negative error code. + * Return: Zero if successful, or a negative error code. */ int snd_pcm_drain_done(struct snd_pcm_substream *substream) { -- cgit v1.2.3-58-ga151 From 625bd5a616ceda4840cd28f82e957c8ced394b6a Mon Sep 17 00:00:00 2001 From: Ikjoon Jang Date: Wed, 24 Mar 2021 18:51:52 +0800 Subject: ALSA: usb-audio: Apply sample rate quirk to Logitech Connect Logitech ConferenceCam Connect is a compound USB device with UVC and UAC. Not 100% reproducible but sometimes it keeps responding STALL to every control transfer once it receives get_freq request. This patch adds 046d:0x084c to a snd_usb_get_sample_rate_quirk list. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203419 Signed-off-by: Ikjoon Jang Cc: Link: https://lore.kernel.org/r/20210324105153.2322881-1-ikjn@chromium.org Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index d3001fb18141..176437a441e6 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1521,6 +1521,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */ case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */ case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */ + case USB_ID(0x046d, 0x084c): /* Logitech ConferenceCam Connect */ return true; } -- cgit v1.2.3-58-ga151 From aa320c7cd45647b75af2233430d36a8d154703d4 Mon Sep 17 00:00:00 2001 From: kernel test robot Date: Sun, 28 Mar 2021 16:54:45 +0200 Subject: ASoC: cygnus: fix for_each_child.cocci warnings Function "for_each_available_child_of_node" should have of_node_put() before return around line 1352. Generated by: scripts/coccinelle/iterators/for_each_child.cocci CC: Sumera Priyadarsini Reported-by: kernel test robot Signed-off-by: kernel test robot Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/alpine.DEB.2.22.394.2103281651320.2854@hadrien Signed-off-by: Mark Brown --- sound/soc/bcm/cygnus-ssp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 6e634b448293..aa16a2375134 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1348,8 +1348,10 @@ static int cygnus_ssp_probe(struct platform_device *pdev) &cygnus_ssp_dai[active_port_count]); /* negative is err, 0 is active and good, 1 is disabled */ - if (err < 0) + if (err < 0) { + of_node_put(child_node); return err; + } else if (!err) { dev_dbg(dev, "Activating DAI: %s\n", cygnus_ssp_dai[active_port_count].name); -- cgit v1.2.3-58-ga151 From c8f79808cd8eb5bc8d14de129bd6d586d3fce0aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 29 Mar 2021 13:30:58 +0200 Subject: ALSA: hda: Re-add dropped snd_poewr_change_state() calls The card power state change via snd_power_change_state() at the system suspend/resume seems dropped mistakenly during the PM code rewrite. The card power state doesn't play much role nowadays but it's still referred in a few places such as the HDMI codec driver. This patch restores them, but in a more appropriate place now in the prepare and complete callbacks. Fixes: f5dac54d9d93 ("ALSA: hda: Separate runtime and system suspend") Cc: Link: https://lore.kernel.org/r/20210329113059.25035-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 5eea130dcf0a..c4146e8617de 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1025,6 +1025,7 @@ static int azx_prepare(struct device *dev) chip = card->private_data; chip->pm_prepared = 1; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); flush_work(&azx_bus(chip)->unsol_work); @@ -1040,6 +1041,7 @@ static void azx_complete(struct device *dev) struct azx *chip; chip = card->private_data; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); chip->pm_prepared = 0; } -- cgit v1.2.3-58-ga151 From 66affb7bb0dc0905155a1b2475261aa704d1ddb5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 29 Mar 2021 13:30:59 +0200 Subject: ALSA: hda: Add missing sanity checks in PM prepare/complete callbacks The recently added PM prepare and complete callbacks don't have the sanity check whether the card instance has been properly initialized, which may potentially lead to Oops. This patch adds the azx_is_pm_ready() call in each place appropriately like other PM callbacks. Fixes: f5dac54d9d93 ("ALSA: hda: Separate runtime and system suspend") Cc: Link: https://lore.kernel.org/r/20210329113059.25035-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c4146e8617de..65551eea6752 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1023,6 +1023,9 @@ static int azx_prepare(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; + if (!azx_is_pm_ready(card)) + return 0; + chip = card->private_data; chip->pm_prepared = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); @@ -1040,6 +1043,9 @@ static void azx_complete(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; + if (!azx_is_pm_ready(card)) + return; + chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D0); chip->pm_prepared = 0; -- cgit v1.2.3-58-ga151 From 417eadfdd9e25188465280edf3668ed163fda2d0 Mon Sep 17 00:00:00 2001 From: Jeremy Szu Date: Tue, 30 Mar 2021 19:44:27 +0800 Subject: ALSA: hda/realtek: fix mute/micmute LEDs for HP 640 G8 The HP EliteBook 640 G8 Notebook PC is using ALC236 codec which is using 0x02 to control mute LED and 0x01 to control micmute LED. Therefore, add a quirk to make it works. Signed-off-by: Jeremy Szu Cc: Link: https://lore.kernel.org/r/20210330114428.40490-1-jeremy.szu@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index fc2f60c58ad8..58946d069ee5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8058,6 +8058,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x87f2, "HP ProBook 640 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), -- cgit v1.2.3-58-ga151 From abc21649b3e5c34b143bf86f0c78e33d5815e250 Mon Sep 17 00:00:00 2001 From: Jia Zhou Date: Tue, 30 Mar 2021 13:19:23 +0200 Subject: ALSA: core: remove redundant spin_lock pair in snd_card_disconnect modification in commit 2a3f7221acdd ("ALSA: core: Fix card races between register and disconnect") resulting in this problem. Fixes: 2a3f7221acdd ("ALSA: core: Fix card races between register and disconnect") Signed-off-by: Jia Zhou Signed-off-by: Yi Wang Link: https://lore.kernel.org/r/1616989007-34429-1-git-send-email-wang.yi59@zte.com.cn Signed-off-by: Takashi Iwai --- sound/core/init.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/core/init.c b/sound/core/init.c index 45f4b01de23f..ef41f5b3a240 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -398,10 +398,8 @@ int snd_card_disconnect(struct snd_card *card) return 0; } card->shutdown = 1; - spin_unlock(&card->files_lock); /* replace file->f_op with special dummy operations */ - spin_lock(&card->files_lock); list_for_each_entry(mfile, &card->files_list, list) { /* it's critical part, use endless loop */ /* we have no room to fail */ -- cgit v1.2.3-58-ga151 From 7c0d6e482062eb5c06ecccfab340abc523bdca00 Mon Sep 17 00:00:00 2001 From: Bastian Germann Date: Wed, 31 Mar 2021 17:18:43 +0200 Subject: ASoC: sunxi: sun4i-codec: fill ASoC card owner card->owner is a required property and since commit 81033c6b584b ("ALSA: core: Warn on empty module") a warning is issued if it is empty. Add it. This fixes following warning observed on Lamobo R1: WARNING: CPU: 1 PID: 190 at sound/core/init.c:207 snd_card_new+0x430/0x480 [snd] Modules linked in: sun4i_codec(E+) sun4i_backend(E+) snd_soc_core(E) ... CPU: 1 PID: 190 Comm: systemd-udevd Tainted: G C E 5.10.0-1-armmp #1 Debian 5.10.4-1 Hardware name: Allwinner sun7i (A20) Family Call trace: (snd_card_new [snd]) (snd_soc_bind_card [snd_soc_core]) (snd_soc_register_card [snd_soc_core]) (sun4i_codec_probe [sun4i_codec]) Fixes: 45fb6b6f2aa3 ("ASoC: sunxi: add support for the on-chip codec on early Allwinner SoCs") Related: commit 3c27ea23ffb4 ("ASoC: qcom: Set card->owner to avoid warnings") Related: commit ec653df2a0cb ("drm/vc4/vc4_hdmi: fill ASoC card owner") Cc: linux-arm-kernel@lists.infradead.org Cc: alsa-devel@alsa-project.org Signed-off-by: Bastian Germann Link: https://lore.kernel.org/r/20210331151843.30583-1-bage@linutronix.de Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 6c13cc84b3fb..2173991c13db 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1364,6 +1364,7 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) return ERR_PTR(-ENOMEM); card->dev = dev; + card->owner = THIS_MODULE; card->name = "sun4i-codec"; card->dapm_widgets = sun4i_codec_card_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(sun4i_codec_card_dapm_widgets); @@ -1396,6 +1397,7 @@ static struct snd_soc_card *sun6i_codec_create_card(struct device *dev) return ERR_PTR(-ENOMEM); card->dev = dev; + card->owner = THIS_MODULE; card->name = "A31 Audio Codec"; card->dapm_widgets = sun6i_codec_card_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); @@ -1449,6 +1451,7 @@ static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) return ERR_PTR(-ENOMEM); card->dev = dev; + card->owner = THIS_MODULE; card->name = "A23 Audio Codec"; card->dapm_widgets = sun6i_codec_card_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); @@ -1487,6 +1490,7 @@ static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) return ERR_PTR(-ENOMEM); card->dev = dev; + card->owner = THIS_MODULE; card->name = "H3 Audio Codec"; card->dapm_widgets = sun6i_codec_card_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); @@ -1525,6 +1529,7 @@ static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev) return ERR_PTR(-ENOMEM); card->dev = dev; + card->owner = THIS_MODULE; card->name = "V3s Audio Codec"; card->dapm_widgets = sun6i_codec_card_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); -- cgit v1.2.3-58-ga151 From 016c20506d5c30151196ab28c694ab10bc3604e6 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 31 Mar 2021 20:07:02 +0200 Subject: ALSA: control - add the missing prev_lops2 initialization As static analysis reported, the prev_lops2 should contain the previous lops2 pointer in snd_ctl_disconnect_layer(). Link: https://lore.kernel.org/alsa-devel/96e9bd5c-c8db-0db8-b393-fbf4a047dc80@canonical.com/ Fixes: 3f0638a0333b ("ALSA: control - add layer registration routines") Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210331180702.663489-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/control.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 6825ca75daf5..20d707d4ef40 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -2074,7 +2074,7 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops) struct snd_ctl_layer_ops *lops2, *prev_lops2; down_write(&snd_ctl_layer_rwsem); - for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) + for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) { if (lops2 == lops) { if (!prev_lops2) snd_ctl_layer = lops->next; @@ -2082,6 +2082,8 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops) prev_lops2->next = lops->next; break; } + prev_lops2 = lops2; + } up_write(&snd_ctl_layer_rwsem); } EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer); -- cgit v1.2.3-58-ga151 From 62327ebbdf0097cda25579522424b350c65422a4 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 31 Mar 2021 20:07:25 +0200 Subject: ALSA: control led - improve the set_led_id() parser It may be possible that the string pointer does not move when parsing. Add a code which detects this state and simply break the parser loop in this case. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210331180725.663623-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control_led.c b/sound/core/control_led.c index d4fb8b873f34..788fd9e275e0 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -506,7 +506,7 @@ static char *parse_iface(char *s, unsigned int *val) static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, size_t count, bool attach) { - char buf2[256], *s; + char buf2[256], *s, *os; size_t len = max(sizeof(s) - 1, count); struct snd_ctl_elem_id id; int err; @@ -517,6 +517,7 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; s = buf2; while (*s) { + os = s; if (!strncasecmp(s, "numid=", 6)) { s = parse_uint(s + 6, &id.numid); } else if (!strncasecmp(s, "iface=", 6)) { @@ -546,6 +547,8 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si } if (*s == ',') s++; + if (s == os) + break; } err = snd_ctl_led_set_id(led_card->number, &id, led_card->led->group, attach); -- cgit v1.2.3-58-ga151 From b861106f3cd693f944ba46d9ea8744a3fbfd14db Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 31 Mar 2021 18:12:34 +0100 Subject: ASoC: codecs: lpass-tx-macro: set npl clock rate correctly NPL clock rate is twice the MCLK rate, so set this correctly to avoid soundwire timeouts. Fixes: c39667ddcfc5 ("ASoC: codecs: lpass-tx-macro: add support for lpass tx macro") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210331171235.24824-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-tx-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 36d7a6442cdb..e8c6c738bbaa 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1811,7 +1811,7 @@ static int tx_macro_probe(struct platform_device *pdev) /* set MCLK and NPL rates */ clk_set_rate(tx->clks[2].clk, MCLK_FREQ); - clk_set_rate(tx->clks[3].clk, MCLK_FREQ); + clk_set_rate(tx->clks[3].clk, 2 * MCLK_FREQ); ret = clk_bulk_prepare_enable(TX_NUM_CLKS_MAX, tx->clks); if (ret) -- cgit v1.2.3-58-ga151 From adfc3ed7dcb98f7411d3632e3bdf81690294fe7d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 31 Mar 2021 18:12:35 +0100 Subject: ASoC: codecs: lpass-rx-macro: set npl clock rate correctly NPL clock rate is twice the MCLK rate, so set this correctly to avoid soundwire timeouts. Fixes: af3d54b99764 ("ASoC: codecs: lpass-rx-macro: add support for lpass rx macro") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210331171235.24824-2-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 8c04b3b2c907..7878da89d8e0 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3551,7 +3551,7 @@ static int rx_macro_probe(struct platform_device *pdev) /* set MCLK and NPL rates */ clk_set_rate(rx->clks[2].clk, MCLK_FREQ); - clk_set_rate(rx->clks[3].clk, MCLK_FREQ); + clk_set_rate(rx->clks[3].clk, 2 * MCLK_FREQ); ret = clk_bulk_prepare_enable(RX_NUM_CLKS_MAX, rx->clks); if (ret) -- cgit v1.2.3-58-ga151 From e7a48c710defa0e0fef54d42b7d9e4ab596e2761 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 2 Apr 2021 11:14:05 +0300 Subject: ASoC: fsl_esai: Fix TDM slot setup for I2S mode When using the driver in I2S TDM mode, the fsl_esai_startup() function rewrites the number of slots previously set by the fsl_esai_set_dai_tdm_slot() function to 2. To fix this, let's use the saved slot count value or, if TDM is not used and the number of slots is not set, the driver will use the default value (2), which is set by fsl_esai_probe(). Signed-off-by: Alexander Shiyan Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20210402081405.9892-1-shc_work@mail.ru Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 08056fa0a0fa..a857a624864f 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -519,11 +519,13 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, ESAI_SAICR_SYNC, esai_priv->synchronous ? ESAI_SAICR_SYNC : 0); - /* Set a default slot number -- 2 */ + /* Set slots count */ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, - ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2)); + ESAI_xCCR_xDC_MASK, + ESAI_xCCR_xDC(esai_priv->slots)); regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, - ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2)); + ESAI_xCCR_xDC_MASK, + ESAI_xCCR_xDC(esai_priv->slots)); } return 0; -- cgit v1.2.3-58-ga151 From 53cc2643c1498779c86ee8e038273c2b2d9c8126 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 2 Apr 2021 14:42:50 +0300 Subject: ALSA: control - off by one in store_mode() If count is 16 then this will put the NUL terminator one element beyond the end of the array. Fixes: cb17fe0045aa ("ALSA: control - add sysfs support to the LED trigger module") Signed-off-by: Dan Carpenter Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/YGcDOtrimR46vr0k@mwanda Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 788fd9e275e0..d756a52e58db 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -391,7 +391,7 @@ static ssize_t store_mode(struct device *dev, struct device_attribute *attr, { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); char _buf[16]; - size_t l = min(count, sizeof(_buf) - 1) + 1; + size_t l = min(count, sizeof(_buf) - 1); enum snd_ctl_led_mode mode; memcpy(_buf, buf, l); -- cgit v1.2.3-58-ga151 From c6423ed2da6214a68527446b5f8e09cf7162b2ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Apr 2021 19:13:14 +0200 Subject: ALSA: hda/conexant: Apply quirk for another HP ZBook G5 model There is another HP ZBook G5 model with the PCI SSID 103c:844f that requires the same quirk for controlling the mute LED. Add the corresponding entry to the quirk table. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212407 Cc: Link: https://lore.kernel.org/r/20210401171314.667-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c20dad46a7c9..dfef9c17e140 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -944,6 +944,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE), -- cgit v1.2.3-58-ga151 From 29654ed8384e9dbaf4cfba689dbcb664a6ab4bb7 Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Wed, 31 Mar 2021 18:21:45 +0000 Subject: ASoC: tlv320aic32x4: Increase maximum register in regmap AIC32X4_REFPOWERUP was added as a register, but the maximum register value in the regmap and regmap range was not correspondingly increased. This caused an error when this register was attempted to be written. Fixes: ec96690de82c ("ASoC: tlv320aic32x4: Enable fast charge") Cc: stable@vger.kernel.org Signed-off-by: Annaliese McDermond Link: https://lore.kernel.org/r/0101017889851cab-ce60cfdb-d88c-43d8-bbd2-7fbf34a0c912-000000@us-west-2.amazonses.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index f04f88c8d425..1ac3b3b12dc6 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -577,12 +577,12 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = { .window_start = 0, .window_len = 128, .range_min = 0, - .range_max = AIC32X4_RMICPGAVOL, + .range_max = AIC32X4_REFPOWERUP, }, }; const struct regmap_config aic32x4_regmap_config = { - .max_register = AIC32X4_RMICPGAVOL, + .max_register = AIC32X4_REFPOWERUP, .ranges = aic32x4_regmap_pages, .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), }; -- cgit v1.2.3-58-ga151 From 1ca1156cfd69530e6b7cb99943baf90c8bd871a5 Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Wed, 31 Mar 2021 18:21:38 +0000 Subject: ASoC: tlv320aic32x4: Register clocks before registering component Clock registration must be performed before the component is registered. aic32x4_component_probe attempts to get all the clocks right off the bat. If the component is registered before the clocks there is a race condition where the clocks may not be registered by the time aic32x4_componet_probe actually runs. Fixes: d1c859d314d8 ("ASoC: codec: tlv3204: Increased maximum supported channels") Cc: stable@vger.kernel.org Signed-off-by: Annaliese McDermond Link: https://lore.kernel.org/r/0101017889850206-dcac4cce-8cc8-4a21-80e9-4e4bef44b981-000000@us-west-2.amazonses.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 1ac3b3b12dc6..b689f26fc4be 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1243,6 +1243,10 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) if (ret) goto err_disable_regulators; + ret = aic32x4_register_clocks(dev, aic32x4->mclk_name); + if (ret) + goto err_disable_regulators; + ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic32x4, &aic32x4_dai, 1); if (ret) { @@ -1250,10 +1254,6 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) goto err_disable_regulators; } - ret = aic32x4_register_clocks(dev, aic32x4->mclk_name); - if (ret) - goto err_disable_regulators; - return 0; err_disable_regulators: -- cgit v1.2.3-58-ga151 From 168632a495f49f33a18c2d502fc249d7610375e9 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Wed, 7 Apr 2021 09:54:28 +0200 Subject: ALSA: aloop: Fix initialization of controls Add a control to the card before copying the id so that the numid field is initialized in the copy. Otherwise the numid field of active_id, format_id, rate_id and channels_id will be the same (0) and snd_ctl_notify() will not queue the events properly. Signed-off-by: Jonas Holmberg Reviewed-by: Jaroslav Kysela Cc: Link: https://lore.kernel.org/r/20210407075428.2666787-1-jonashg@axis.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 8a24e5ae7cef..ef0cdfddfd3f 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -1572,6 +1572,14 @@ static int loopback_mixer_new(struct loopback *loopback, int notify) return -ENOMEM; kctl->id.device = dev; kctl->id.subdevice = substr; + + /* Add the control before copying the id so that + * the numid field of the id is set in the copy. + */ + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + switch (idx) { case ACTIVE_IDX: setup->active_id = kctl->id; @@ -1588,9 +1596,6 @@ static int loopback_mixer_new(struct loopback *loopback, int notify) default: break; } - err = snd_ctl_add(card, kctl); - if (err < 0) - return err; } } } -- cgit v1.2.3-58-ga151 From 5fb45414ae03421255593fd5556aa2d1d82303aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 6 Apr 2021 13:35:34 +0200 Subject: ALSA: usb-audio: Add error checks for usb_driver_claim_interface() calls There are a few calls of usb_driver_claim_interface() but all of those miss the proper error checks, as reported by Coverity. This patch adds those missing checks. Along with it, replace the magic pointer with -1 with a constant USB_AUDIO_IFACE_UNUSED for better readability. Reported-by: coverity-bot Addresses-Coverity-ID: 1475943 ("Error handling issues") Addresses-Coverity-ID: 1475944 ("Error handling issues") Addresses-Coverity-ID: 1475945 ("Error handling issues") Fixes: b1ce7ba619d9 ("ALSA: usb-audio: claim autodetected PCM interfaces all at once") Fixes: e5779998bf8b ("ALSA: usb-audio: refactor code") Link: https://lore.kernel.org/r/202104051059.FB7F3016@keescook Link: https://lore.kernel.org/r/20210406113534.30455-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 14 +++++++------- sound/usb/quirks.c | 16 ++++++++++++---- sound/usb/usbaudio.h | 2 ++ 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 0826a437f8fc..7b7526d3a56e 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -181,9 +181,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int ctrlif, interface); return -EINVAL; } - usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); - - return 0; + return usb_driver_claim_interface(&usb_audio_driver, iface, + USB_AUDIO_IFACE_UNUSED); } if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && @@ -203,7 +202,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int if (! snd_usb_parse_audio_interface(chip, interface)) { usb_set_interface(dev, interface, 0); /* reset the current interface */ - usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); + return usb_driver_claim_interface(&usb_audio_driver, iface, + USB_AUDIO_IFACE_UNUSED); } return 0; @@ -862,7 +862,7 @@ static void usb_audio_disconnect(struct usb_interface *intf) struct snd_card *card; struct list_head *p; - if (chip == (void *)-1L) + if (chip == USB_AUDIO_IFACE_UNUSED) return; card = chip->card; @@ -992,7 +992,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) struct usb_mixer_interface *mixer; struct list_head *p; - if (chip == (void *)-1L) + if (chip == USB_AUDIO_IFACE_UNUSED) return 0; if (!chip->num_suspended_intf++) { @@ -1022,7 +1022,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) struct list_head *p; int err = 0; - if (chip == (void *)-1L) + if (chip == USB_AUDIO_IFACE_UNUSED) return 0; atomic_inc(&chip->active); /* avoid autopm */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 9e5e37eff10e..232fbc0d37bd 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -55,8 +55,12 @@ static int create_composite_quirk(struct snd_usb_audio *chip, if (!iface) continue; if (quirk->ifnum != probed_ifnum && - !usb_interface_claimed(iface)) - usb_driver_claim_interface(driver, iface, (void *)-1L); + !usb_interface_claimed(iface)) { + err = usb_driver_claim_interface(driver, iface, + USB_AUDIO_IFACE_UNUSED); + if (err < 0) + return err; + } } return 0; @@ -426,8 +430,12 @@ static int create_autodetect_quirks(struct snd_usb_audio *chip, continue; err = create_autodetect_quirk(chip, iface, driver); - if (err >= 0) - usb_driver_claim_interface(driver, iface, (void *)-1L); + if (err >= 0) { + err = usb_driver_claim_interface(driver, iface, + USB_AUDIO_IFACE_UNUSED); + if (err < 0) + return err; + } } return 0; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 60b9dd7df6bb..8794c8658ab9 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -61,6 +61,8 @@ struct snd_usb_audio { struct media_intf_devnode *ctl_intf_media_devnode; }; +#define USB_AUDIO_IFACE_UNUSED ((void *)-1L) + #define usb_audio_err(chip, fmt, args...) \ dev_err(&(chip)->dev->dev, fmt, ##args) #define usb_audio_warn(chip, fmt, args...) \ -- cgit v1.2.3-58-ga151 From 884c7094a272fb674423bd5a473caa3c714045fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 6 Apr 2021 13:38:37 +0200 Subject: ALSA: usb-audio: Drop implicit fb quirk entries dubbed for capture The implicit feedback quirk table contains the entries that also appear in the capture quirks, and those are all handled to be skipped. For the code simplicity, drop the duped entries in the playback quirk table, and check the match with the capture quirk table instead. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212519 Link: https://lore.kernel.org/r/20210406113837.32041-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 11a85e66aa96..19622c58b72b 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -70,16 +70,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { .type = IMPLICIT_FB_FIXED, .ep_num = 0x84, .iface = 0 }, /* MOTU MicroBook II */ - /* No quirk for playback but with capture quirk (see below) */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0130), /* BOSS BR-80 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0171), /* BOSS RC-505 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0185), /* BOSS GP-10 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0189), /* BOSS GT-100v2 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d6), /* BOSS GT-1 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8), /* BOSS Katana */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x01e5), /* BOSS GT-001 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0203), /* BOSS AD-10 */ - {} /* terminator */ }; @@ -278,6 +268,11 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, } } + /* Don't apply playback quirks for the devices with capture quirk */ + p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); + if (p && p->type == IMPLICIT_FB_FIXED) + return 0; /* no quirk */ + /* Generic UAC2 implicit feedback */ if (attr == USB_ENDPOINT_SYNC_ASYNC && alts->desc.bInterfaceClass == USB_CLASS_AUDIO && -- cgit v1.2.3-58-ga151 From 6f68accaa8641b70b698da659216f82f87537869 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 7 Apr 2021 16:57:14 +0200 Subject: ASoC: meson: axg-frddr: set fifo depth according to the period When the period is small, using all the FRDDR fifo depth increases the latency of the playback because the following device won't start pulling data until the fifo reaches the depth set. We can adjust this depth so trim it down for small periods. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210407145714.311138-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-frddr.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index c3ae8ac30745..8ed114de0bdf 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -46,11 +47,28 @@ static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream, return 0; } +static int axg_frddr_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); + unsigned int period, depth, val; + + period = params_period_bytes(params); + + /* Trim the FIFO depth if the period is small to improve latency */ + depth = min(period, fifo->depth); + val = (depth / AXG_FIFO_BURST) - 1; + regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK, + CTRL1_FRDDR_DEPTH(val)); + + return 0; +} + static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); - unsigned int val; int ret; /* Enable pclk to access registers and clock the fifo ip */ @@ -61,11 +79,6 @@ static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, /* Apply single buffer mode to the interface */ regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0); - /* Use all fifo depth */ - val = (fifo->depth / AXG_FIFO_BURST) - 1; - regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK, - CTRL1_FRDDR_DEPTH(val)); - return 0; } @@ -84,6 +97,7 @@ static int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd, } static const struct snd_soc_dai_ops axg_frddr_ops = { + .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, }; -- cgit v1.2.3-58-ga151 From c8426b2700b57d2760ff335840a02f66a64b6044 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Apr 2021 11:57:30 +0200 Subject: ALSA: hda/realtek: Fix speaker amp setup on Acer Aspire E1 We've got a report about Acer Aspire E1 (PCI SSID 1025:0840) that loses the speaker output after resume. With the comparison of COEF dumps, it was identified that the COEF 0x0d bits 0x6000 corresponds to the speaker amp. This patch adds the specific quirk for the device to restore the COEF bits at the codec (re-)initialization. BugLink: https://bugzilla.suse.com/show_bug.cgi?id=1183869 Cc: Link: https://lore.kernel.org/r/20210407095730.12560-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 58946d069ee5..a7544b77d3f7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3927,6 +3927,15 @@ static void alc271_fixup_dmic(struct hda_codec *codec, snd_hda_sequence_write(codec, verbs); } +/* Fix the speaker amp after resume, etc */ +static void alc269vb_fixup_aspire_e1_coef(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + if (action == HDA_FIXUP_ACT_INIT) + alc_update_coef_idx(codec, 0x0d, 0x6000, 0x6000); +} + static void alc269_fixup_pcm_44k(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -6301,6 +6310,7 @@ enum { ALC283_FIXUP_HEADSET_MIC, ALC255_FIXUP_MIC_MUTE_LED, ALC282_FIXUP_ASPIRE_V5_PINS, + ALC269VB_FIXUP_ASPIRE_E1_COEF, ALC280_FIXUP_HP_GPIO4, ALC286_FIXUP_HP_GPIO_LED, ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, @@ -6979,6 +6989,10 @@ static const struct hda_fixup alc269_fixups[] = { { }, }, }, + [ALC269VB_FIXUP_ASPIRE_E1_COEF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269vb_fixup_aspire_e1_coef, + }, [ALC280_FIXUP_HP_GPIO4] = { .type = HDA_FIXUP_FUNC, .v.func = alc280_fixup_hp_gpio4, @@ -7901,6 +7915,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), + SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF), SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC), @@ -8395,6 +8410,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"}, {.id = ALC255_FIXUP_MIC_MUTE_LED, .name = "alc255-dell-mute"}, {.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"}, + {.id = ALC269VB_FIXUP_ASPIRE_E1_COEF, .name = "aspire-e1-coef"}, {.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"}, {.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"}, {.id = ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, .name = "hp-gpio2-hotkey"}, -- cgit v1.2.3-58-ga151 From 66c6d1ef86ff3c1466e646d94c8eb3dcc9ccf873 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 8 Apr 2021 19:31:49 +0900 Subject: ALSA: control: Add memory consumption limit to user controls ALSA control interface allows users to add arbitrary control elements (called "user controls" or "user elements"), and its resource usage is limited just by the max number of control sets (currently 32). This limit, however, is quite loose: each allocation of control set may have 1028 elements, and each element may have up to 512 bytes (ILP32) or 1024 bytes (LP64) of value data. Moreover, each control set may contain the enum strings and TLV data, which can be up to 64kB and 128kB, respectively. Totally, the whole memory consumption may go over 38MB -- it's quite large, and we'd rather like to reduce the size. OTOH, there have been other requests even to increase the max number of user elements; e.g. ALSA firewire stack require the more user controls, hence we want to raise the bar, too. For satisfying both requirements, this patch changes the management of user controls: instead of setting the upper limit of the number of user controls, we check the actual memory allocation size and set the upper limit of the total allocation in bytes. As long as the memory consumption stays below the limit, more user controls are allowed than the current limit 32. At the same time, we set the lower limit (8MB) as default than the current theoretical limit, in order to lower the risk of DoS. As a compromise for lowering the default limit, now the actual memory limit is defined as a module option, 'max_user_ctl_alloc_size', so that user can increase/decrease the limit if really needed, too. Link: https://lore.kernel.org/r/s5htur3zl5e.wl-tiwai@suse.de Co-developed-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210408103149.40357-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- include/sound/core.h | 2 +- sound/core/control.c | 75 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 52 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/include/sound/core.h b/include/sound/core.h index 2e24f194ef70..1f9aef0adbc9 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -100,7 +100,7 @@ struct snd_card { struct rw_semaphore controls_rwsem; /* controls list lock */ rwlock_t ctl_files_rwlock; /* ctl_files list lock */ int controls_count; /* count of all controls */ - int user_ctl_count; /* count of all user controls */ + size_t user_ctl_alloc_size; // current memory allocation by user controls. struct list_head controls; /* all controls for this card */ struct list_head ctl_files; /* active control files */ diff --git a/sound/core/control.c b/sound/core/control.c index 20d707d4ef40..a076c08c21b6 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -18,8 +19,11 @@ #include #include -/* max number of user-defined controls */ -#define MAX_USER_CONTROLS 32 +// Max allocation size for user controls. +static int max_user_ctl_alloc_size = 8 * 1024 * 1024; +module_param_named(max_user_ctl_alloc_size, max_user_ctl_alloc_size, int, 0444); +MODULE_PARM_DESC(max_user_ctl_alloc_size, "Max allocation size for user controls"); + #define MAX_CONTROL_COUNT 1028 struct snd_kctl_ioctl { @@ -561,9 +565,6 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, goto error; } ret = snd_ctl_remove(card, kctl); - if (ret < 0) - goto error; - card->user_ctl_count--; error: up_write(&card->controls_rwsem); return ret; @@ -1265,6 +1266,12 @@ struct user_element { void *priv_data; /* private data (like strings for enumerated type) */ }; +// check whether the addition (in bytes) of user ctl element may overflow the limit. +static bool check_user_elem_overflow(struct snd_card *card, ssize_t add) +{ + return (ssize_t)card->user_ctl_alloc_size + add > max_user_ctl_alloc_size; +} + static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1342,6 +1349,10 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, if (size > 1024 * 128) /* sane value */ return -EINVAL; + // does the TLV size change cause overflow? + if (check_user_elem_overflow(ue->card, (ssize_t)(size - ue->tlv_data_size))) + return -ENOMEM; + container = vmemdup_user(buf, size); if (IS_ERR(container)) return PTR_ERR(container); @@ -1359,11 +1370,16 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, for (i = 0; i < kctl->count; ++i) kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; mask = SNDRV_CTL_EVENT_MASK_INFO; + } else { + ue->card->user_ctl_alloc_size -= ue->tlv_data_size; + ue->tlv_data_size = 0; + kvfree(ue->tlv_data); } - kvfree(ue->tlv_data); ue->tlv_data = container; ue->tlv_data_size = size; + // decremented at private_free. + ue->card->user_ctl_alloc_size += size; mask |= SNDRV_CTL_EVENT_MASK_TLV; for (i = 0; i < kctl->count; ++i) @@ -1405,16 +1421,17 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) unsigned int i; const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr; - if (ue->info.value.enumerated.names_length > 64 * 1024) + buf_len = ue->info.value.enumerated.names_length; + if (buf_len > 64 * 1024) return -EINVAL; - names = vmemdup_user((const void __user *)user_ptrval, - ue->info.value.enumerated.names_length); + if (check_user_elem_overflow(ue->card, buf_len)) + return -ENOMEM; + names = vmemdup_user((const void __user *)user_ptrval, buf_len); if (IS_ERR(names)) return PTR_ERR(names); /* check that there are enough valid names */ - buf_len = ue->info.value.enumerated.names_length; p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { name_len = strnlen(p, buf_len); @@ -1428,14 +1445,27 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) ue->priv_data = names; ue->info.value.enumerated.names_ptr = 0; + // increment the allocation size; decremented again at private_free. + ue->card->user_ctl_alloc_size += ue->info.value.enumerated.names_length; return 0; } +static size_t compute_user_elem_size(size_t size, unsigned int count) +{ + return sizeof(struct user_element) + size * count; +} + static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) { struct user_element *ue = kcontrol->private_data; + // decrement the allocation size. + ue->card->user_ctl_alloc_size -= compute_user_elem_size(ue->elem_data_size, kcontrol->count); + ue->card->user_ctl_alloc_size -= ue->tlv_data_size; + if (ue->priv_data) + ue->card->user_ctl_alloc_size -= ue->info.value.enumerated.names_length; + kvfree(ue->tlv_data); kvfree(ue->priv_data); kfree(ue); @@ -1449,6 +1479,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, unsigned int count; unsigned int access; long private_size; + size_t alloc_size; struct user_element *ue; unsigned int offset; int err; @@ -1466,13 +1497,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, return err; } - /* - * The number of userspace controls are counted control by control, - * not element by element. - */ - if (card->user_ctl_count + 1 > MAX_USER_CONTROLS) - return -ENOMEM; - /* Check the number of elements for this userspace control. */ count = info->owner; if (count == 0) @@ -1503,6 +1527,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (info->count < 1) return -EINVAL; private_size = value_sizes[info->type] * info->count; + alloc_size = compute_user_elem_size(private_size, count); + + if (check_user_elem_overflow(card, alloc_size)) + return -ENOMEM; /* * Keep memory object for this userspace control. After passing this @@ -1514,16 +1542,18 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (err < 0) return err; memcpy(&kctl->id, &info->id, sizeof(kctl->id)); - kctl->private_data = kzalloc(sizeof(struct user_element) + private_size * count, - GFP_KERNEL); - if (kctl->private_data == NULL) { + ue = kzalloc(alloc_size, GFP_KERNEL); + if (!ue) { kfree(kctl); return -ENOMEM; } + kctl->private_data = ue; kctl->private_free = snd_ctl_elem_user_free; + // increment the allocated size; decremented again at private_free. + card->user_ctl_alloc_size += alloc_size; + /* Set private data for this userspace control. */ - ue = (struct user_element *)kctl->private_data; ue->card = card; ue->info = *info; ue->info.access = 0; @@ -1565,9 +1595,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, * applications because the field originally means PID of a process * which locks the element. */ - - card->user_ctl_count++; - unlock: up_write(&card->controls_rwsem); return err; -- cgit v1.2.3-58-ga151 From 44de8d80dba4e65f4fe7c17ea4be75e3cf9a902c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 8 Apr 2021 08:32:40 +0000 Subject: ASoC: rt1011: remove pack_id check in rt1011 For latest design, different package could use the same setting, therefore the check of pack_id will no longer be used. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/4cbe1cd3b8664140889132464c7dee7b@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 16 ++-------------- sound/soc/codecs/rt1011.h | 1 - 2 files changed, 2 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 098ecf13814d..bfe045367db3 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2239,18 +2239,9 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag) dc_offset |= (value & 0xffff); dev_info(dev, "Gain1 offset=0x%x\n", dc_offset); - /* check the package info. */ - regmap_read(rt1011->regmap, RT1011_EFUSE_MATCH_DONE, &value); - if (value & 0x4) - rt1011->pack_id = 1; - if (cali_flag) { - if (rt1011->pack_id) - regmap_write(rt1011->regmap, RT1011_ADC_SET_1, 0x292c); - else - regmap_write(rt1011->regmap, RT1011_ADC_SET_1, 0x2925); - + regmap_write(rt1011->regmap, RT1011_ADC_SET_1, 0x2925); /* Class D on */ regmap_write(rt1011->regmap, RT1011_CLASS_D_POS, 0x010e); regmap_write(rt1011->regmap, @@ -2376,10 +2367,7 @@ static void rt1011_calibration_work(struct work_struct *work) rt1011_r0_load(rt1011); } - if (rt1011->pack_id) - snd_soc_component_write(component, RT1011_ADC_SET_1, 0x292c); - else - snd_soc_component_write(component, RT1011_ADC_SET_1, 0x2925); + snd_soc_component_write(component, RT1011_ADC_SET_1, 0x2925); } static int rt1011_parse_dp(struct rt1011_priv *rt1011, struct device *dev) diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index f3a9a96640f1..68fadc15fa8c 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -692,7 +692,6 @@ struct rt1011_priv { unsigned int r0_reg, cali_done; unsigned int r0_calib, temperature_calib; int recv_spk_mode; - unsigned int pack_id; /* 0: WLCSP; 1: QFN */ }; #endif /* end of _RT1011_H_ */ -- cgit v1.2.3-58-ga151 From 7b3f5b207da5116add56c335c5fb92cee140dc63 Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Thu, 8 Apr 2021 14:40:34 +0800 Subject: ASoC: codecs: Fix runtime PM imbalance in tas2552_probe There is a rumtime PM imbalance between the error handling path after devm_snd_soc_register_component() and all other error handling paths. Add a PM runtime increment to balance refcount. Signed-off-by: Dinghao Liu Link: https://lore.kernel.org/r/20210408064036.6691-1-dinghao.liu@zju.edu.cn Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index bd00c35116cd..700baa6314aa 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -730,8 +730,10 @@ static int tas2552_probe(struct i2c_client *client, ret = devm_snd_soc_register_component(&client->dev, &soc_component_dev_tas2552, tas2552_dai, ARRAY_SIZE(tas2552_dai)); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "Failed to register component: %d\n", ret); + pm_runtime_get_noresume(&client->dev); + } return ret; } -- cgit v1.2.3-58-ga151 From d763145312582c08c4e9ed99d61276cde8488256 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Apr 2021 09:56:56 +0200 Subject: ALSA: usb-audio: Skip probe of UA-101 devices UA-101 device and co are supported by another driver, snd-ua101, but the USB audio class driver (snd-usb-audio) catches all and this resulted in the lack of functionality like missing MIDI devices. This patch introduces a sort of deny-listing for those devices to just return -ENODEV at probe in snd-usb-audio driver, so that it falls back to the probe by snd-ua101. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212477 Link: https://lore.kernel.org/r/20210408075656.30184-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 2 ++ sound/usb/quirks-table.h | 21 +++++++++++++++++++++ sound/usb/usbaudio.h | 1 + 3 files changed, 24 insertions(+) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 7b7526d3a56e..2f6a62416c05 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -713,6 +713,8 @@ static int usb_audio_probe(struct usb_interface *intf, quirk = get_alias_quirk(dev, id); if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) return -ENXIO; + if (quirk && quirk->ifnum == QUIRK_NODEV_INTERFACE) + return -ENODEV; err = snd_usb_apply_boot_quirk(dev, intf, quirk, id); if (err < 0) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 9716a9f7c095..92f525b1c992 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1674,6 +1674,27 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, + +/* UA101 and co are supported by another driver */ +{ + USB_DEVICE(0x0582, 0x0044), /* UA-1000 high speed */ + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_NODEV_INTERFACE + }, +}, +{ + USB_DEVICE(0x0582, 0x007d), /* UA-101 high speed */ + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_NODEV_INTERFACE + }, +}, +{ + USB_DEVICE(0x0582, 0x008d), /* UA-101 full speed */ + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_NODEV_INTERFACE + }, +}, + /* this catches most recent vendor-specific Roland devices */ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 8794c8658ab9..a536ee33d36e 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -77,6 +77,7 @@ struct snd_usb_audio { */ /* special values for .ifnum */ +#define QUIRK_NODEV_INTERFACE -3 /* return -ENODEV */ #define QUIRK_NO_INTERFACE -2 #define QUIRK_ANY_INTERFACE -1 -- cgit v1.2.3-58-ga151 From 64f40f9be14106e7df0098c427cb60be645bddb7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Apr 2021 16:45:49 +0200 Subject: ALSA: usb-audio: Add MIDI quirk for Vox ToneLab EX ToneLab EX guitar pedal device requires the same quirk like ToneLab ST for supporting the MIDI. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212593 Cc: Link: https://lore.kernel.org/r/20210407144549.1530-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 92f525b1c992..bdba37d0faab 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2397,6 +2397,16 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0204), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "KORG, Inc.", + /* .product_name = "ToneLab EX", */ + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE, + } +}, + /* AKAI devices */ { USB_DEVICE(0x09e8, 0x0062), -- cgit v1.2.3-58-ga151 From 57b138dde3504b79358cd0d95d989bf5eba8280b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 9 Apr 2021 15:34:41 +0300 Subject: ALSA: control - double free in snd_ctl_led_init() "group - 1" was intended here instead of "group". The current error handling will double free the first item in the array and leak the last item. Fixes: cb17fe0045aa ("ALSA: control - add sysfs support to the LED trigger module") Signed-off-by: Dan Carpenter Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/YHBJ4frGxErWB182@mwanda Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control_led.c b/sound/core/control_led.c index d756a52e58db..93b201063c7d 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -734,7 +734,7 @@ static int __init snd_ctl_led_init(void) if (device_add(&led->dev)) { put_device(&led->dev); for (; group > 0; group--) { - led = &snd_ctl_leds[group]; + led = &snd_ctl_leds[group - 1]; device_del(&led->dev); } device_del(&snd_ctl_led_dev); -- cgit v1.2.3-58-ga151 From 618fad3d921a781fe500bdf8cbecbf2c4ec1f696 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 9 Apr 2021 14:46:16 -0700 Subject: ALSA: HDA: Add access description in __snd_hda_add_vmaster Add description for access parameter in __snd_hda_add_vmaster() to prevent the compilation warning: warning: Function parameter or member 'access' not described in '__snd_hda_add_vmaster' Fixes: e65bf99718b5 ("ALSA: HDA - remove the custom implementation for the audio LED trigger") Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409214616.1539685-1-ranjani.sridharan@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e54e39b35709..a31009afc025 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1938,6 +1938,7 @@ static int add_follower(struct hda_codec *codec, * @followers: follower control names (optional) * @suffix: suffix string to each follower name (optional) * @init_follower_vol: initialize followers to unmute/0dB + * @access: kcontrol access rights * @ctl_ret: store the vmaster kcontrol in return * * Create a virtual master control with the given name. The TLV data -- cgit v1.2.3-58-ga151 From d91cbe83d319e8923d36f974d8c9b1e1b56fea62 Mon Sep 17 00:00:00 2001 From: Chen Huang Date: Thu, 8 Apr 2021 12:54:29 +0000 Subject: ALSA: virtio: use module_virtio_driver() to simplify the code module_virtio_driver() makes the code simpler by eliminating boilerplate code. Signed-off-by: Chen Huang Reviewed-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210408125429.1158703-1-chenhuang5@huawei.com Signed-off-by: Takashi Iwai --- sound/virtio/virtio_card.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index ae9128063917..150ab3e37013 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -432,17 +432,7 @@ static struct virtio_driver virtsnd_driver = { #endif }; -static int __init init(void) -{ - return register_virtio_driver(&virtsnd_driver); -} -module_init(init); - -static void __exit fini(void) -{ - unregister_virtio_driver(&virtsnd_driver); -} -module_exit(fini); +module_virtio_driver(virtsnd_driver); MODULE_DEVICE_TABLE(virtio, id_table); MODULE_DESCRIPTION("Virtio sound card driver"); -- cgit v1.2.3-58-ga151 From d2e8f641257d0d3af6e45d6ac2d6f9d56b8ea964 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Apr 2021 10:41:52 +0200 Subject: ALSA: usb-audio: Explicitly set up the clock selector In the current code, we have some assumption that the audio clock selector has been set up implicitly and don't want to touch it unless it's really needed for the fallback autoclock setup. This works for most devices but some seem having a problem. Partially this was covered for the devices with a single connector at the initialization phase (commit 086b957cc17f "ALSA: usb-audio: Skip the clock selector inquiry for single connections"), but also there are cases where the wrong clock set up is kept silently. The latter seems to be the cause of the noises on Behringer devices. In this patch, we explicitly set up the audio clock selector whenever the appropriate node is found. Reported-by: Geraldo Nascimento BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199327 Link: https://lore.kernel.org/r/CAEsQvcvF7LnO8PxyyCxuRCx=7jNeSCvFAd-+dE0g_rd1rOxxdw@mail.gmail.com Cc: Link: https://lore.kernel.org/r/20210413084152.32325-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/clock.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/clock.c b/sound/usb/clock.c index a746802d0ac3..17bbde73d4d1 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -296,7 +296,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); if (selector) { - int ret, i, cur; + int ret, i, cur, err; if (selector->bNrInPins == 1) { ret = 1; @@ -324,13 +324,17 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, ret = __uac_clock_find_source(chip, fmt, selector->baCSourceID[ret - 1], visited, validate); + if (ret > 0) { + err = uac_clock_selector_set_val(chip, entity_id, cur); + if (err < 0) + return err; + } + if (!validate || ret > 0 || !chip->autoclock) return ret; /* The current clock source is invalid, try others. */ for (i = 1; i <= selector->bNrInPins; i++) { - int err; - if (i == cur) continue; @@ -396,7 +400,7 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id); if (selector) { - int ret, i, cur; + int ret, i, cur, err; /* the entity ID we are looking for is a selector. * find out what it currently selects */ @@ -418,6 +422,12 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, ret = __uac3_clock_find_source(chip, fmt, selector->baCSourceID[ret - 1], visited, validate); + if (ret > 0) { + err = uac_clock_selector_set_val(chip, entity_id, cur); + if (err < 0) + return err; + } + if (!validate || ret > 0 || !chip->autoclock) return ret; -- cgit v1.2.3-58-ga151 From 858066864a6383d1eecd2fa96a0b8e69935632f8 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Apr 2021 15:22:56 +0200 Subject: ASoC: meson: axg-frddr: fix fifo depth on g12 and sm1 Previous fifo depth patch was only tested on axg, not g12 or sm1. Of course, while adding hw_params dai callback for the axg, I forgot to do the same for g12 and sm1, leaving the depth unset and breaking playback on these SoCs. Add hw_params callback to the g12 dai_ops to fix the problem. Fixes: 6f68accaa864 ("ASoC: meson: axg-frddr: set fifo depth according to the period") Reported-by: Christian Hewitt Tested-by: Christian Hewitt Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210412132256.89920-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-frddr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 8ed114de0bdf..37f4bb3469b5 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -171,6 +171,7 @@ static const struct axg_fifo_match_data axg_frddr_match_data = { static const struct snd_soc_dai_ops g12a_frddr_ops = { .prepare = g12a_frddr_dai_prepare, + .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, }; -- cgit v1.2.3-58-ga151 From 543f8d780867bdbd8b0792487fa1644d89faa19c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 14 Apr 2021 12:58:58 +0200 Subject: ALSA: control_led - fix the stack usage (control element ops) It's a bad idea to allocate big structures on the stack. Mark the variables as static and add a note for the locking. Fixes: 22d8de62f11b ("ALSA: control - add generic LED trigger module as the new control layer") Cc: Nathan Chancellor Cc: Takashi Sakamoto Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210414105858.1937710-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 93b201063c7d..25f57c14f294 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -94,11 +94,15 @@ static struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access) return &snd_ctl_leds[group]; } +/* + * A note for callers: + * The two static variables info and value are protected using snd_ctl_led_mutex. + */ static int snd_ctl_led_get(struct snd_ctl_led_ctl *lctl) { + static struct snd_ctl_elem_info info; + static struct snd_ctl_elem_value value; struct snd_kcontrol *kctl = lctl->kctl; - struct snd_ctl_elem_info info; - struct snd_ctl_elem_value value; unsigned int i; int result; -- cgit v1.2.3-58-ga151 From ebe8dc5afb3912e2d4f5c62cf7c492a13143a77a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 14 Apr 2021 10:32:55 +0200 Subject: ALSA: usb-audio: Apply implicit feedback mode for BOSS devices During the recent rewrite of the implicit feedback support, we've tested to apply the implicit fb on BOSS devices, but it failed, as the capture stream didn't start without the playback. As the end result, it got another type of quirk for tying both streams but starts playback always (commit 6234fdc1cede "ALSA: usb-audio: Quirk for BOSS GT-001"). Meanwhile, Mike Oliphant has tested the real implicit feedback mode for the playback again with the latest code, and found out that it actually works if the initial feedback sync is skipped; that is, on those BOSS devices, the playback stream has to be started at first without waiting for the capture URB completions. Otherwise it gets stuck. In the rest operations after the capture stream processed, we can take them as the implicit feedback source. This patch is an attempt to improve the support for BOSS devices with the implicit feedback mode in the way described above. It adds a new flag to snd_usb_audio, playback_first, indicating that the playback stream starts without sync with the initial capture completion. This flag is set in the quirk table with the new IMPLICIT_FB_BOTH type. Reported-and-tested-by: Mike Oliphant Link: https://lore.kernel.org/r/20210414083255.9527-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 3 ++- sound/usb/implicit.c | 35 +++++++++++++++++++++++------------ sound/usb/usbaudio.h | 1 + 3 files changed, 26 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 102d53515a76..f4c3d2b38abb 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1375,7 +1375,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) if (!ep_state_update(ep, EP_STATE_STOPPED, EP_STATE_RUNNING)) goto __error; - if (snd_usb_endpoint_implicit_feedback_sink(ep)) { + if (snd_usb_endpoint_implicit_feedback_sink(ep) && + !ep->chip->playback_first) { for (i = 0; i < ep->nurbs; i++) { struct snd_urb_ctx *ctx = ep->urb + i; list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 19622c58b72b..4bd9c105a529 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -21,6 +21,7 @@ enum { IMPLICIT_FB_NONE, IMPLICIT_FB_GENERIC, IMPLICIT_FB_FIXED, + IMPLICIT_FB_BOTH, /* generic playback + capture (for BOSS) */ }; struct snd_usb_implicit_fb_match { @@ -36,6 +37,9 @@ struct snd_usb_implicit_fb_match { #define IMPLICIT_FB_FIXED_DEV(vend, prod, ep, ifnum) \ { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_FIXED, .ep_num = (ep),\ .iface = (ifnum) } +#define IMPLICIT_FB_BOTH_DEV(vend, prod, ep, ifnum) \ + { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_BOTH, .ep_num = (ep),\ + .iface = (ifnum) } #define IMPLICIT_FB_SKIP_DEV(vend, prod) \ { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_NONE } @@ -75,14 +79,14 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ {} /* terminator */ }; @@ -268,10 +272,17 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, } } - /* Don't apply playback quirks for the devices with capture quirk */ + /* Special handling for devices with capture quirks */ p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); - if (p && p->type == IMPLICIT_FB_FIXED) - return 0; /* no quirk */ + if (p) { + switch (p->type) { + case IMPLICIT_FB_FIXED: + return 0; /* no quirk */ + case IMPLICIT_FB_BOTH: + chip->playback_first = 1; + return add_generic_implicit_fb(chip, fmt, alts); + } + } /* Generic UAC2 implicit feedback */ if (attr == USB_ENDPOINT_SYNC_ASYNC && @@ -321,7 +332,7 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip, const struct snd_usb_implicit_fb_match *p; p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); - if (p && p->type == IMPLICIT_FB_FIXED) + if (p && (p->type == IMPLICIT_FB_FIXED || p->type == IMPLICIT_FB_BOTH)) return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0, p->iface, NULL); return 0; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index a536ee33d36e..538831cbd925 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -37,6 +37,7 @@ struct snd_usb_audio { unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ unsigned int tx_length_quirk:1; /* Put length specifier in transfers */ unsigned int need_delayed_register:1; /* warn for delayed registration */ + unsigned int playback_first:1; /* for implicit fb: don't wait for the first capture URBs */ int num_interfaces; int num_suspended_intf; int sample_rate_read_error; -- cgit v1.2.3-58-ga151 From a523ef731ac6674dc07574f31bf44cc5bfa14e4d Mon Sep 17 00:00:00 2001 From: Lukasz Majczak Date: Thu, 15 Apr 2021 14:43:47 +0200 Subject: ASoC: Intel: kbl_da7219_max98927: Fix kabylake_ssp_fixup function kabylake_ssp_fixup function uses snd_soc_dpcm to identify the codecs DAIs. The HW parameters are changed based on the codec DAI of the stream. The earlier approach to get snd_soc_dpcm was using container_of() macro on snd_pcm_hw_params. The structures have been modified over time and snd_soc_dpcm does not have snd_pcm_hw_params as a reference but as a copy. This causes the current driver to crash when used. This patch changes the way snd_soc_dpcm is extracted. snd_soc_pcm_runtime holds 2 dpcm instances (one for playback and one for capture). 2 codecs on the SSP are dmic (capture) and speakers (playback). Based on the stream direction, snd_soc_dpcm is extracted from snd_soc_pcm_runtime. Tested for all use cases of the driver. Based on similar fix in kbl_rt5663_rt5514_max98927.c from Harsha Priya and Vamshi Krishna Gopal Cc: # 5.4+ Signed-off-by: Lukasz Majczak Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210415124347.475432-1-lma@semihalf.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98927.c | 38 ++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index cc9a2509ace2..e0149cf6127d 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -282,11 +282,33 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *chan = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm = container_of( - params, struct snd_soc_dpcm, hw_params); - struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; - struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; + /* + * The following loop will be called only for playback stream + * In this platform, there is only one playback device on every SSP + */ + for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { + rtd_dpcm = dpcm; + break; + } + + /* + * This following loop will be called only for capture stream + * In this platform, there is only one capture device on every SSP + */ + for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { + rtd_dpcm = dpcm; + break; + } + + if (!rtd_dpcm) + return -EINVAL; + + /* + * The above 2 loops are mutually exclusive based on the stream direction, + * thus rtd_dpcm variable will never be overwritten + */ /* * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE, * where as kblda7219m98927 & kblmax98927 supports S16_LE by default. @@ -309,9 +331,9 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, /* * The ADSP will convert the FE rate to 48k, stereo, 24 bit */ - if (!strcmp(fe_dai_link->name, "Kbl Audio Port") || - !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) { + if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || + !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || + !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { rate->min = rate->max = 48000; chan->min = chan->max = 2; snd_mask_none(fmt); @@ -322,7 +344,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, * The speaker on the SSP0 supports S16_LE and not S24_LE. * thus changing the mask here */ - if (!strcmp(be_dai_link->name, "SSP0-Codec")) + if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; -- cgit v1.2.3-58-ga151 From 998f26f47e556f14cd124c508d76bceb2c3f6e6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Apr 2021 15:18:56 +0200 Subject: ALSA: control: Fix racy management of user ctl memory size account We've got a report about the possible race in the user control element counts (card->user_ctl_count), and it was confirmed that the race wasn't serious in the old code up to 5.12. There, the value modification itself was exclusive and protected via a write semaphore, hence it's at most concurrent reads and evaluations before the increment. Since it's only about the soft-limit to avoid the exhausting memory usage, one-off isn't a big problem at all. Meanwhile, the relevant code has been largely modified recently, and now card->user_ctl_count was replaced with card->user_ctl_alloc_size, and a few more places were added to access this field. And, in this new code, it turned out to be more serious: the modifications are scattered in various places, and a few of them are without protection. It implies that it may lead to an inconsistent value by racy accesses. For addressing it, this patch extends the range covered by the card->controls_rwsem write lock at snd_ctl_elem_add() so that the all code paths that modify and refer to card->user_ctl_alloc_size are protected by the rwsem properly. The patch adds also comments in a couple of functions to indicate that they are under the rwsem lock. Fixes: 66c6d1ef86ff ("ALSA: control: Add memory consumption limit to user controls") Link: https://lore.kernel.org/r/FEEBF384-44BE-42CF-8FB3-93470933F64F@purdue.edu Link: https://lore.kernel.org/r/20210415131856.13113-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/control.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index a076c08c21b6..498e3701514a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1337,6 +1337,7 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, return change; } +/* called in controls_rwsem write lock */ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, unsigned int size) { @@ -1414,6 +1415,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kctl, int op_flag, return read_user_tlv(kctl, buf, size); } +/* called in controls_rwsem write lock */ static int snd_ctl_elem_init_enum_names(struct user_element *ue) { char *names, *p; @@ -1529,8 +1531,11 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, private_size = value_sizes[info->type] * info->count; alloc_size = compute_user_elem_size(private_size, count); - if (check_user_elem_overflow(card, alloc_size)) - return -ENOMEM; + down_write(&card->controls_rwsem); + if (check_user_elem_overflow(card, alloc_size)) { + err = -ENOMEM; + goto unlock; + } /* * Keep memory object for this userspace control. After passing this @@ -1540,12 +1545,13 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, */ err = snd_ctl_new(&kctl, count, access, file); if (err < 0) - return err; + goto unlock; memcpy(&kctl->id, &info->id, sizeof(kctl->id)); ue = kzalloc(alloc_size, GFP_KERNEL); if (!ue) { kfree(kctl); - return -ENOMEM; + err = -ENOMEM; + goto unlock; } kctl->private_data = ue; kctl->private_free = snd_ctl_elem_user_free; @@ -1563,7 +1569,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, err = snd_ctl_elem_init_enum_names(ue); if (err < 0) { snd_ctl_free_one(kctl); - return err; + goto unlock; } } @@ -1580,7 +1586,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, kctl->tlv.c = snd_ctl_elem_user_tlv; /* This function manage to free the instance on failure. */ - down_write(&card->controls_rwsem); err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE); if (err < 0) { snd_ctl_free_one(kctl); -- cgit v1.2.3-58-ga151 From d1ee66c5d3c5a0498dd5e3f2af5b8c219a98bba5 Mon Sep 17 00:00:00 2001 From: Phil Calvin Date: Thu, 15 Apr 2021 18:01:29 -0400 Subject: ALSA: hda/realtek: fix mic boost on Intel NUC 8 Fix two bugs with the Intel HDA Realtek ALC233 sound codec present in Intel NUC NUC8i7BEH and probably a few other similar NUC models. These codecs advertise a 4-level microphone input boost amplifier on pin 0x19, but the highest two boost settings do not work correctly, and produce only low analog noise that does not seem to contain any discernible signal. There is an existing fixup for this exact problem but for a different PCI subsystem ID, so we re-use that logic. Changing the boost level also triggers a DC spike in the input signal that bleeds off over about a second and overwhelms any input during that time. Thankfully, the existing fixup has the side effect of making the boost control show up in userspace as a mute/unmute switch, and this keeps (e.g.) PulseAudio from fiddling with it during normal input volume adjustments. Finally, the NUC hardware has built-in inverted stereo mics. This patch also enables the usual fixup for this so the two channels cancel noise instead of the actual signal. [ Re-ordered the quirk entry point by tiwai ] Signed-off-by: Phil Calvin Cc: Link: https://lore.kernel.org/r/80dc5663-7734-e7e5-25ef-15b5df24511a@philcalvin.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 00a15e7cfdb9..50437ec1b9af 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6422,6 +6422,8 @@ enum { ALC269_FIXUP_LEMOTE_A1802, ALC269_FIXUP_LEMOTE_A190X, ALC256_FIXUP_INTEL_NUC8_RUGGED, + ALC233_FIXUP_INTEL_NUC8_DMIC, + ALC233_FIXUP_INTEL_NUC8_BOOST, ALC256_FIXUP_INTEL_NUC10, ALC255_FIXUP_XIAOMI_HEADSET_MIC, ALC274_FIXUP_HP_MIC, @@ -7143,6 +7145,16 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_fixup_lenovo_line2_mic_hotkey, }, + [ALC233_FIXUP_INTEL_NUC8_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + .chained = true, + .chain_id = ALC233_FIXUP_INTEL_NUC8_BOOST, + }, + [ALC233_FIXUP_INTEL_NUC8_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost + }, [ALC255_FIXUP_DELL_SPK_NOISE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_disable_aamix, @@ -8286,6 +8298,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), + SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), -- cgit v1.2.3-58-ga151 From 26928ca1f06aab4361eb5adbe7ef3b5c82f13cf2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Apr 2021 10:12:11 +0200 Subject: ALSA: hda/realtek: Add quirk for Lenovo Ideapad S740 Lenovo Ideapad S740 requires quite a few COEF setups to make its speakers working. The verb table was provided from Ryan Prescott as the result of investigation via qemu: https://github.com/ryanprescott/realtek-verb-tools/wiki/How-to-sniff-verbs-from-a-Windows-sound-driver BugLink: https://github.com/thesofproject/linux/issues/2748 Tested-by: Ryan Prescott Link: https://lore.kernel.org/r/20210416081211.20059-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/ideapad_s740_helper.c | 492 ++++++++++++++++++++++++++++++++++++ sound/pci/hda/patch_realtek.c | 11 + 2 files changed, 503 insertions(+) create mode 100644 sound/pci/hda/ideapad_s740_helper.c (limited to 'sound') diff --git a/sound/pci/hda/ideapad_s740_helper.c b/sound/pci/hda/ideapad_s740_helper.c new file mode 100644 index 000000000000..564b9086e52d --- /dev/null +++ b/sound/pci/hda/ideapad_s740_helper.c @@ -0,0 +1,492 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Fixes for Lenovo Ideapad S740, to be included from codec driver */ + +static const struct hda_verb alc285_ideapad_s740_coefs[] = { +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x10 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0320 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0041 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0041 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001d }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004e }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001d }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004e }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x002a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x002a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0046 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0046 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0044 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0044 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{} +}; + +static void alc285_fixup_ideapad_s740_coef(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_add_verbs(codec, alc285_ideapad_s740_coefs); + break; + } +} diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 50437ec1b9af..1ef40f3ca259 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6239,6 +6239,9 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, /* for alc295_fixup_hp_top_speakers */ #include "hp_x360_helper.c" +/* for alc285_fixup_ideapad_s740_coef() */ +#include "ideapad_s740_helper.c" + enum { ALC269_FIXUP_GPIO2, ALC269_FIXUP_SONY_VAIO, @@ -6436,6 +6439,7 @@ enum { ALC282_FIXUP_ACER_DISABLE_LINEOUT, ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST, ALC256_FIXUP_ACER_HEADSET_MIC, + ALC285_FIXUP_IDEAPAD_S740_COEF, }; static const struct hda_fixup alc269_fixups[] = { @@ -7920,6 +7924,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC }, + [ALC285_FIXUP_IDEAPAD_S740_COEF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_ideapad_s740_coef, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -8263,6 +8273,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3176, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940", ALC298_FIXUP_LENOVO_SPK_VOLUME), + SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), -- cgit v1.2.3-58-ga151 From 75b62ab65d2715ce6ff0794033d61ab9dc4a2dfc Mon Sep 17 00:00:00 2001 From: Jonas Witschel Date: Fri, 16 Apr 2021 12:58:54 +0200 Subject: ALSA: hda/realtek: fix mute/micmute LEDs for HP ProBook 445 G7 The HP ProBook 445 G7 (17T32ES) uses ALC236. Like ALC236_FIXUP_HP_GPIO_LED, COEF index 0x34 bit 5 is used to control the playback mute LED, but the microphone mute LED is controlled using pin VREF instead of a COEF index. AlsaInfo: https://alsa-project.org/db/?f=0d3f4d1af39cc359f9fea9b550727ee87e5cf45a Signed-off-by: Jonas Witschel Cc: Link: https://lore.kernel.org/r/20210416105852.52588-1-diabonas@archlinux.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1ef40f3ca259..67aeed5d25b6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4445,6 +4445,25 @@ static void alc236_fixup_hp_mute_led(struct hda_codec *codec, alc236_fixup_hp_coef_micmute_led(codec, fix, action); } +static void alc236_fixup_hp_micmute_led_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->cap_mute_led_nid = 0x1a; + snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set); + codec->power_filter = led_power_filter; + } +} + +static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc236_fixup_hp_mute_led_coefbit(codec, fix, action); + alc236_fixup_hp_micmute_led_vref(codec, fix, action); +} + #if IS_REACHABLE(CONFIG_INPUT) static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) @@ -6410,6 +6429,7 @@ enum { ALC285_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_GPIO_LED, ALC236_FIXUP_HP_MUTE_LED, + ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS, @@ -7669,6 +7689,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc236_fixup_hp_mute_led, }, + [ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc236_fixup_hp_mute_led_micmute_vref, + }, [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -8092,6 +8116,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), -- cgit v1.2.3-58-ga151 From 0c37e2eb6b83e375e8a654d01598292d5591fc65 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 16 Apr 2021 16:11:57 +0300 Subject: ALSA: hda/hdmi: fix race in handling acomp ELD notification at resume When snd-hda-codec-hdmi is used with ASoC HDA controller like SOF (acomp used for ELD notifications), display connection change done during suspend, can be lost due to following sequence of events: 1. system in S3 suspend 2. DP/HDMI receiver connected 3. system resumed 4. HDA controller resumed, but card->deferred_resume_work not complete 5. acomp eld_notify callback 6. eld_notify ignored as power state is not CTL_POWER_D0 7. HDA resume deferred work completed, power state set to CTL_POWER_D0 This results in losing the notification, and the jack state reported to user-space is not correct. The check on step 6 was added in commit 8ae743e82f0b ("ALSA: hda - Skip ELD notification during system suspend"). It would seem with the deferred resume logic in ASoC core, this check is not safe. Fix the issue by modifying the check to use "dev.power.power_state.event" instead of ALSA specific card power state variable. BugLink: https://github.com/thesofproject/linux/issues/2825 Suggested-by: Takashi Iwai Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20210416131157.1881366-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5de3666a7101..4b2cc8cb55c4 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2654,7 +2654,7 @@ static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) /* skip notification during system suspend (but not in runtime PM); * the state will be updated at resume */ - if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) + if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) return; /* ditto during suspend/resume process itself */ if (snd_hdac_is_in_pm(&codec->core)) @@ -2840,7 +2840,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) /* skip notification during system suspend (but not in runtime PM); * the state will be updated at resume */ - if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) + if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) return; /* ditto during suspend/resume process itself */ if (snd_hdac_is_in_pm(&codec->core)) -- cgit v1.2.3-58-ga151 From d86f43b17ed4cd751f73d890ea63f818ffa5ef3d Mon Sep 17 00:00:00 2001 From: Lucas Endres Date: Fri, 16 Apr 2021 11:50:20 -0500 Subject: ALSA: usb-audio: Add support for many Roland devices' implicit feedback quirks It makes USB audio capture and playback possible and pristine on my Roland INTEGRA-7, Boutique D-05, and R-26, along with many more I've encountered people having had issues with over the last decade or so. Signed-off-by: Lucas Endres Link: https://lore.kernel.org/r/CAOsVg8rA61B=005_VyUwpw3piVwA7Bo5fs1GYEB054efyzGjLw@mail.gmail.com Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 4bd9c105a529..428e3a449f5d 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -79,13 +79,72 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00a6, 0x0d, 0x01), /* Roland JUNO-G */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00a9, 0x0d, 0x01), /* Roland MC-808 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00ad, 0x0d, 0x01), /* Roland SH-201 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00b2, 0x0d, 0x01), /* Roland VG-99 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00b3, 0x0d, 0x01), /* Roland VG-99 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c2, 0x0d, 0x01), /* Roland SonicCell */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c4, 0x0d, 0x01), /* Edirol M-16DX */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c5, 0x0d, 0x01), /* Roland SP-555 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c7, 0x0d, 0x01), /* Roland V-Synth GT */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00d1, 0x0d, 0x01), /* Roland Music Atelier */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00da, 0x0d, 0x01), /* BOSS GT-10 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00db, 0x0d, 0x01), /* BOSS GT-10 Guitar Effects Processor */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00dc, 0x0d, 0x01), /* BOSS GT-10B */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00de, 0x0d, 0x01), /* Roland Fantom-G */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00eb, 0x0d, 0x01), /* Roland VS-100 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00f8, 0x0d, 0x01), /* Roland JUNO Series */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fc, 0x0d, 0x01), /* Roland VS-700C */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fd, 0x0d, 0x01), /* Roland VS-700 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fe, 0x0d, 0x01), /* Roland VS-700 M1 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00ff, 0x0d, 0x01), /* Roland VS-700 M2 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0100, 0x0d, 0x01), /* Roland VS-700 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0101, 0x0d, 0x01), /* Roland VS-700 M2 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0102, 0x0d, 0x01), /* Roland VB-99 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0109, 0x0d, 0x01), /* BOSS eBand JS-8 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0111, 0x0d, 0x01), /* Roland GAIA SH-01 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0113, 0x0d, 0x01), /* BOSS ME-25 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0114, 0x0d, 0x01), /* Roland SD-50 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0117, 0x0d, 0x01), /* Roland VS-20 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0119, 0x0d, 0x01), /* Roland OCTAPAD SPD-30 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x011c, 0x0d, 0x01), /* Roland Lucina AX-09 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x011e, 0x0d, 0x01), /* BOSS BR-800 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0120, 0x0d, 0x01), /* Roland OCTA-CAPTURE */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0121, 0x0d, 0x01), /* Roland OCTA-CAPTURE */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0123, 0x0d, 0x01), /* Roland JUNO-Gi */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0124, 0x0d, 0x01), /* Roland M-300 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0127, 0x0d, 0x01), /* Roland GR-55 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x012b, 0x0d, 0x01), /* Roland DUO-CAPTURE */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x012f, 0x0d, 0x01), /* Roland QUAD-CAPTURE */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0132, 0x0d, 0x01), /* Roland TRI-CAPTURE */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0134, 0x0d, 0x01), /* Roland V-Mixer */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0137, 0x0d, 0x01), /* Roland DUO-CAPTURE Advanced Mode */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0138, 0x0d, 0x01), /* BOSS RC-300 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x013a, 0x0d, 0x01), /* Roland JUPITER-80 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x013e, 0x0d, 0x01), /* Roland R-26 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0145, 0x0d, 0x01), /* Roland SPD-SX */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x014b, 0x0d, 0x01), /* BOSS eBand JS-10 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x014d, 0x0d, 0x01), /* BOSS GT-100 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0150, 0x0d, 0x01), /* Roland TD-15 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0151, 0x0d, 0x01), /* Roland TD-11 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0154, 0x0d, 0x01), /* Roland JUPITER-50 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0158, 0x0d, 0x01), /* Roland TD-30 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0159, 0x0d, 0x01), /* Roland DUO-CAPTURE EX */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x015b, 0x0d, 0x01), /* Roland INTEGRA-7 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x015d, 0x0d, 0x01), /* Roland R-88 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x017a, 0x0d, 0x01), /* Roland VT-3 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x017c, 0x0d, 0x01), /* Roland TR-8 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01b5, 0x0d, 0x01), /* Roland Boutique JP-08 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01fd, 0x0d, 0x01), /* Roland Boutique SH-01A */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01ff, 0x0d, 0x01), /* Roland Boutique D-05 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ {} /* terminator */ -- cgit v1.2.3-58-ga151 From 76fae6185f5456865ff1bcb647709d44fd987eb6 Mon Sep 17 00:00:00 2001 From: Luke D Jones Date: Mon, 19 Apr 2021 15:04:11 +1200 Subject: ALSA: hda/realtek: GA503 use same quirks as GA401 The GA503 has almost exactly the same default setup as the GA401 model with the same issues. The GA401 quirks solve all the issues so we will use the full quirk chain. Signed-off-by: Luke D Jones Cc: Link: https://lore.kernel.org/r/20210419030411.28304-1-luke@ljones.dev Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 67aeed5d25b6..1ad1bb740c32 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8167,6 +8167,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), + SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), -- cgit v1.2.3-58-ga151 From e7df7df5a3809d733888db6ce6592a644acaac19 Mon Sep 17 00:00:00 2001 From: Olivia Mackintosh Date: Sun, 18 Apr 2021 17:59:01 +0100 Subject: ALSA: usb-audio: DJM-750: ensure format is set Add case statement to set sample-rate for the DJM-750 Pioneer mixer. This was included as part of another patch but I think it has been archived on Patchwork and hasn't been merged. Signed-off-by: Olivia Mackintosh Cc: Link: https://lore.kernel.org/r/20210418165901.25776-1-livvy@base.nu Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 63f27ce64bcb..8b8bee3c3dd6 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1511,6 +1511,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */ pioneer_djm_set_format_quirk(subs, 0x0082); break; + case USB_ID(0x08e4, 0x017f): /* Pioneer DJM-750 */ case USB_ID(0x08e4, 0x0163): /* Pioneer DJM-850 */ pioneer_djm_set_format_quirk(subs, 0x0086); break; -- cgit v1.2.3-58-ga151 From fd9db1058c6c2a8c02f00707b26c4647d95e6acc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 19 Apr 2021 17:39:18 +0200 Subject: ALSA: usb-audio: Re-apply implicit feedback mode to Pioneer devices Pioneer devices are supposed to be working with the implicit feedback mode, but so far the attempt to apply the implicit feedback caused issues, hence we explicitly skipped the implicit feedback mode for them. Recently, Geraldo discovered that the device actually works if you skip the generic matching of the sync EPs for the capture stream. That is, we should apply the implicit feedback setup for the playback like other similar devices, while we need to return 1 from audioformat_capture_quirk() so that no further matching will be done. And, later on, Olivia reported later that the fiddling with the capture quirk alone doesn't suffice for the test with speaker-test program. This seems to be a similar case like the recently fixed BOSS devices. Indeed, the problem could be addressed by setting playback_first flag, which indicates that the playback URBs have to be sent out at first even in the implicit feedback mode. This patch implements the application of the implicit feedback to Pioneer devices as described in the above. The former skip_pioneer_sync_ep() was dropped, and instead we provide is_pioneer_implicit_fb() to check the Pioneer devices that need the implicit feedback. In the audioformat_implicit_fb_quirk(), simply apply the implicit fb for playback and set chip->playback_first flag if matching, and in audioformat_capture_quirk()(), it returns 1 for skipping the generic EP sync handling. Reported-by: Geraldo Tested-by: Olivia Mackintosh Link: https://lore.kernel.org/r/s5ha6pygqfz.wl-tiwai@suse.de Link: https://lore.kernel.org/r/20210419153918.450-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 428e3a449f5d..77ffcea294dd 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -230,18 +230,27 @@ static int add_roland_implicit_fb(struct snd_usb_audio *chip, ifnum, alts); } -/* Playback and capture EPs on Pioneer devices share the same iface/altset, - * but they don't seem working with the implicit fb mode well, hence we - * just return as if the sync were already set up. +/* Playback and capture EPs on Pioneer devices share the same iface/altset + * for the implicit feedback operation */ -static int skip_pioneer_sync_ep(struct snd_usb_audio *chip, - struct audioformat *fmt, - struct usb_host_interface *alts) +static bool is_pioneer_implicit_fb(struct snd_usb_audio *chip, + struct usb_host_interface *alts) + { struct usb_endpoint_descriptor *epd; + if (USB_ID_VENDOR(chip->usb_id) != 0x2b73 && + USB_ID_VENDOR(chip->usb_id) != 0x08e4) + return false; + if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) + return false; if (alts->desc.bNumEndpoints != 2) - return 0; + return false; + + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_out(epd) || + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return false; epd = get_endpoint(alts, 1); if (!usb_endpoint_is_isoc_in(epd) || @@ -250,8 +259,9 @@ static int skip_pioneer_sync_ep(struct snd_usb_audio *chip, USB_ENDPOINT_USAGE_DATA && (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != USB_ENDPOINT_USAGE_IMPLICIT_FB)) - return 0; - return 1; /* don't handle with the implicit fb, just skip sync EP */ + return false; + + return true; } static int __add_generic_implicit_fb(struct snd_usb_audio *chip, @@ -367,12 +377,12 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, } /* Pioneer devices with vendor spec class */ - if (attr == USB_ENDPOINT_SYNC_ASYNC && - alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC && - (USB_ID_VENDOR(chip->usb_id) == 0x2b73 || /* Pioneer */ - USB_ID_VENDOR(chip->usb_id) == 0x08e4 /* Pioneer */)) { - if (skip_pioneer_sync_ep(chip, fmt, alts)) - return 1; + if (is_pioneer_implicit_fb(chip, alts)) { + chip->playback_first = 1; + return add_implicit_fb_sync_ep(chip, fmt, + get_endpoint(alts, 1)->bEndpointAddress, + 1, alts->desc.bInterfaceNumber, + alts); } /* Try the generic implicit fb if available */ @@ -394,6 +404,8 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip, if (p && (p->type == IMPLICIT_FB_FIXED || p->type == IMPLICIT_FB_BOTH)) return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0, p->iface, NULL); + if (is_pioneer_implicit_fb(chip, alts)) + return 1; /* skip the quirk, also don't handle generic sync EP */ return 0; } -- cgit v1.2.3-58-ga151 From 1c9d9dfd2d254211cb37b1513b1da3e6835b8f00 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 20 Apr 2021 14:17:34 +0800 Subject: ALSA: hda/realtek - Headset Mic issue on HP platform Boot with plugged headset, the Headset Mic will be gone. Signed-off-by: Kailang Yang Cc: Link: https://lore.kernel.org/r/207eecfc3189466a820720bc0c409ea9@realtek.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1ad1bb740c32..77cb72fe3b1b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8104,6 +8104,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC), + SND_PCI_QUIRK(0x103c, 0x8158, "HP", ALC256_FIXUP_HP_HEADSET_MIC), SND_PCI_QUIRK(0x103c, 0x820d, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), SND_PCI_QUIRK(0x103c, 0x827e, "HP x360", ALC295_FIXUP_HP_X360), -- cgit v1.2.3-58-ga151 From bd15b15523fd3197d1bb46403e02e92877a4f412 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 20 Apr 2021 19:55:29 +0800 Subject: ALSA: hda/realtek: Enable mute/micmute LEDs and limit mic boost on EliteBook 845 G8 On HP EliteBook 845 G8, the audio LEDs can be enabled by ALC285_FIXUP_HP_MUTE_LED. So use it accordingly. In addition to that, the mic captures lots of noises, so also limits the mic boost. The quality of capture audio becomes crystal clear after limiting the mic boost. Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20210420115530.1349353-1-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 77cb72fe3b1b..97473e67716b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6460,6 +6460,7 @@ enum { ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST, ALC256_FIXUP_ACER_HEADSET_MIC, ALC285_FIXUP_IDEAPAD_S740_COEF, + ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST, }; static const struct hda_fixup alc269_fixups[] = { @@ -7954,6 +7955,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_THINKPAD_ACPI, }, + [ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC285_FIXUP_HP_MUTE_LED, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -8135,6 +8142,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -- cgit v1.2.3-58-ga151 From cfd577acb769301b19c31361d45ae1f145318b7a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 20 Apr 2021 14:47:19 +0100 Subject: ALSA: usb: midi: don't return -ENOMEM when usb_urb_ep_type_check fails Currently when the call to usb_urb_ep_type_check fails (returning -EINVAL) the error return path returns -ENOMEM via the exit label "error". Other uses of the same error exit label set the err variable to -ENOMEM but this is not being used. I believe the original intent was for the error exit path to return the value in err rather than the hard coded -ENOMEM, so return this rather than the hard coded -ENOMEM. Addresses-Coverity: ("Unused value") Fixes: 738d9edcfd44 ("ALSA: usb-audio: Add sanity checks for invalid EPs") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210420134719.381409-1-colin.king@canonical.com Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 9efda4b06acb..a10ac75969a8 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1316,7 +1316,7 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, error: snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + return err; } /* -- cgit v1.2.3-58-ga151 From 1300c7037f0f08692008053e4b12a2fb6fbd185a Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 21 Apr 2021 13:53:11 +0530 Subject: ASoC: amd: drop S24_LE format support AMD I2S Controller doesn't support S24_LE format. Remove S24_LE format support from ACP DMA driver and CPU DAI Driver. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/1618993402-10354-1-git-send-email-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/raven/acp3x-i2s.c | 6 ++---- sound/soc/amd/raven/acp3x-pcm-dma.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index 5bc028692fcf..2cd93887410c 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -264,8 +264,7 @@ static struct snd_soc_dai_driver acp3x_i2s_dai = { .playback = { .rates = SNDRV_PCM_RATE_8000_96000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -274,8 +273,7 @@ static struct snd_soc_dai_driver acp3x_i2s_dai = { .capture = { .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .rate_min = 8000, diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 417cda24030c..f22bb2bdf527 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -24,8 +24,7 @@ static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = { SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_96000, @@ -45,8 +44,7 @@ static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = { SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, -- cgit v1.2.3-58-ga151 From 62bad12bceebd7d336ced4e44f408b702c151ba0 Mon Sep 17 00:00:00 2001 From: Sia Jee Heng Date: Wed, 21 Apr 2021 08:55:46 +0800 Subject: ASoC: Intel: KMB: Fix random noise at the HDMI output Random noise could be heard when playing audio to the HDMI output. This is due to the IEC conversion is invoked in the external loop. As a result, this additional loop takes up a lot of the processing cycle. hdmi_reformat_iec958() process the conversion using an internal loop, it is safe to move it out from the external loop to avoid unnecessary processing cycle been spent. Furthermore, ALSA IEC958 plugin works in 32bit format only. Signed-off-by: Sia Jee Heng Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210421005546.7534-1-jee.heng.sia@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/keembay/kmb_platform.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index 0fd1e8f62c89..96741c7c0fba 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -105,14 +105,15 @@ static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s, void *buf = runtime->dma_area; int i; + if (kmb_i2s->iec958_fmt) + hdmi_reformat_iec958(runtime, kmb_i2s, tx_ptr); + /* KMB i2s uses two separate L/R FIFO */ for (i = 0; i < kmb_i2s->fifo_th; i++) { if (kmb_i2s->config.data_width == 16) { writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0)); writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0)); } else { - if (kmb_i2s->iec958_fmt) - hdmi_reformat_iec958(runtime, kmb_i2s, tx_ptr); writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0)); writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0)); } -- cgit v1.2.3-58-ga151 From a89f3a93cd20f77ac1f84089297258d4b409e280 Mon Sep 17 00:00:00 2001 From: Niklas Carlsson Date: Thu, 22 Apr 2021 15:02:26 +0200 Subject: ASoC: adau17x1: Avoid overwriting CHPF Configuring number of channels per LRCLK frame by using e.g. snd_soc_dai_set_tdm_slot before configuring DAI format was being overwritten by the latter due to a regmap_write which would write over the whole register. Signed-off-by: Niklas Carlsson Link: https://lore.kernel.org/r/20210422130226.15201-1-Niklas.Carlsson@axis.com Signed-off-by: Mark Brown --- sound/soc/codecs/adau17x1.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 546ee8178038..8aae7ab74091 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -553,6 +553,7 @@ static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, { struct adau *adau = snd_soc_component_get_drvdata(dai->component); unsigned int ctrl0, ctrl1; + unsigned int ctrl0_mask; int lrclk_pol; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -612,8 +613,16 @@ static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, if (lrclk_pol) ctrl0 |= ADAU17X1_SERIAL_PORT0_LRCLK_POL; - regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0); - regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT1, ctrl1); + /* Set the mask to update all relevant bits in ADAU17X1_SERIAL_PORT0 */ + ctrl0_mask = ADAU17X1_SERIAL_PORT0_MASTER | + ADAU17X1_SERIAL_PORT0_LRCLK_POL | + ADAU17X1_SERIAL_PORT0_BCLK_POL | + ADAU17X1_SERIAL_PORT0_PULSE_MODE; + + regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0_mask, + ctrl0); + regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1, + ADAU17X1_SERIAL_PORT1_DELAY_MASK, ctrl1); adau->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; -- cgit v1.2.3-58-ga151 From 37153cc5303aecd1ac7fc4b4b12bb93f634b4953 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Apr 2021 14:04:12 +0200 Subject: Revert "ALSA: usb-audio: Add support for many Roland devices..." This reverts commit d86f43b17ed4 ("ALSA: usb-audio: Add support for many Roland devices' feedback quirks"). It turned out that many quirk entries there don't contain the proper EP values and/or the quirk types, which lead to the broken operations. As we're going to cover all Roland/BOSS devices in a more generic way rather the explicit lists, let's revert the previous additions at first. Fixes: d86f43b17ed4 ("ALSA: usb-audio: Add support for many Roland devices' implicit feedback quirks") Link: https://lore.kernel.org/r/20210422120413.457-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 59 ---------------------------------------------------- 1 file changed, 59 deletions(-) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 77ffcea294dd..94acfaa7f2ef 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -79,72 +79,13 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00a6, 0x0d, 0x01), /* Roland JUNO-G */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00a9, 0x0d, 0x01), /* Roland MC-808 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00ad, 0x0d, 0x01), /* Roland SH-201 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00b2, 0x0d, 0x01), /* Roland VG-99 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00b3, 0x0d, 0x01), /* Roland VG-99 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c2, 0x0d, 0x01), /* Roland SonicCell */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c4, 0x0d, 0x01), /* Edirol M-16DX */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c5, 0x0d, 0x01), /* Roland SP-555 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c7, 0x0d, 0x01), /* Roland V-Synth GT */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00d1, 0x0d, 0x01), /* Roland Music Atelier */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00da, 0x0d, 0x01), /* BOSS GT-10 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00db, 0x0d, 0x01), /* BOSS GT-10 Guitar Effects Processor */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00dc, 0x0d, 0x01), /* BOSS GT-10B */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00de, 0x0d, 0x01), /* Roland Fantom-G */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00eb, 0x0d, 0x01), /* Roland VS-100 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00f8, 0x0d, 0x01), /* Roland JUNO Series */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fc, 0x0d, 0x01), /* Roland VS-700C */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fd, 0x0d, 0x01), /* Roland VS-700 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fe, 0x0d, 0x01), /* Roland VS-700 M1 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00ff, 0x0d, 0x01), /* Roland VS-700 M2 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0100, 0x0d, 0x01), /* Roland VS-700 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0101, 0x0d, 0x01), /* Roland VS-700 M2 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0102, 0x0d, 0x01), /* Roland VB-99 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0109, 0x0d, 0x01), /* BOSS eBand JS-8 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0111, 0x0d, 0x01), /* Roland GAIA SH-01 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0113, 0x0d, 0x01), /* BOSS ME-25 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0114, 0x0d, 0x01), /* Roland SD-50 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0117, 0x0d, 0x01), /* Roland VS-20 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0119, 0x0d, 0x01), /* Roland OCTAPAD SPD-30 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x011c, 0x0d, 0x01), /* Roland Lucina AX-09 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x011e, 0x0d, 0x01), /* BOSS BR-800 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0120, 0x0d, 0x01), /* Roland OCTA-CAPTURE */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0121, 0x0d, 0x01), /* Roland OCTA-CAPTURE */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0123, 0x0d, 0x01), /* Roland JUNO-Gi */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0124, 0x0d, 0x01), /* Roland M-300 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0127, 0x0d, 0x01), /* Roland GR-55 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x012b, 0x0d, 0x01), /* Roland DUO-CAPTURE */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x012f, 0x0d, 0x01), /* Roland QUAD-CAPTURE */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0132, 0x0d, 0x01), /* Roland TRI-CAPTURE */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0134, 0x0d, 0x01), /* Roland V-Mixer */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0137, 0x0d, 0x01), /* Roland DUO-CAPTURE Advanced Mode */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0138, 0x0d, 0x01), /* BOSS RC-300 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x013a, 0x0d, 0x01), /* Roland JUPITER-80 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x013e, 0x0d, 0x01), /* Roland R-26 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0145, 0x0d, 0x01), /* Roland SPD-SX */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x014b, 0x0d, 0x01), /* BOSS eBand JS-10 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x014d, 0x0d, 0x01), /* BOSS GT-100 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0150, 0x0d, 0x01), /* Roland TD-15 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0151, 0x0d, 0x01), /* Roland TD-11 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0154, 0x0d, 0x01), /* Roland JUPITER-50 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0158, 0x0d, 0x01), /* Roland TD-30 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0159, 0x0d, 0x01), /* Roland DUO-CAPTURE EX */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x015b, 0x0d, 0x01), /* Roland INTEGRA-7 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x015d, 0x0d, 0x01), /* Roland R-88 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x017a, 0x0d, 0x01), /* Roland VT-3 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x017c, 0x0d, 0x01), /* Roland TR-8 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01b5, 0x0d, 0x01), /* Roland Boutique JP-08 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01fd, 0x0d, 0x01), /* Roland Boutique SH-01A */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01ff, 0x0d, 0x01), /* Roland Boutique D-05 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ {} /* terminator */ -- cgit v1.2.3-58-ga151 From 316791b556f7c4aeb7a7fea8f400f4434e71d1bf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Apr 2021 14:04:13 +0200 Subject: ALSA: usb-audio: Generic application of implicit fb to Roland/BOSS devices Through the examinations and experiments with lots of Roland and BOSS USB-audio devices, we found out that the recently introduced full-duplex operations with the implicit feedback mode work fine for quite a few devices, while the others need only the capture-side quirk to enforce the full-duplex mode. The recent commit d86f43b17ed4 ("ALSA: usb-audio: Add support for many Roland devices' implicit feedback quirks") tried to add such quirk entries manually in the lists, but this turned out to be too many and error-prone, hence it was reverted again. This patch is another attempt to cover those missing Roland/BOSS devices but in a more generic way. It matches the devices with the vendor ID 0x0582, and checks whether they are with both ASYNC sync types or ASYNC is only for capture device. In the former case, it's the device with the implicit feedback mode, and applies accordingly. In both cases, the capture stream requires always the full-duplex mode, and we apply the known capture quirk for that, too. Basically the already existing BOSS device quirk entries become redundant after this generic matching, so those are removed. Although the capture_implicit_fb_quirks[] table became empty and superfluous, I keep it for now, so that people can put a special device easily at any time later again. Link: https://lore.kernel.org/r/CAOsVg8rA61B=005_VyUwpw3piVwA7Bo5fs1GYEB054efyzGjLw@mail.gmail.com Link: https://lore.kernel.org/r/20210414083255.9527-1-tiwai@suse.de BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212519 Tested-by: Lucas Endres Link: https://lore.kernel.org/r/20210422120413.457-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 92 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 94acfaa7f2ef..590a0dbba7a2 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -79,15 +79,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ - {} /* terminator */ }; @@ -145,30 +136,70 @@ static int add_generic_uac2_implicit_fb(struct snd_usb_audio *chip, ifnum, alts); } -/* Like the function above, but specific to Roland with vendor class and hack */ +static bool roland_sanity_check_iface(struct usb_host_interface *alts) +{ + if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC || + (alts->desc.bInterfaceSubClass != 2 && + alts->desc.bInterfaceProtocol != 2) || + alts->desc.bNumEndpoints < 1) + return false; + return true; +} + +/* Like the UAC2 case above, but specific to Roland with vendor class and hack */ static int add_roland_implicit_fb(struct snd_usb_audio *chip, struct audioformat *fmt, - unsigned int ifnum, - unsigned int altsetting) + struct usb_host_interface *alts) { - struct usb_host_interface *alts; struct usb_endpoint_descriptor *epd; - alts = snd_usb_get_host_interface(chip, ifnum, altsetting); - if (!alts) + if (!roland_sanity_check_iface(alts)) return 0; - if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC || - (alts->desc.bInterfaceSubClass != 2 && - alts->desc.bInterfaceProtocol != 2) || - alts->desc.bNumEndpoints < 1) + /* only when both streams are with ASYNC type */ + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_out(epd) || + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return 0; + + /* check capture EP */ + alts = snd_usb_get_host_interface(chip, + alts->desc.bInterfaceNumber + 1, + alts->desc.bAlternateSetting); + if (!alts || !roland_sanity_check_iface(alts)) return 0; epd = get_endpoint(alts, 0); if (!usb_endpoint_is_isoc_in(epd) || - (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != - USB_ENDPOINT_USAGE_IMPLICIT_FB) + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) return 0; + chip->playback_first = 1; return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0, - ifnum, alts); + alts->desc.bInterfaceNumber, alts); +} + +/* capture quirk for Roland device; always full-duplex */ +static int add_roland_capture_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts) +{ + struct usb_endpoint_descriptor *epd; + + if (!roland_sanity_check_iface(alts)) + return 0; + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_in(epd) || + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return 0; + + alts = snd_usb_get_host_interface(chip, + alts->desc.bInterfaceNumber - 1, + alts->desc.bAlternateSetting); + if (!alts || !roland_sanity_check_iface(alts)) + return 0; + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_out(epd)) + return 0; + return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0, + alts->desc.bInterfaceNumber, alts); } /* Playback and capture EPs on Pioneer devices share the same iface/altset @@ -306,14 +337,8 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, } /* Roland/BOSS implicit feedback with vendor spec class */ - if (attr == USB_ENDPOINT_SYNC_ASYNC && - alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC && - alts->desc.bInterfaceProtocol == 2 && - alts->desc.bNumEndpoints == 1 && - USB_ID_VENDOR(chip->usb_id) == 0x0582 /* Roland */) { - if (add_roland_implicit_fb(chip, fmt, - alts->desc.bInterfaceNumber + 1, - alts->desc.bAlternateSetting)) + if (USB_ID_VENDOR(chip->usb_id) == 0x0582) { + if (add_roland_implicit_fb(chip, fmt, alts) > 0) return 1; } @@ -345,6 +370,13 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip, if (p && (p->type == IMPLICIT_FB_FIXED || p->type == IMPLICIT_FB_BOTH)) return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0, p->iface, NULL); + + /* Roland/BOSS need full-duplex streams */ + if (USB_ID_VENDOR(chip->usb_id) == 0x0582) { + if (add_roland_capture_quirk(chip, fmt, alts) > 0) + return 1; + } + if (is_pioneer_implicit_fb(chip, alts)) return 1; /* skip the quirk, also don't handle generic sync EP */ return 0; -- cgit v1.2.3-58-ga151 From 988cc17552606be67a956cf8cd6ff504cfc5d643 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Apr 2021 08:33:49 +0200 Subject: ALSA: usb-audio: Fix implicit sync clearance at stopping stream The recent endpoint management change for implicit feedback mode added a clearance of ep->sync_sink (formerly ep->sync_slave) pointer at snd_usb_endpoint_stop() to assure no leftover for the feedback from the already stopped capture stream. This turned out to cause a regression, however, when full-duplex streams were running and only a capture was stopped. Because of the above clearance of ep->sync_sink pointer, no more feedback is done, hence the playback will stall. This patch fixes the ep->sync_sink clearance to be done only after all endpoints are released, for addressing the regression. Reported-and-tested-by: Lucas Endres Fixes: bf6313a0ff76 ("ALSA: usb-audio: Refactor endpoint management") Cc: Link: https://lore.kernel.org/r/20210426063349.18601-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index f4c3d2b38abb..014c43862826 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1443,11 +1443,11 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) if (snd_BUG_ON(!atomic_read(&ep->running))) return; - if (ep->sync_source) - WRITE_ONCE(ep->sync_source->sync_sink, NULL); - - if (!atomic_dec_return(&ep->running)) + if (!atomic_dec_return(&ep->running)) { + if (ep->sync_source) + WRITE_ONCE(ep->sync_source->sync_sink, NULL); stop_urbs(ep, false); + } } /** -- cgit v1.2.3-58-ga151 From 9bbb94e57df135ef61bef075d9c99b8d9e89e246 Mon Sep 17 00:00:00 2001 From: Sami Loone Date: Sun, 25 Apr 2021 22:37:12 +0200 Subject: ALSA: hda/realtek: fix static noise on ALC285 Lenovo laptops Remove a duplicate vendor+subvendor pin fixup entry as one is masking the other and making it unreachable. Consider the more specific newcomer as a second chance instead. The generic entry is made less strict to also match for laptops with slightly different 0x12 pin configuration. Tested on Lenovo Yoga 6 (AMD) where 0x12 is 0x40000000. Fixes: 607184cb1635 ("ALSA: hda/realtek - Add supported for more Lenovo ALC285 Headset Button") Signed-off-by: Sami Loone Cc: Link: https://lore.kernel.org/r/YIXS+GT/dGI/LtK6@yoga Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 97473e67716b..f4c2b10aeb68 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8800,12 +8800,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60130}, {0x19, 0x03a11020}, {0x21, 0x0321101f}), - SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, - {0x14, 0x90170110}, - {0x19, 0x04a11040}, - {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE, - {0x12, 0x90a60130}, {0x14, 0x90170110}, {0x19, 0x04a11040}, {0x21, 0x04211020}), @@ -8976,6 +8971,10 @@ static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, {0x19, 0x40000000}, {0x1a, 0x40000000}), + SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, + {0x14, 0x90170110}, + {0x19, 0x04a11040}, + {0x21, 0x04211020}), {} }; -- cgit v1.2.3-58-ga151 From 1c98f574403dbcf2eb832d5535a10d967333ef2d Mon Sep 17 00:00:00 2001 From: Lv Yunlong Date: Mon, 26 Apr 2021 06:11:29 -0700 Subject: ALSA: emu8000: Fix a use after free in snd_emu8000_create_mixer Our code analyzer reported a uaf. In snd_emu8000_create_mixer, the callee snd_ctl_add(..,emu->controls[i]) calls snd_ctl_add_replace(.., kcontrol,..). Inside snd_ctl_add_replace(), if error happens, kcontrol will be freed by snd_ctl_free_one(kcontrol). Then emu->controls[i] points to a freed memory, and the execution comes to __error branch of snd_emu8000_create_mixer. The freed emu->controls[i] is used in snd_ctl_remove(card, emu->controls[i]). My patch set emu->controls[i] to NULL if snd_ctl_add() failed to avoid the uaf. Signed-off-by: Lv Yunlong Cc: Link: https://lore.kernel.org/r/20210426131129.4796-1-lyl2019@mail.ustc.edu.cn Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 0aa545ac6e60..1c90421a88dc 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1029,8 +1029,10 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) memset(emu->controls, 0, sizeof(emu->controls)); for (i = 0; i < EMU8000_NUM_CONTROLS; i++) { - if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0) + if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0) { + emu->controls[i] = NULL; goto __error; + } } return 0; -- cgit v1.2.3-58-ga151 From 4fb44dd2c1dda18606348acdfdb97e8759dde9df Mon Sep 17 00:00:00 2001 From: Lv Yunlong Date: Mon, 26 Apr 2021 07:55:41 -0700 Subject: ALSA: sb: Fix two use after free in snd_sb_qsound_build In snd_sb_qsound_build, snd_ctl_add(..,p->qsound_switch...) and snd_ctl_add(..,p->qsound_space..) are called. But the second arguments of snd_ctl_add() could be freed via snd_ctl_add_replace() ->snd_ctl_free_one(). After the error code is returned, snd_sb_qsound_destroy(p) is called in __error branch. But in snd_sb_qsound_destroy(), the freed p->qsound_switch and p->qsound_space are still used by snd_ctl_remove(). My patch set p->qsound_switch and p->qsound_space to NULL if snd_ctl_add() failed to avoid the uaf bugs. But these codes need to further be improved with the code style. Signed-off-by: Lv Yunlong Cc: Link: https://lore.kernel.org/r/20210426145541.8070-1-lyl2019@mail.ustc.edu.cn Signed-off-by: Takashi Iwai --- sound/isa/sb/sb16_csp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 8635a2b6b36b..4789345a8fdd 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -1045,10 +1045,14 @@ static int snd_sb_qsound_build(struct snd_sb_csp * p) spin_lock_init(&p->q_lock); - if ((err = snd_ctl_add(card, p->qsound_switch = snd_ctl_new1(&snd_sb_qsound_switch, p))) < 0) + if ((err = snd_ctl_add(card, p->qsound_switch = snd_ctl_new1(&snd_sb_qsound_switch, p))) < 0) { + p->qsound_switch = NULL; goto __error; - if ((err = snd_ctl_add(card, p->qsound_space = snd_ctl_new1(&snd_sb_qsound_space, p))) < 0) + } + if ((err = snd_ctl_add(card, p->qsound_space = snd_ctl_new1(&snd_sb_qsound_space, p))) < 0) { + p->qsound_space = NULL; goto __error; + } return 0; -- cgit v1.2.3-58-ga151 From 0e853a9c3937caa9f13fdde547d6202f92457c2b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 26 Apr 2021 17:37:48 +0100 Subject: ALSA: hda/cirrus: Set Initial DMIC volume for Bullseye to -26 dB After booting for first time on Bullseye, the DMIC is currently muted. Instead, the DMIC volume should be set to a valid initial value. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1923557 Reported-and-tested-by: You-Sheng Yang Cc: Link: https://lore.kernel.org/r/20210426163749.196153-2-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 5d57096b3a95..a4f82f147ff3 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -2172,6 +2172,11 @@ static void cs8409_cs42l42_fixups(struct hda_codec *codec, (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); break; case HDA_FIXUP_ACT_PROBE: + + /* Set initial volume on Bullseye to -26 dB */ + if (codec->fixup_id == CS8409_BULLSEYE) + snd_hda_codec_amp_init_stereo(codec, CS8409_CS42L42_DMIC_ADC_PIN_NID, + HDA_INPUT, 0, 0xff, 0x19); snd_hda_gen_add_kctl(&spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer); snd_hda_gen_add_kctl(&spec->gen, -- cgit v1.2.3-58-ga151 From 45b14fe200ba0611b6c3874aa5bba584dc979fb9 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 26 Apr 2021 17:37:49 +0100 Subject: ALSA: hda/cirrus: Use CS8409 filter to fix abnormal sounds on Bullseye Cracking noises have been reported on the built-in speaker for certain Bullseye platforms, when volume is > 80%. This issue is caused by the specific combination of Codec and AMP in this platform, and cannot be fixed by the AMP, so indead must be fixed at codec level, by adding attenuation to the volume. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1924997 Reported-and-tested-by: You-Sheng Yang Cc: Link: https://lore.kernel.org/r/20210426163749.196153-3-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a4f82f147ff3..726507d0b04c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1481,6 +1481,34 @@ static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = { {} /* Terminator */ }; +static const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[] = { + { 0x47, 0x65, 0x4000 }, /* EQ_SEL=1, EQ1/2_EN=0 */ + { 0x47, 0x64, 0x4000 }, /* +EQ_ACC */ + { 0x47, 0x65, 0x4010 }, /* +EQ2_EN */ + { 0x47, 0x63, 0x0647 }, /* EQ_DATA_HI=0x0647 */ + { 0x47, 0x64, 0xc0c7 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=0, EQ_DATA_LO=0x67 */ + { 0x47, 0x63, 0x0647 }, /* EQ_DATA_HI=0x0647 */ + { 0x47, 0x64, 0xc1c7 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=1, EQ_DATA_LO=0x67 */ + { 0x47, 0x63, 0xf370 }, /* EQ_DATA_HI=0xf370 */ + { 0x47, 0x64, 0xc271 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=2, EQ_DATA_LO=0x71 */ + { 0x47, 0x63, 0x1ef8 }, /* EQ_DATA_HI=0x1ef8 */ + { 0x47, 0x64, 0xc348 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=3, EQ_DATA_LO=0x48 */ + { 0x47, 0x63, 0xc110 }, /* EQ_DATA_HI=0xc110 */ + { 0x47, 0x64, 0xc45a }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=4, EQ_DATA_LO=0x5a */ + { 0x47, 0x63, 0x1f29 }, /* EQ_DATA_HI=0x1f29 */ + { 0x47, 0x64, 0xc574 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=5, EQ_DATA_LO=0x74 */ + { 0x47, 0x63, 0x1d7a }, /* EQ_DATA_HI=0x1d7a */ + { 0x47, 0x64, 0xc653 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=6, EQ_DATA_LO=0x53 */ + { 0x47, 0x63, 0xc38c }, /* EQ_DATA_HI=0xc38c */ + { 0x47, 0x64, 0xc714 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=7, EQ_DATA_LO=0x14 */ + { 0x47, 0x63, 0x1ca3 }, /* EQ_DATA_HI=0x1ca3 */ + { 0x47, 0x64, 0xc8c7 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=8, EQ_DATA_LO=0xc7 */ + { 0x47, 0x63, 0xc38c }, /* EQ_DATA_HI=0xc38c */ + { 0x47, 0x64, 0xc914 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=9, EQ_DATA_LO=0x14 */ + { 0x47, 0x64, 0x0000 }, /* -EQ_ACC, -EQ_WRT */ + {} /* Terminator */ +}; + /** * cs8409_enable_i2c_clock - Enable I2C clocks * @codec: the codec instance @@ -2029,6 +2057,7 @@ static void cs8409_enable_ur(struct hda_codec *codec, int flag) static void cs8409_cs42l42_hw_init(struct hda_codec *codec) { const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg; + const struct cs8409_cir_param *seq_bullseye = cs8409_cs42l42_bullseye_atn; struct cs_spec *spec = codec->spec; if (spec->gpio_mask) { @@ -2043,6 +2072,10 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec) for (; seq->nid; seq++) cs_vendor_coef_set(codec, seq->cir, seq->coeff); + if (codec->fixup_id == CS8409_BULLSEYE) + for (; seq_bullseye->nid; seq_bullseye++) + cs_vendor_coef_set(codec, seq_bullseye->cir, seq_bullseye->coeff); + /* Disable Unsolicited Response during boot */ cs8409_enable_ur(codec, 0); -- cgit v1.2.3-58-ga151 From e861431303d23428bf26e8496252d7bee260a956 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 26 Apr 2021 16:39:02 -0500 Subject: ALSA: virtio: fix kernel-doc make W=1 warning: sound/virtio/virtio_ctl_msg.c:70: warning: expecting prototype for virtsnd_ctl_msg_request(). Prototype was for virtsnd_ctl_msg_response() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210426213902.234711-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/virtio/virtio_ctl_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/virtio/virtio_ctl_msg.c b/sound/virtio/virtio_ctl_msg.c index 26ff7e7cc041..18dc5aca2e0c 100644 --- a/sound/virtio/virtio_ctl_msg.c +++ b/sound/virtio/virtio_ctl_msg.c @@ -61,7 +61,7 @@ void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg) } /** - * virtsnd_ctl_msg_request() - Get a pointer to the response header. + * virtsnd_ctl_msg_response() - Get a pointer to the response header. * @msg: Control message. * * Context: Any context. -- cgit v1.2.3-58-ga151 From 970e3012c04c96351c413f193a9c909e6d871ce2 Mon Sep 17 00:00:00 2001 From: Eckhart Mohr Date: Tue, 27 Apr 2021 17:30:25 +0200 Subject: ALSA: hda/realtek: Add quirk for Intel Clevo PCx0Dx This applies a SND_PCI_QUIRK(...) to the Clevo PCx0Dx barebones. This fix enables audio output over the headset jack and ensures that a microphone connected via the headset combo jack is correctly recognized when pluged in. [ Rearranged the list entries in a sorted order -- tiwai ] Signed-off-by: Eckhart Mohr Co-developed-by: Werner Sembach Signed-off-by: Werner Sembach Cc: Link: https://lore.kernel.org/r/20210427153025.451118-1-wse@tuxedocomputers.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f4c2b10aeb68..4a3939c45a12 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2552,8 +2552,10 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), -- cgit v1.2.3-58-ga151 From a3ffcebc87480664aef7c8283394d4cf2aec327c Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Tue, 27 Apr 2021 18:26:34 +0800 Subject: ALSA: usb-audio: Remove redundant assignment to len Variable len is set to zero but this value is never read as it is overwritten with a new value later on, hence it is a redundant assignment and can be removed. Cleans up the following clang-analyzer warning: sound/usb/mixer.c:2713:3: warning: Value stored to 'len' is never read [clang-analyzer-deadcode.DeadStores]. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/1619519194-57806-1-git-send-email-jiapeng.chong@linux.alibaba.com Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 2faf5767c7f8..428d581f988f 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2726,7 +2726,6 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, #define MAX_ITEM_NAME_LEN 64 for (i = 0; i < desc->bNrInPins; i++) { struct usb_audio_term iterm; - len = 0; namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); if (!namelist[i]) { err = -ENOMEM; -- cgit v1.2.3-58-ga151 From b265047ac56bad8c4f3d0c8bf9cb4e828ee0d28e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:52 +0200 Subject: ALSA: hda/realtek: Re-order ALC882 Acer quirk table entries Just re-order the alc882_fixup_tbl[] entries for Acer devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4a3939c45a12..bc4136b2b82f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2470,13 +2470,13 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { ALC882_FIXUP_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", ALC882_FIXUP_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", + ALC882_FIXUP_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", ALC882_FIXUP_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", - ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210), SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G", ALC882_FIXUP_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE), -- cgit v1.2.3-58-ga151 From b7529c18feecb1af92f9db08c8e7fe446a82d96d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:53 +0200 Subject: ALSA: hda/realtek: Re-order ALC882 Sony quirk table entries Just re-order the alc882_fixup_tbl[] entries for Sony devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bc4136b2b82f..61a7c2f7a648 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2489,11 +2489,11 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS), SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3), + SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP), - SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), - SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), /* All Apple entries are in codec SSIDs */ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), -- cgit v1.2.3-58-ga151 From 13e1a4cd490b959a4c72c9f4fb502ef56b190062 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:54 +0200 Subject: ALSA: hda/realtek: Re-order ALC882 Clevo quirk table entries Just re-order the alc882_fixup_tbl[] entries for Clevo devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also, user lower hex letters in the entry. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 61a7c2f7a648..5eee67d443c2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2536,9 +2536,19 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), + SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x950A, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950), @@ -2548,16 +2558,6 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530), -- cgit v1.2.3-58-ga151 From 45461e3b554c75ddff9703539f3711cc3dfb0422 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:55 +0200 Subject: ALSA: hda/realtek: Re-order ALC269 HP quirk table entries Just re-order the alc269_fixup_tbl[] entries for HP devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Formerly, some entries were grouped for the actual codec, but this doesn't seem reasonable to keep in that way. So now we simply keep the PCI SSID order for the whole. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 44 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5eee67d443c2..5c594b8b8723 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8055,35 +8055,18 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY), - /* ALC282 */ SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), + SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS), - SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS), - SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M), - SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - /* ALC290 */ - SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), @@ -8091,26 +8074,41 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY), SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS), SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS), SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M), + SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC), -- cgit v1.2.3-58-ga151 From 433f894ec7fbd3b4bf1f3187b2ddd566078c4aef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:56 +0200 Subject: ALSA: hda/realtek: Re-order ALC269 Acer quirk table entries Just re-order the alc269_fixup_tbl[] entries for Acer devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5c594b8b8723..fd7255490635 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7971,12 +7971,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), SND_PCI_QUIRK(0x1025, 0x072d, "Acer Aspire V5-571G", ALC269_FIXUP_ASPIRE_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), + SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF), SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE), -- cgit v1.2.3-58-ga151 From aa143ad39a52d968ac69e426d329bb74f270e6ca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:57 +0200 Subject: ALSA: hda/realtek: Re-order ALC269 Dell quirk table entries Just re-order the alc269_fixup_tbl[] entries for Dell devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index fd7255490635..7e1accdd990f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8032,8 +8032,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0738, "Dell Precision 5820", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x1028, 0x075c, "Dell XPS 27 7760", ALC298_FIXUP_SPK_VOLUME), SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), - SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3), SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), + SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3), SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), @@ -8043,8 +8043,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), - SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x097d, "Dell Precision", ALC289_FIXUP_DUAL_SPK), + SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x098d, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x09bf, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0a2e, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC), -- cgit v1.2.3-58-ga151 From 3cd0ed636dd19e7fbe3ebe8de8476e1718d5a8f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:58 +0200 Subject: ALSA: hda/realtek: Re-order ALC269 ASUS quirk table entries Just re-order the alc269_fixup_tbl[] entries for ASUS devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7e1accdd990f..d99666c706b7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8151,16 +8151,18 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), + SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE), @@ -8173,13 +8175,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), - SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), -- cgit v1.2.3-58-ga151 From cab561f8d4bc9b196ae20c960aa5da89fd786ab5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:59 +0200 Subject: ALSA: hda/realtek: Re-order ALC269 Sony quirk table entries Just re-order the alc269_fixup_tbl[] entries for Sony devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d99666c706b7..53967d50d382 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8186,12 +8186,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101), - SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), + SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT), SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN), -- cgit v1.2.3-58-ga151 From f552ff54c2a700616a02b038e4bf3cbf859f65b7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:00 +0200 Subject: ALSA: hda/realtek: Re-order ALC269 Lenovo quirk table entries Just re-order the alc269_fixup_tbl[] entries for Lenovo devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 53967d50d382..539bae66a4ba 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8266,9 +8266,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST), SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), @@ -8313,6 +8313,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK), @@ -8331,7 +8332,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS), SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20), -- cgit v1.2.3-58-ga151 From c656f747df151a0a89756a5312f4ca2116758ba4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:01 +0200 Subject: ALSA: hda/realtek: Re-order remaining ALC269 quirk table entries Just re-order the alc269_fixup_tbl[] entries for FSC, Medion, Samsung and Lemote devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 539bae66a4ba..11f731b95eef 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8195,10 +8195,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT), SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN), - SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC), + SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), + SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), @@ -8208,9 +8209,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), @@ -8338,13 +8339,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI), SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101), SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ + SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), + SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), - SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), - SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), - SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), -- cgit v1.2.3-58-ga151 From 9edeb1109d05953b2f0e24e5b2341a98c3fa78d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:02 +0200 Subject: ALSA: hda/realtek: Re-order ALC662 quirk table entries Just re-order the alc662_fixup_tbl[] entries for Acer and ASUS devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 11f731b95eef..cbed3c610170 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10086,6 +10086,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS), SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE), SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE), SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), @@ -10102,9 +10103,9 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), - SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751), + SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51), @@ -10124,7 +10125,6 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON), SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), - SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS), #if 0 /* Below is a quirk table taken from the old code. -- cgit v1.2.3-58-ga151 From defce244b01ee12534910a4544e11be5eb927d25 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:03 +0200 Subject: ALSA: hda/realtek: Remove redundant entry for ALC861 Haier/Uniwill devices The quirk entry for Uniwill ECS M31EI is with the PCI SSID device 0, which means matching with all. That is, it's essentially equivalent with SND_PCI_QUIRK_VENDOR(0x1584), which also matches with the previous entry for Haier W18 applying the very same quirk. Let's unify them with the single vendor-quirk entry. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-13-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cbed3c610170..bd7bfd7c9ee7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9290,8 +9290,7 @@ static const struct snd_pci_quirk alc861_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F), SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT), - SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", ALC861_FIXUP_AMP_VREF_0F), - SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", ALC861_FIXUP_AMP_VREF_0F), + SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F), SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505), {} }; -- cgit v1.2.3-58-ga151 From 2e6a731296be9d356fdccee9fb6ae345dad96438 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:04 +0200 Subject: ALSA: hda/conexant: Re-order CX5066 quirk table entries Just re-order the cx5066_fixups[] entries for HP devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-14-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index dfef9c17e140..d111258c6f45 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -930,18 +930,18 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), - SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK), - SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK), - SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), - SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK), - SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), - SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO), - SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED), -- cgit v1.2.3-58-ga151 From 266fd994b2b0ab7ba3e5541868838ce30775964b Mon Sep 17 00:00:00 2001 From: Sami Loone Date: Sat, 1 May 2021 12:07:53 +0200 Subject: ALSA: hda/realtek: ALC285 Thinkpad jack pin quirk is unreachable In 9bbb94e57df1 ("ALSA: hda/realtek: fix static noise on ALC285 Lenovo laptops") an existing Lenovo quirk was made more generic by removing a 0x12 pin requirement from the entry. This made the second chance table Thinkpad jack entry unreachable as the pin configurations became identical. Revert the 0x12 pin requirement removal and move Thinkpad jack pin quirk back to the primary pin table as they can co-exist when more specific configurations come first. Add a more targeted pin quirk for Lenovo devices that have 0x12 as 0x40000000. Tested on Yoga 6 (AMD) laptop. [ Corrected the commit ID -- tiwai ] Fixes: 9bbb94e57df1 ("ALSA: hda/realtek: fix static noise on ALC285 Lenovo laptops") Signed-off-by: Sami Loone Cc: Link: https://lore.kernel.org/r/YI0oefvTYn8URYDb@yoga Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bd7bfd7c9ee7..a0fa99a31c23 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8801,6 +8801,16 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x19, 0x03a11020}, {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE, + {0x12, 0x90a60130}, + {0x14, 0x90170110}, + {0x19, 0x04a11040}, + {0x21, 0x04211020}), + SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE, + {0x14, 0x90170110}, + {0x19, 0x04a11040}, + {0x1d, 0x40600001}, + {0x21, 0x04211020}), + SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, {0x14, 0x90170110}, {0x19, 0x04a11040}, {0x21, 0x04211020}), @@ -8971,10 +8981,6 @@ static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, {0x19, 0x40000000}, {0x1a, 0x40000000}), - SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, - {0x14, 0x90170110}, - {0x19, 0x04a11040}, - {0x21, 0x04211020}), {} }; -- cgit v1.2.3-58-ga151 From ab2165e2e6ed17345ffa8ee88ca764e8788ebcd7 Mon Sep 17 00:00:00 2001 From: Timo Gurr Date: Mon, 3 May 2021 13:08:22 +0200 Subject: ALSA: usb-audio: Add dB range mapping for Sennheiser Communications Headset PC 8 The decibel volume range contains a negative maximum value resulting in pipewire complaining about the device and effectivly having no sound output. The wrong values also resulted in the headset sounding muted already at a mixer level of about ~25%. PipeWire BugLink: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/1049 BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212897 Signed-off-by: Timo Gurr Cc: Link: https://lore.kernel.org/r/20210503110822.10222-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/mixer_maps.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 646deb6244b1..c5794e83fd80 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -337,6 +337,13 @@ static const struct usbmix_name_map bose_companion5_map[] = { { 0 } /* terminator */ }; +/* Sennheiser Communications Headset [PC 8], the dB value is reported as -6 negative maximum */ +static const struct usbmix_dB_map sennheiser_pc8_dB = {-9500, 0}; +static const struct usbmix_name_map sennheiser_pc8_map[] = { + { 9, NULL, .dB = &sennheiser_pc8_dB }, + { 0 } /* terminator */ +}; + /* * Dell usb dock with ALC4020 codec had a firmware problem where it got * screwed up when zero volume is passed; just skip it as a workaround @@ -593,6 +600,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x17aa, 0x1046), .map = lenovo_p620_rear_map, }, + { + /* Sennheiser Communications Headset [PC 8] */ + .id = USB_ID(0x1395, 0x0025), + .map = sennheiser_pc8_map, + }, { 0 } /* terminator */ }; -- cgit v1.2.3-58-ga151 From 8eedd3a70a70f51fa963f3ad7fa97afd0c75bd44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 May 2021 10:20:57 +0200 Subject: ALSA: hda/realtek: Fix silent headphone output on ASUS UX430UA It was reported that the headphone output on ASUS UX430UA (SSID 1043:1740) with ALC295 codec is silent while the speaker works. After the investigation, it turned out that the DAC assignment has to be fixed on this machine; unlike others, it expects DAC 0x02 to be assigned to the speaker pin 0x07 while DAC 0x03 to headphone pin 0x21. This patch provides a fixup for the fixed DAC/pin mapping for this device. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212933 Cc: Link: https://lore.kernel.org/r/20210504082057.6913-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a0fa99a31c23..bbbe37f3e724 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5695,6 +5695,18 @@ static void alc_fixup_tpt470_dacs(struct hda_codec *codec, spec->gen.preferred_dacs = preferred_pairs; } +static void alc295_fixup_asus_dacs(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const hda_nid_t preferred_pairs[] = { + 0x17, 0x02, 0x21, 0x03, 0 + }; + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->gen.preferred_dacs = preferred_pairs; +} + static void alc_shutup_dell_xps13(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -6463,6 +6475,7 @@ enum { ALC256_FIXUP_ACER_HEADSET_MIC, ALC285_FIXUP_IDEAPAD_S740_COEF, ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST, + ALC295_FIXUP_ASUS_DACS, }; static const struct hda_fixup alc269_fixups[] = { @@ -7963,6 +7976,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC285_FIXUP_HP_MUTE_LED, }, + [ALC295_FIXUP_ASUS_DACS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc295_fixup_asus_dacs, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -8161,6 +8178,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS), SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), -- cgit v1.2.3-58-ga151 From 622464c893142f7beac89f5ba8c9773bca5e5004 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 May 2021 11:18:02 +0200 Subject: ALSA: hda/realtek: Fix speaker amp on HP Envy AiO 32 HP Envy AiO 32-a12xxx has an external amp that is controlled via GPIO bit 0x04. However, unlike other devices, this amp seems to shut down itself after the certain period, hence the OS needs to up/down the bit dynamically only during the actual playback. This patch adds the control of the GPIO bit via the existing pcm_hook mechanism. Ideally it should be triggered at the actual stream start, but we have only the state change at prepare/cleanup, so use those for switching the GPIO bit on/off. This should be good enough for the purpose, and was actually confirmed to work fine. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212873 Cc: Link: https://lore.kernel.org/r/20210504091802.13200-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bbbe37f3e724..ee2841dd0c6d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4338,6 +4338,35 @@ static void alc245_fixup_hp_x360_amp(struct hda_codec *codec, } } +/* toggle GPIO2 at each time stream is started; we use PREPARE state instead */ +static void alc274_hp_envy_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + switch (action) { + case HDA_GEN_PCM_ACT_PREPARE: + alc_update_gpio_data(codec, 0x04, true); + break; + case HDA_GEN_PCM_ACT_CLEANUP: + alc_update_gpio_data(codec, 0x04, false); + break; + } +} + +static void alc274_fixup_hp_envy_gpio(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PROBE) { + spec->gpio_mask |= 0x04; + spec->gpio_dir |= 0x04; + spec->gen.pcm_playback_hook = alc274_hp_envy_pcm_hook; + } +} + static void alc_update_coef_led(struct hda_codec *codec, struct alc_coef_led *led, bool polarity, bool on) @@ -6465,6 +6494,7 @@ enum { ALC255_FIXUP_XIAOMI_HEADSET_MIC, ALC274_FIXUP_HP_MIC, ALC274_FIXUP_HP_HEADSET_MIC, + ALC274_FIXUP_HP_ENVY_GPIO, ALC256_FIXUP_ASUS_HPE, ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, ALC287_FIXUP_HP_GPIO_LED, @@ -7907,6 +7937,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC274_FIXUP_HP_MIC }, + [ALC274_FIXUP_HP_ENVY_GPIO] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc274_fixup_hp_envy_gpio, + }, [ALC256_FIXUP_ASUS_HPE] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -8140,6 +8174,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), -- cgit v1.2.3-58-ga151 From 5d84b5318d860c9d80ca5dfae0e971ede53b4921 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 May 2021 14:18:32 +0200 Subject: ALSA: hda/realtek: Add fixup for HP OMEN laptop HP OMEN dc0019-ur with codec SSID 103c:84da requires the pin config overrides and the existing mic/mute LED setup. This patch implements those in the fixup table. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212733 Cc: Link: https://lore.kernel.org/r/20210504121832.4558-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ee2841dd0c6d..6d58f24c9702 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6506,6 +6506,7 @@ enum { ALC285_FIXUP_IDEAPAD_S740_COEF, ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST, ALC295_FIXUP_ASUS_DACS, + ALC295_FIXUP_HP_OMEN, }; static const struct hda_fixup alc269_fixups[] = { @@ -8014,6 +8015,26 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc295_fixup_asus_dacs, }, + [ALC295_FIXUP_HP_OMEN] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x12, 0xb7a60130 }, + { 0x13, 0x40000000 }, + { 0x14, 0x411111f0 }, + { 0x16, 0x411111f0 }, + { 0x17, 0x90170110 }, + { 0x18, 0x411111f0 }, + { 0x19, 0x02a11030 }, + { 0x1a, 0x411111f0 }, + { 0x1b, 0x04a19030 }, + { 0x1d, 0x40600001 }, + { 0x1e, 0x411111f0 }, + { 0x21, 0x03211020 }, + {} + }, + .chained = true, + .chain_id = ALC269_FIXUP_HP_LINE1_MIC1_LED, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -8172,6 +8193,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x82c0, "HP G3 mini premium", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3), + SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN), SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), @@ -8577,6 +8599,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"}, {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, {.id = ALC245_FIXUP_HP_X360_AMP, .name = "alc245-hp-x360-amp"}, + {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"}, {} }; #define ALC225_STANDARD_PINS \ -- cgit v1.2.3-58-ga151 From f48652bbe3ae62ba2835a396b7e01f063e51c4cd Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 4 May 2021 15:39:17 +0800 Subject: ALSA: hda: generic: change the DAC ctl name for LO+SPK or LO+HP Without this change, the DAC ctl's name could be changed only when the machine has both Speaker and Headphone, but we met some machines which only has Lineout and Headhpone, and the Lineout and Headphone share the Audio Mixer0 and DAC0, the ctl's name is set to "Front". On most of machines, the "Front" is used for Speaker only or Lineout only, but on this machine it is shared by Lineout and Headphone, This introduces an issue in the pipewire and pulseaudio, suppose users want the Headphone to be on and the Speaker/Lineout to be off, they could turn off the "Front", this works on most of the machines, but on this machine, the "Front" couldn't be turned off otherwise the headphone will be off too. Here we do some change to let the ctl's name change to "Headphone+LO" on this machine, and pipewire and pulseaudio already could handle "Headphone+LO" and "Speaker+LO". (https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/747) BugLink: http://bugs.launchpad.net/bugs/804178 Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20210504073917.22406-1-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 3998e1771805..b638fc2ef6f7 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1204,11 +1204,17 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch, *index = ch; return "Headphone"; case AUTO_PIN_LINE_OUT: - /* This deals with the case where we have two DACs and - * one LO, one HP and one Speaker */ - if (!ch && cfg->speaker_outs && cfg->hp_outs) { - bool hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type); - bool spk_lo_shared = !path_has_mixer(codec, spec->speaker_paths[0], ctl_type); + /* This deals with the case where one HP or one Speaker or + * one HP + one Speaker need to share the DAC with LO + */ + if (!ch) { + bool hp_lo_shared = false, spk_lo_shared = false; + + if (cfg->speaker_outs) + spk_lo_shared = !path_has_mixer(codec, + spec->speaker_paths[0], ctl_type); + if (cfg->hp_outs) + hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type); if (hp_lo_shared && spk_lo_shared) return spec->vmaster_mute.hook ? "PCM" : "Master"; if (hp_lo_shared) -- cgit v1.2.3-58-ga151 From 8822702f6e4c8917c83ba79e0ebf2c8c218910d4 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Fri, 7 May 2021 10:44:52 +0800 Subject: ALSA: hda/realtek: reset eapd coeff to default value for alc287 Ubuntu users reported an audio bug on the Lenovo Yoga Slim 7 14IIL05, he installed dual OS (Windows + Linux), if he booted to the Linux from Windows, the Speaker can't work well, it has crackling noise, if he poweroff the machine first after Windows, the Speaker worked well. Before rebooting or shutdown from Windows, the Windows changes the codec eapd coeff value, but the BIOS doesn't re-initialize its value, when booting into the Linux from Windows, the eapd coeff value is not correct. To fix it, set the codec default value to that coeff register in the alsa driver. BugLink: http://bugs.launchpad.net/bugs/1925057 Suggested-by: Kailang Yang Cc: Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20210507024452.8300-1-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6d58f24c9702..a5f3e78ec04e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -395,7 +395,6 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0282: case 0x10ec0283: case 0x10ec0286: - case 0x10ec0287: case 0x10ec0288: case 0x10ec0285: case 0x10ec0298: @@ -406,6 +405,10 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0275: alc_update_coef_idx(codec, 0xe, 0, 1<<0); break; + case 0x10ec0287: + alc_update_coef_idx(codec, 0x10, 1<<9, 0); + alc_write_coef_idx(codec, 0x8, 0x4ab7); + break; case 0x10ec0293: alc_update_coef_idx(codec, 0xa, 1<<13, 0); break; -- cgit v1.2.3-58-ga151 From c1b55029493879f5bd585ff79f326e71f0bc05e3 Mon Sep 17 00:00:00 2001 From: Daniel Cordova A Date: Fri, 7 May 2021 12:31:16 -0500 Subject: ALSA: hda: fixup headset for ASUS GU502 laptop The GU502 requires a few steps to make headset i/o works properly: pincfg, verbs to unmute headphone out and callback to toggle output between speakers and headphone using jack. Signed-off-by: Daniel Cordova A Cc: Link: https://lore.kernel.org/r/20210507173116.12043-1-danesc87@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a5f3e78ec04e..b4b71609dff1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6254,6 +6254,35 @@ static void alc294_fixup_gx502_hp(struct hda_codec *codec, } } +static void alc294_gu502_toggle_output(struct hda_codec *codec, + struct hda_jack_callback *cb) +{ + /* Windows sets 0x10 to 0x8420 for Node 0x20 which is + * responsible from changes between speakers and headphones + */ + if (snd_hda_jack_detect_state(codec, 0x21) == HDA_JACK_PRESENT) + alc_write_coef_idx(codec, 0x10, 0x8420); + else + alc_write_coef_idx(codec, 0x10, 0x0a20); +} + +static void alc294_fixup_gu502_hp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (!is_jack_detectable(codec, 0x21)) + return; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_jack_detect_enable_callback(codec, 0x21, + alc294_gu502_toggle_output); + break; + case HDA_FIXUP_ACT_INIT: + alc294_gu502_toggle_output(codec, NULL); + break; + } +} + static void alc285_fixup_hp_gpio_amp_init(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -6471,6 +6500,9 @@ enum { ALC294_FIXUP_ASUS_GX502_HP, ALC294_FIXUP_ASUS_GX502_PINS, ALC294_FIXUP_ASUS_GX502_VERBS, + ALC294_FIXUP_ASUS_GU502_HP, + ALC294_FIXUP_ASUS_GU502_PINS, + ALC294_FIXUP_ASUS_GU502_VERBS, ALC285_FIXUP_HP_GPIO_LED, ALC285_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_GPIO_LED, @@ -7712,6 +7744,35 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc294_fixup_gx502_hp, }, + [ALC294_FIXUP_ASUS_GU502_PINS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a11050 }, /* rear HP mic */ + { 0x1a, 0x01a11830 }, /* rear external mic */ + { 0x21, 0x012110f0 }, /* rear HP out */ + { } + }, + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_GU502_VERBS + }, + [ALC294_FIXUP_ASUS_GU502_VERBS] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* set 0x15 to HP-OUT ctrl */ + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* unmute the 0x15 amp */ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, + /* set 0x1b to HP-OUT */ + { 0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { } + }, + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_GU502_HP + }, + [ALC294_FIXUP_ASUS_GU502_HP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc294_fixup_gu502_hp, + }, [ALC294_FIXUP_ASUS_COEF_1B] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -8256,6 +8317,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), + SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), -- cgit v1.2.3-58-ga151 From e84749a78dc82bc545f12ce009e3dbcc2c5a8a91 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 May 2021 17:06:59 +0200 Subject: ALSA: usb-audio: Validate MS endpoint descriptors snd_usbmidi_get_ms_info() may access beyond the border when a malformed descriptor is passed. This patch adds the sanity checks of the given MS endpoint descriptors, and skips invalid ones. Reported-by: syzbot+6bb23a5d5548b93c94aa@syzkaller.appspotmail.com Cc: Link: https://lore.kernel.org/r/20210510150659.17710-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/usb/midi.c b/sound/usb/midi.c index a10ac75969a8..649eb8d1ab7d 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1956,8 +1956,12 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, ms_ep = find_usb_ms_endpoint_descriptor(hostep); if (!ms_ep) continue; + if (ms_ep->bLength <= sizeof(*ms_ep)) + continue; if (ms_ep->bNumEmbMIDIJack > 0x10) continue; + if (ms_ep->bLength < sizeof(*ms_ep) + ms_ep->bNumEmbMIDIJack) + continue; if (usb_endpoint_dir_out(ep)) { if (endpoints[epidx].out_ep) { if (++epidx >= MIDI_MAX_ENDPOINTS) { -- cgit v1.2.3-58-ga151 From 91e02557f377b6837d4f82b14229d92cae231001 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 May 2021 11:05:00 +0200 Subject: ALSA: usb-audio: Fix potential out-of-bounce access in MIDI EP parser The recently introduced MIDI endpoint parser code has an access to the field without the size validation, hence it might lead to out-of-bounce access. Add the sanity checks for the descriptor sizes. Fixes: eb596e0fd13c ("ALSA: usb-audio: generate midi streaming substream names from jack names") Link: https://lore.kernel.org/r/20210511090500.2637-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 649eb8d1ab7d..2c01649c70f6 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1750,7 +1750,7 @@ static struct usb_midi_in_jack_descriptor *find_usb_in_jack_descriptor( struct usb_midi_in_jack_descriptor *injd = (struct usb_midi_in_jack_descriptor *)extra; - if (injd->bLength > 4 && + if (injd->bLength >= sizeof(*injd) && injd->bDescriptorType == USB_DT_CS_INTERFACE && injd->bDescriptorSubtype == UAC_MIDI_IN_JACK && injd->bJackID == jack_id) @@ -1773,7 +1773,7 @@ static struct usb_midi_out_jack_descriptor *find_usb_out_jack_descriptor( struct usb_midi_out_jack_descriptor *outjd = (struct usb_midi_out_jack_descriptor *)extra; - if (outjd->bLength > 4 && + if (outjd->bLength >= sizeof(*outjd) && outjd->bDescriptorType == USB_DT_CS_INTERFACE && outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK && outjd->bJackID == jack_id) @@ -1820,7 +1820,8 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, outjd = find_usb_out_jack_descriptor(hostif, jack_id); if (outjd) { sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins); - iJack = *(((uint8_t *) outjd) + sz - sizeof(uint8_t)); + if (outjd->bLength >= sz) + iJack = *(((uint8_t *) outjd) + sz - sizeof(uint8_t)); } } else { /* and out jacks connect to ins */ -- cgit v1.2.3-58-ga151 From f2be77fee648ddd6d0d259d3527344ba0120e314 Mon Sep 17 00:00:00 2001 From: Elia Devito Date: Tue, 11 May 2021 14:46:49 +0200 Subject: ALSA: hda/realtek: Add fixup for HP Spectre x360 15-df0xxx Fixup to enable all 4 speaker on HP Spectre x360 15-df0xxx and probably on similar models. 0x14 pin config override is required to enable all speakers and alc285-speaker2-to-dac1 fixup to enable volume adjustment. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=189331 Signed-off-by: Elia Devito Cc: Link: https://lore.kernel.org/r/20210511124651.4802-1-eliadevito@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b4b71609dff1..3e269de84079 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6542,6 +6542,7 @@ enum { ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST, ALC295_FIXUP_ASUS_DACS, ALC295_FIXUP_HP_OMEN, + ALC285_FIXUP_HP_SPECTRE_X360, }; static const struct hda_fixup alc269_fixups[] = { @@ -8099,6 +8100,15 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HP_LINE1_MIC1_LED, }, + [ALC285_FIXUP_HP_SPECTRE_X360] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x90170110 }, /* enable top speaker */ + {} + }, + .chained = true, + .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -8259,6 +8269,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN), SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), + SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360), SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED), @@ -8665,6 +8676,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, {.id = ALC245_FIXUP_HP_X360_AMP, .name = "alc245-hp-x360-amp"}, {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"}, + {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"}, {} }; #define ALC225_STANDARD_PINS \ -- cgit v1.2.3-58-ga151 From 4b059ce1f4b368208c2310925f49be77f15e527b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 May 2021 13:56:34 +0200 Subject: Revert "ALSA: sb: fix a missing check of snd_ctl_add" This reverts commit beae77170c60aa786f3e4599c18ead2854d8694d. Because of recent interactions with developers from @umn.edu, all commits from them have been recently re-reviewed to ensure if they were correct or not. Upon review, this commit was found to be incorrect for the reasons below, so it must be reverted. It is safe to ignore this error as the mixer element is optional, and the driver is very legacy. Cc: Aditya Pakki Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20210503115736.2104747-8-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/isa/sb/sb16_main.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 38dc1fde25f3..aa4870531023 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -846,14 +846,10 @@ int snd_sb16dsp_pcm(struct snd_sb *chip, int device) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops); - if (chip->dma16 >= 0 && chip->dma8 != chip->dma16) { - err = snd_ctl_add(card, snd_ctl_new1( - &snd_sb16_dma_control, chip)); - if (err) - return err; - } else { + if (chip->dma16 >= 0 && chip->dma8 != chip->dma16) + snd_ctl_add(card, snd_ctl_new1(&snd_sb16_dma_control, chip)); + else pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; - } snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, 64*1024, 128*1024); -- cgit v1.2.3-58-ga151 From 1dacca7fa1ebea47d38d20cd2df37094805d2649 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 May 2021 13:56:59 +0200 Subject: Revert "ALSA: gus: add a check of the status of snd_ctl_add" This reverts commit 0f25e000cb4398081748e54f62a902098aa79ec1. Because of recent interactions with developers from @umn.edu, all commits from them have been recently re-reviewed to ensure if they were correct or not. Upon review, this commit was found to be incorrect for the reasons below, so it must be reverted. It will be fixed up "correctly" in a later kernel change. The original commit did nothing if there was an error, except to print out a message, which is pointless. So remove the commit as it gives a "false sense of doing something". Cc: Kangjie Lu Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20210503115736.2104747-33-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/isa/gus/gus_main.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index afc088f0377c..b7518122a10d 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -77,17 +77,8 @@ static const struct snd_kcontrol_new snd_gus_joystick_control = { static void snd_gus_init_control(struct snd_gus_card *gus) { - int ret; - - if (!gus->ace_flag) { - ret = - snd_ctl_add(gus->card, - snd_ctl_new1(&snd_gus_joystick_control, - gus)); - if (ret) - snd_printk(KERN_ERR "gus: snd_ctl_add failed: %d\n", - ret); - } + if (!gus->ace_flag) + snd_ctl_add(gus->card, snd_ctl_new1(&snd_gus_joystick_control, gus)); } /* -- cgit v1.2.3-58-ga151 From 94f88309f201821073f57ae6005caefa61bf7b7e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 May 2021 13:57:01 +0200 Subject: Revert "ALSA: sb8: add a check for request_region" This reverts commit dcd0feac9bab901d5739de51b3f69840851f8919. Because of recent interactions with developers from @umn.edu, all commits from them have been recently re-reviewed to ensure if they were correct or not. Upon review, this commit was found to be incorrect for the reasons below, so it must be reverted. It will be fixed up "correctly" in a later kernel change. The original commit message for this change was incorrect as the code path can never result in a NULL dereference, alluding to the fact that whatever tool was used to "find this" is broken. It's just an optional resource reservation, so removing this check is fine. Cc: Kangjie Lu Acked-by: Takashi Iwai Fixes: dcd0feac9bab ("ALSA: sb8: add a check for request_region") Cc: stable Link: https://lore.kernel.org/r/20210503115736.2104747-35-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/isa/sb/sb8.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 6c9d534ce8b6..95290ffe5c6e 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -95,10 +95,6 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) /* block the 0x388 port to avoid PnP conflicts */ acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); - if (!acard->fm_res) { - err = -EBUSY; - goto _err; - } if (port[dev] != SNDRV_AUTO_PORT) { if ((err = snd_sbdsp_create(card, port[dev], irq[dev], -- cgit v1.2.3-58-ga151 From a28591f61b60fac820c6de59826ffa710e5e314e Mon Sep 17 00:00:00 2001 From: Atul Gopinathan Date: Mon, 3 May 2021 13:57:02 +0200 Subject: ALSA: sb8: Add a comment note regarding an unused pointer The field "fm_res" of "struct snd_sb8" is never used/dereferenced throughout the sb8.c code. Therefore there is no need for any null value check after the "request_region()". Add a comment note to make developers know about this and prevent any "NULL check" patches on this part of code. Cc: Takashi Iwai Signed-off-by: Atul Gopinathan Link: https://lore.kernel.org/r/20210503115736.2104747-36-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/isa/sb/sb8.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 95290ffe5c6e..ed3a87ebe3f4 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -93,7 +93,11 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) acard = card->private_data; card->private_free = snd_sb8_free; - /* block the 0x388 port to avoid PnP conflicts */ + /* + * Block the 0x388 port to avoid PnP conflicts. + * No need to check this value after request_region, + * as we never do anything with it. + */ acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); if (port[dev] != SNDRV_AUTO_PORT) { -- cgit v1.2.3-58-ga151 From 4667a6fc1777ce071504bab570d3599107f4790f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 May 2021 13:57:03 +0200 Subject: Revert "ALSA: usx2y: Fix potential NULL pointer dereference" This reverts commit a2c6433ee5a35a8de6d563f6512a26f87835ea0f. Because of recent interactions with developers from @umn.edu, all commits from them have been recently re-reviewed to ensure if they were correct or not. Upon review, this commit was found to be incorrect for the reasons below, so it must be reverted. It will be fixed up "correctly" in a later kernel change. The original patch was incorrect, and would leak memory if the error path the patch added was hit. Cc: Aditya Pakki Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20210503115736.2104747-37-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/usb/usx2y/usb_stream.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index 091c071b270a..6bba17bf689a 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -91,12 +91,7 @@ static int init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, for (u = 0; u < USB_STREAM_NURBS; ++u) { sk->inurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL); - if (!sk->inurb[u]) - return -ENOMEM; - sk->outurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL); - if (!sk->outurb[u]) - return -ENOMEM; } if (init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe) || -- cgit v1.2.3-58-ga151 From 1e0ce84215dbfd6065872e5d3755352da34f198b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 May 2021 13:57:21 +0200 Subject: Revert "ASoC: rt5645: fix a NULL pointer dereference" This reverts commit 51dd97d1df5fb9ac58b9b358e63e67b530f6ae21. Because of recent interactions with developers from @umn.edu, all commits from them have been recently re-reviewed to ensure if they were correct or not. Upon review, this commit was found to be incorrect for the reasons below, so it must be reverted. It will be fixed up "correctly" in a later kernel change. Lots of things seem to be still allocated here and must be properly cleaned up if an error happens here. Cc: Kangjie Lu Cc: Mark Brown Link: https://lore.kernel.org/r/20210503115736.2104747-55-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/rt5645.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9408ee63cb26..7cb90975009a 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3431,9 +3431,6 @@ static int rt5645_probe(struct snd_soc_component *component) RT5645_HWEQ_NUM, sizeof(struct rt5645_eq_param_s), GFP_KERNEL); - if (!rt5645->eq_param) - return -ENOMEM; - return 0; } -- cgit v1.2.3-58-ga151 From 5e70b8e22b64eed13d5bbebcb5911dae65bf8c6b Mon Sep 17 00:00:00 2001 From: Phillip Potter Date: Mon, 3 May 2021 13:57:22 +0200 Subject: ASoC: rt5645: add error checking to rt5645_probe function Check for return value from various snd_soc_dapm_* calls, as many of them can return errors and this should be handled. Also, reintroduce the allocation failure check for rt5645->eq_param as well. Make all areas where return values are checked lead to the end of the function in the case of an error. Finally, introduce a comment explaining how resources here are actually eventually cleaned up by the caller. Cc: Mark Brown Signed-off-by: Phillip Potter Link: https://lore.kernel.org/r/20210503115736.2104747-56-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/rt5645.c | 48 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 7cb90975009a..438fa18bcb55 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3388,30 +3388,44 @@ static int rt5645_probe(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); + int ret = 0; rt5645->component = component; switch (rt5645->codec_type) { case CODEC_TYPE_RT5645: - snd_soc_dapm_new_controls(dapm, + ret = snd_soc_dapm_new_controls(dapm, rt5645_specific_dapm_widgets, ARRAY_SIZE(rt5645_specific_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, + if (ret < 0) + goto exit; + + ret = snd_soc_dapm_add_routes(dapm, rt5645_specific_dapm_routes, ARRAY_SIZE(rt5645_specific_dapm_routes)); + if (ret < 0) + goto exit; + if (rt5645->v_id < 3) { - snd_soc_dapm_add_routes(dapm, + ret = snd_soc_dapm_add_routes(dapm, rt5645_old_dapm_routes, ARRAY_SIZE(rt5645_old_dapm_routes)); + if (ret < 0) + goto exit; } break; case CODEC_TYPE_RT5650: - snd_soc_dapm_new_controls(dapm, + ret = snd_soc_dapm_new_controls(dapm, rt5650_specific_dapm_widgets, ARRAY_SIZE(rt5650_specific_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, + if (ret < 0) + goto exit; + + ret = snd_soc_dapm_add_routes(dapm, rt5650_specific_dapm_routes, ARRAY_SIZE(rt5650_specific_dapm_routes)); + if (ret < 0) + goto exit; break; } @@ -3419,9 +3433,17 @@ static int rt5645_probe(struct snd_soc_component *component) /* for JD function */ if (rt5645->pdata.jd_mode) { - snd_soc_dapm_force_enable_pin(dapm, "JD Power"); - snd_soc_dapm_force_enable_pin(dapm, "LDO2"); - snd_soc_dapm_sync(dapm); + ret = snd_soc_dapm_force_enable_pin(dapm, "JD Power"); + if (ret < 0) + goto exit; + + ret = snd_soc_dapm_force_enable_pin(dapm, "LDO2"); + if (ret < 0) + goto exit; + + ret = snd_soc_dapm_sync(dapm); + if (ret < 0) + goto exit; } if (rt5645->pdata.long_name) @@ -3431,7 +3453,15 @@ static int rt5645_probe(struct snd_soc_component *component) RT5645_HWEQ_NUM, sizeof(struct rt5645_eq_param_s), GFP_KERNEL); - return 0; + if (!rt5645->eq_param) + ret = -ENOMEM; +exit: + /* + * If there was an error above, everything will be cleaned up by the + * caller if we return an error here. This will be done with a later + * call to rt5645_remove(). + */ + return ret; } static void rt5645_remove(struct snd_soc_component *component) -- cgit v1.2.3-58-ga151 From fdda0dd2686ecd1f2e616c9e0366ea71b40c485d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 May 2021 13:57:23 +0200 Subject: Revert "ASoC: cs43130: fix a NULL pointer dereference" This reverts commit a2be42f18d409213bb7e7a736e3ef6ba005115bb. Because of recent interactions with developers from @umn.edu, all commits from them have been recently re-reviewed to ensure if they were correct or not. Upon review, this commit was found to be incorrect for the reasons below, so it must be reverted. It will be fixed up "correctly" in a later kernel change. The original patch here is not correct, sysfs files that were created are not unwound. Cc: Kangjie Lu Cc: Mark Brown Link: https://lore.kernel.org/r/20210503115736.2104747-57-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/cs43130.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 80bc7c10ed75..c2b6f0ae6d57 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -2319,8 +2319,6 @@ static int cs43130_probe(struct snd_soc_component *component) return ret; cs43130->wq = create_singlethread_workqueue("cs43130_hp"); - if (!cs43130->wq) - return -ENOMEM; INIT_WORK(&cs43130->work, cs43130_imp_meas); } -- cgit v1.2.3-58-ga151 From 2da441a6491d93eff8ffff523837fd621dc80389 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 May 2021 13:57:24 +0200 Subject: ASoC: cs43130: handle errors in cs43130_probe() properly cs43130_probe() does not do any valid error checking of things it initializes, OR what it does, it does not unwind properly if there are errors. Fix this up by moving the sysfs files to an attribute group so the driver core will correctly add/remove them all at once and handle errors with them, and correctly check for creating a new workqueue and unwinding if that fails. Cc: Mark Brown Link: https://lore.kernel.org/r/20210503115736.2104747-58-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/cs43130.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index c2b6f0ae6d57..80cd3ea0c157 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -1735,6 +1735,14 @@ static DEVICE_ATTR(hpload_dc_r, 0444, cs43130_show_dc_r, NULL); static DEVICE_ATTR(hpload_ac_l, 0444, cs43130_show_ac_l, NULL); static DEVICE_ATTR(hpload_ac_r, 0444, cs43130_show_ac_r, NULL); +static struct attribute *hpload_attrs[] = { + &dev_attr_hpload_dc_l.attr, + &dev_attr_hpload_dc_r.attr, + &dev_attr_hpload_ac_l.attr, + &dev_attr_hpload_ac_r.attr, +}; +ATTRIBUTE_GROUPS(hpload); + static struct reg_sequence hp_en_cal_seq[] = { {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, {CS43130_HP_MEAS_LOAD_1, 0}, @@ -2302,23 +2310,15 @@ static int cs43130_probe(struct snd_soc_component *component) cs43130->hpload_done = false; if (cs43130->dc_meas) { - ret = device_create_file(component->dev, &dev_attr_hpload_dc_l); - if (ret < 0) - return ret; - - ret = device_create_file(component->dev, &dev_attr_hpload_dc_r); - if (ret < 0) - return ret; - - ret = device_create_file(component->dev, &dev_attr_hpload_ac_l); - if (ret < 0) - return ret; - - ret = device_create_file(component->dev, &dev_attr_hpload_ac_r); - if (ret < 0) + ret = sysfs_create_groups(&component->dev->kobj, hpload_groups); + if (ret) return ret; cs43130->wq = create_singlethread_workqueue("cs43130_hp"); + if (!cs43130->wq) { + sysfs_remove_groups(&component->dev->kobj, hpload_groups); + return -ENOMEM; + } INIT_WORK(&cs43130->work, cs43130_imp_meas); } -- cgit v1.2.3-58-ga151 From 27b57bb76a897be80494ee11ee4e85326d19383d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 May 2021 21:40:38 +0200 Subject: Revert "Revert "ALSA: usx2y: Fix potential NULL pointer dereference"" This reverts commit 4667a6fc1777ce071504bab570d3599107f4790f. Takashi writes: I have already started working on the bigger cleanup of this driver code based on 5.13-rc1, so could you drop this revert? I missed our previous discussion about this, my fault for applying it. Reported-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/usx2y/usb_stream.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index 6bba17bf689a..091c071b270a 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -91,7 +91,12 @@ static int init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, for (u = 0; u < USB_STREAM_NURBS; ++u) { sk->inurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL); + if (!sk->inurb[u]) + return -ENOMEM; + sk->outurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL); + if (!sk->outurb[u]) + return -ENOMEM; } if (init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe) || -- cgit v1.2.3-58-ga151 From 1b6604896e78969baffc1b6cc6bc175f95929ac4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 13 May 2021 21:56:48 +0900 Subject: ALSA: dice: fix stream format at middle sampling rate for Alesis iO 26 Alesis iO 26 FireWire has two pairs of digital optical interface. It delivers PCM frames from the interfaces by second isochronous packet streaming. Although both of the interfaces are available at 44.1/48.0 kHz, first one of them is only available at 88.2/96.0 kHz. It reduces the number of PCM samples to 4 in Multi Bit Linear Audio data channel of data blocks on the second isochronous packet streaming. This commit fixes hardcoded stream formats. Cc: Fixes: 28b208f600a3 ("ALSA: dice: add parameters of stream formats for models produced by Alesis") Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210513125652.110249-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-alesis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-alesis.c b/sound/firewire/dice/dice-alesis.c index 0916864511d5..27c13b9cc9ef 100644 --- a/sound/firewire/dice/dice-alesis.c +++ b/sound/firewire/dice/dice-alesis.c @@ -16,7 +16,7 @@ alesis_io14_tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT] = { static const unsigned int alesis_io26_tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT] = { {10, 10, 4}, /* Tx0 = Analog + S/PDIF. */ - {16, 8, 0}, /* Tx1 = ADAT1 + ADAT2. */ + {16, 4, 0}, /* Tx1 = ADAT1 + ADAT2 (available at low rate). */ }; int snd_dice_detect_alesis_formats(struct snd_dice *dice) -- cgit v1.2.3-58-ga151 From 0edabdfe89581669609eaac5f6a8d0ae6fe95e7f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 13 May 2021 21:56:49 +0900 Subject: ALSA: bebob/oxfw: fix Kconfig entry for Mackie d.2 Pro Mackie d.2 has an extension card for IEEE 1394 communication, which uses BridgeCo DM1000 ASIC. On the other hand, Mackie d.4 Pro has built-in function for IEEE 1394 communication by Oxford Semiconductor OXFW971, according to schematic diagram available in Mackie website. Although I misunderstood that Mackie d.2 Pro would be also a model with OXFW971, it's wrong. Mackie d.2 Pro is a model which includes the extension card as factory settings. This commit fixes entries in Kconfig and comment in ALSA OXFW driver. Cc: Fixes: fd6f4b0dc167 ("ALSA: bebob: Add skelton for BeBoB based devices") Fixes: ec4dba5053e1 ("ALSA: oxfw: Add support for Behringer/Mackie devices") Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210513125652.110249-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 4 ++-- sound/firewire/bebob/bebob.c | 2 +- sound/firewire/oxfw/oxfw.c | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 25778765cbfe..9897bd26a438 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -38,7 +38,7 @@ config SND_OXFW * Mackie(Loud) Onyx 1640i (former model) * Mackie(Loud) Onyx Satellite * Mackie(Loud) Tapco Link.Firewire - * Mackie(Loud) d.2 pro/d.4 pro + * Mackie(Loud) d.4 pro * Mackie(Loud) U.420/U.420d * TASCAM FireOne * Stanton Controllers & Systems 1 Deck/Mixer @@ -84,7 +84,7 @@ config SND_BEBOB * PreSonus FIREBOX/FIREPOD/FP10/Inspire1394 * BridgeCo RDAudio1/Audio5 * Mackie Onyx 1220/1620/1640 (FireWire I/O Card) - * Mackie d.2 (FireWire Option) + * Mackie d.2 (FireWire Option) and d.2 Pro * Stanton FinalScratch 2 (ScratchAmp) * Tascam IF-FW/DM * Behringer XENIX UFX 1204/1604 diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 2c8e3392a490..daeecfa8b9aa 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -387,7 +387,7 @@ static const struct ieee1394_device_id bebob_id_table[] = { SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal), /* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */ SND_BEBOB_DEV_ENTRY(VEN_MACKIE2, 0x00010065, &spec_normal), - /* Mackie, d.2 (Firewire Option) */ + // Mackie, d.2 (Firewire option card) and d.2 Pro (the card is built-in). SND_BEBOB_DEV_ENTRY(VEN_MACKIE1, 0x00010067, &spec_normal), /* Stanton, ScratchAmp */ SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal), diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 1f1e3236efb8..9eea25c46dc7 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -355,7 +355,6 @@ static const struct ieee1394_device_id oxfw_id_table[] = { * Onyx-i series (former models): 0x081216 * Mackie Onyx Satellite: 0x00200f * Tapco LINK.firewire 4x6: 0x000460 - * d.2 pro: Unknown * d.4 pro: Unknown * U.420: Unknown * U.420d: Unknown -- cgit v1.2.3-58-ga151 From 395f41e2cdac63e7581fb9574e5ac0f02556e34a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 13 May 2021 21:56:50 +0900 Subject: ALSA: firewire-lib: fix check for the size of isochronous packet payload The check for size of isochronous packet payload just cares of the size of IR context payload without the size of CIP header. Cc: Fixes: f11453c7cc01 ("ALSA: firewire-lib: use 16 bytes IR context header to separate CIP header") Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210513125652.110249-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 4e2f2bb7879f..b53971bf4b90 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -633,18 +633,24 @@ static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, unsigned int *syt, unsigned int index) { const __be32 *cip_header; + unsigned int cip_header_size; int err; *payload_length = be32_to_cpu(ctx_header[0]) >> ISO_DATA_LENGTH_SHIFT; - if (*payload_length > s->ctx_data.tx.ctx_header_size + - s->ctx_data.tx.max_ctx_payload_length) { + + if (!(s->flags & CIP_NO_HEADER)) + cip_header_size = 8; + else + cip_header_size = 0; + + if (*payload_length > cip_header_size + s->ctx_data.tx.max_ctx_payload_length) { dev_err(&s->unit->device, "Detect jumbo payload: %04x %04x\n", - *payload_length, s->ctx_data.tx.max_ctx_payload_length); + *payload_length, cip_header_size + s->ctx_data.tx.max_ctx_payload_length); return -EIO; } - if (!(s->flags & CIP_NO_HEADER)) { + if (cip_header_size > 0) { cip_header = ctx_header + 2; err = check_cip_header(s, cip_header, *payload_length, data_blocks, data_block_counter, syt); -- cgit v1.2.3-58-ga151 From 1be4f21d9984fa9835fae5411a29465dc5aece6f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 13 May 2021 21:56:51 +0900 Subject: ALSA: firewire-lib: fix calculation for size of IR context payload The quadlets for CIP header is handled as a part of IR context header, thus it doesn't join in IR context payload. However current calculation includes the quadlets in IR context payload. Cc: Fixes: f11453c7cc01 ("ALSA: firewire-lib: use 16 bytes IR context header to separate CIP header") Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210513125652.110249-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index b53971bf4b90..73aff017dc9a 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1071,23 +1071,22 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, s->data_block_counter = 0; } - /* initialize packet buffer */ + // initialize packet buffer. + max_ctx_payload_size = amdtp_stream_get_max_payload(s); if (s->direction == AMDTP_IN_STREAM) { dir = DMA_FROM_DEVICE; type = FW_ISO_CONTEXT_RECEIVE; - if (!(s->flags & CIP_NO_HEADER)) + if (!(s->flags & CIP_NO_HEADER)) { + max_ctx_payload_size -= 8; ctx_header_size = IR_CTX_HEADER_SIZE_CIP; - else + } else { ctx_header_size = IR_CTX_HEADER_SIZE_NO_CIP; - - max_ctx_payload_size = amdtp_stream_get_max_payload(s) - - ctx_header_size; + } } else { dir = DMA_TO_DEVICE; type = FW_ISO_CONTEXT_TRANSMIT; ctx_header_size = 0; // No effect for IT context. - max_ctx_payload_size = amdtp_stream_get_max_payload(s); if (!(s->flags & CIP_NO_HEADER)) max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP; } -- cgit v1.2.3-58-ga151 From 814b43127f4ac69332e809152e30773941438aff Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 13 May 2021 21:56:52 +0900 Subject: ALSA: firewire-lib: fix amdtp_packet tracepoints event for packet_index field The snd_firewire_lib:amdtp_packet tracepoints event includes index of packet processed in a context handling. However in IR context, it is not calculated as expected. Cc: Fixes: 753e717986c2 ("ALSA: firewire-lib: use packet descriptor for IR context") Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210513125652.110249-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream-trace.h | 6 +++--- sound/firewire/amdtp-stream.c | 15 +++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream-trace.h b/sound/firewire/amdtp-stream-trace.h index 26e7cb555d3c..aa53c13b89d3 100644 --- a/sound/firewire/amdtp-stream-trace.h +++ b/sound/firewire/amdtp-stream-trace.h @@ -14,8 +14,8 @@ #include TRACE_EVENT(amdtp_packet, - TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int data_block_counter, unsigned int index), - TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, data_block_counter, index), + TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int data_block_counter, unsigned int packet_index, unsigned int index), + TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, data_block_counter, packet_index, index), TP_STRUCT__entry( __field(unsigned int, second) __field(unsigned int, cycle) @@ -48,7 +48,7 @@ TRACE_EVENT(amdtp_packet, __entry->payload_quadlets = payload_length / sizeof(__be32); __entry->data_blocks = data_blocks; __entry->data_block_counter = data_block_counter, - __entry->packet_index = s->packet_index; + __entry->packet_index = packet_index; __entry->irq = !!in_interrupt(); __entry->index = index; ), diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 73aff017dc9a..e0faa6601966 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -526,7 +526,7 @@ static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, } trace_amdtp_packet(s, cycle, cip_header, payload_length, data_blocks, - data_block_counter, index); + data_block_counter, s->packet_index, index); } static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, @@ -630,7 +630,7 @@ static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, unsigned int *payload_length, unsigned int *data_blocks, unsigned int *data_block_counter, - unsigned int *syt, unsigned int index) + unsigned int *syt, unsigned int packet_index, unsigned int index) { const __be32 *cip_header; unsigned int cip_header_size; @@ -668,7 +668,7 @@ static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, } trace_amdtp_packet(s, cycle, cip_header, *payload_length, *data_blocks, - *data_block_counter, index); + *data_block_counter, packet_index, index); return err; } @@ -707,12 +707,13 @@ static int generate_device_pkt_descs(struct amdtp_stream *s, unsigned int packets) { unsigned int dbc = s->data_block_counter; + unsigned int packet_index = s->packet_index; + unsigned int queue_size = s->queue_size; int i; int err; for (i = 0; i < packets; ++i) { struct pkt_desc *desc = descs + i; - unsigned int index = (s->packet_index + i) % s->queue_size; unsigned int cycle; unsigned int payload_length; unsigned int data_blocks; @@ -721,7 +722,7 @@ static int generate_device_pkt_descs(struct amdtp_stream *s, cycle = compute_cycle_count(ctx_header[1]); err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length, - &data_blocks, &dbc, &syt, i); + &data_blocks, &dbc, &syt, packet_index, i); if (err < 0) return err; @@ -729,13 +730,15 @@ static int generate_device_pkt_descs(struct amdtp_stream *s, desc->syt = syt; desc->data_blocks = data_blocks; desc->data_block_counter = dbc; - desc->ctx_payload = s->buffer.packets[index].buffer; + desc->ctx_payload = s->buffer.packets[packet_index].buffer; if (!(s->flags & CIP_DBC_IS_END_EVENT)) dbc = (dbc + desc->data_blocks) & 0xff; ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header); + + packet_index = (packet_index + 1) % queue_size; } s->data_block_counter = dbc; -- cgit v1.2.3-58-ga151 From 1d5cfca286178ce81fb0c8a5f5777ef123cd69e4 Mon Sep 17 00:00:00 2001 From: PeiSen Hou Date: Fri, 14 May 2021 12:50:48 +0200 Subject: ALSA: hda/realtek: Add some CLOVE SSIDs of ALC293 Fix "use as headset mic, without its own jack detect" problen. Signed-off-by: PeiSen Hou Cc: Link: https://lore.kernel.org/r/d0746eaf29f248a5acc30313e3ba4f99@realtek.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3e269de84079..552e2cb73291 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8385,12 +8385,19 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x50b8, "Clevo NK50SZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x50d5, "Clevo NP50D5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x50f0, "Clevo NH50A[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50f2, "Clevo NH50E[PR]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x50f3, "Clevo NH58DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50f5, "Clevo NH55EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50f6, "Clevo NH55DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x5101, "Clevo S510WU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x5157, "Clevo W517GU1", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x51a1, "Clevo NS50MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x70f3, "Clevo NH77DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -8408,9 +8415,17 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x8a51, "Clevo NH70RCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8d50, "Clevo NH55RCQ-M", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x951d, "Clevo N950T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x9600, "Clevo N960K[PR]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x961d, "Clevo N960S[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x971d, "Clevo N970T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL53RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xa600, "Clevo NL5XNU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xb018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xb019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xb022, "Clevo NH77D[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xc018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xc019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xc022, "Clevo NH77[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS), SND_PCI_QUIRK(0x17aa, 0x1048, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), -- cgit v1.2.3-58-ga151 From c1f0616124c455c5c762b6f123e40bba5df759e6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 16 May 2021 18:17:55 +0200 Subject: ALSA: intel8x0: Don't update period unless prepared The interrupt handler of intel8x0 calls snd_intel8x0_update() whenever the hardware sets the corresponding status bit for each stream. This works fine for most cases as long as the hardware behaves properly. But when the hardware gives a wrong bit set, this leads to a zero- division Oops, and reportedly, this seems what happened on a VM. For fixing the crash, this patch adds a internal flag indicating that the stream is ready to be updated, and check it (as well as the flag being in suspended) to ignore such spurious update. Cc: Reported-and-tested-by: Sergey Senozhatsky Link: https://lore.kernel.org/r/s5h5yzi7uh0.wl-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 35903d1a1cbd..5b124c4ad572 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -331,6 +331,7 @@ struct ichdev { unsigned int ali_slot; /* ALI DMA slot */ struct ac97_pcm *pcm; int pcm_open_flag; + unsigned int prepared:1; unsigned int suspended: 1; }; @@ -691,6 +692,9 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich int status, civ, i, step; int ack = 0; + if (!ichdev->prepared || ichdev->suspended) + return; + spin_lock_irqsave(&chip->reg_lock, flags); status = igetbyte(chip, port + ichdev->roff_sr); civ = igetbyte(chip, port + ICH_REG_OFF_CIV); @@ -881,6 +885,7 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream, if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; + ichdev->prepared = 0; } err = snd_ac97_pcm_open(ichdev->pcm, params_rate(hw_params), params_channels(hw_params), @@ -902,6 +907,7 @@ static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream) if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; + ichdev->prepared = 0; } return 0; } @@ -976,6 +982,7 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; } snd_intel8x0_setup_periods(chip, ichdev); + ichdev->prepared = 1; return 0; } -- cgit v1.2.3-58-ga151 From 9f079c1bdc9087842dc5ac9d81b1d7f2578e81ce Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 18 May 2021 10:25:10 +0900 Subject: ALSA: dice: disable double_pcm_frames mode for M-Audio Profire 610, 2626 and Avid M-Box 3 Pro ALSA dice driver detects jumbo payload at high sampling transfer frequency for below models: * Avid M-Box 3 Pro * M-Audio Profire 610 * M-Audio Profire 2626 Although many DICE-based devices have a quirk at high sampling transfer frequency to multiplex double number of PCM frames into data block than the number in IEC 61883-1/6, the above devices are just compliant to IEC 61883-1/6. This commit disables the mode of double_pcm_frames for the models. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210518012510.37126-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-pcm.c | 4 ++-- sound/firewire/dice/dice-stream.c | 2 +- sound/firewire/dice/dice.c | 24 ++++++++++++++++++++++++ sound/firewire/dice/dice.h | 3 ++- 4 files changed, 29 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index af8a90ee40f3..a69ca1111b03 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -218,7 +218,7 @@ static int pcm_open(struct snd_pcm_substream *substream) if (frames_per_period > 0) { // For double_pcm_frame quirk. - if (rate > 96000) { + if (rate > 96000 && !dice->disable_double_pcm_frames) { frames_per_period *= 2; frames_per_buffer *= 2; } @@ -273,7 +273,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, mutex_lock(&dice->mutex); // For double_pcm_frame quirk. - if (rate > 96000) { + if (rate > 96000 && !dice->disable_double_pcm_frames) { events_per_period /= 2; events_per_buffer /= 2; } diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 1a14c083e8ce..c4dfe76500c2 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -181,7 +181,7 @@ static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream, // as 'Dual Wire'. // For this quirk, blocking mode is required and PCM buffer size should // be aligned to SYT_INTERVAL. - double_pcm_frames = rate > 96000; + double_pcm_frames = (rate > 96000 && !dice->disable_double_pcm_frames); if (double_pcm_frames) { rate /= 2; pcm_chs *= 2; diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 107a81691f0e..239d164b0eea 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -21,6 +21,7 @@ MODULE_LICENSE("GPL v2"); #define OUI_SSL 0x0050c2 // Actually ID reserved by IEEE. #define OUI_PRESONUS 0x000a92 #define OUI_HARMAN 0x000fd7 +#define OUI_AVID 0x00a07e #define DICE_CATEGORY_ID 0x04 #define WEISS_CATEGORY_ID 0x00 @@ -222,6 +223,14 @@ static int dice_probe(struct fw_unit *unit, (snd_dice_detect_formats_t)entry->driver_data; } + // Below models are compliant to IEC 61883-1/6 and have no quirk at high sampling transfer + // frequency. + // * Avid M-Box 3 Pro + // * M-Audio Profire 610 + // * M-Audio Profire 2626 + if (entry->vendor_id == OUI_MAUDIO || entry->vendor_id == OUI_AVID) + dice->disable_double_pcm_frames = true; + spin_lock_init(&dice->lock); mutex_init(&dice->mutex); init_completion(&dice->clock_accepted); @@ -278,7 +287,22 @@ static void dice_bus_reset(struct fw_unit *unit) #define DICE_INTERFACE 0x000001 +#define DICE_DEV_ENTRY_TYPICAL(vendor, model, data) \ + { \ + .match_flags = IEEE1394_MATCH_VENDOR_ID | \ + IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | \ + IEEE1394_MATCH_VERSION, \ + .vendor_id = (vendor), \ + .model_id = (model), \ + .specifier_id = (vendor), \ + .version = DICE_INTERFACE, \ + .driver_data = (kernel_ulong_t)(data), \ + } + static const struct ieee1394_device_id dice_id_table[] = { + // Avid M-Box 3 Pro. To match in probe function. + DICE_DEV_ENTRY_TYPICAL(OUI_AVID, 0x000004, snd_dice_detect_extension_formats), /* M-Audio Profire 2626 has a different value in version field. */ { .match_flags = IEEE1394_MATCH_VENDOR_ID | diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index adc6f7c84460..3c967d1b3605 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -109,7 +109,8 @@ struct snd_dice { struct fw_iso_resources rx_resources[MAX_STREAMS]; struct amdtp_stream tx_stream[MAX_STREAMS]; struct amdtp_stream rx_stream[MAX_STREAMS]; - bool global_enabled; + bool global_enabled:1; + bool disable_double_pcm_frames:1; struct completion clock_accepted; unsigned int substreams_counter; -- cgit v1.2.3-58-ga151 From 4c6fe8c547e3c9e8c15dabdd23c569ee0df3adb1 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 18 May 2021 10:26:12 +0900 Subject: ALSA: dice: fix stream format for TC Electronic Konnekt Live at high sampling transfer frequency At high sampling transfer frequency, TC Electronic Konnekt Live transfers/receives 6 audio data frames in multi bit linear audio data channel of data block in CIP payload. Current hard-coded stream format is wrong. Cc: Fixes: f1f0f330b1d0 ("ALSA: dice: add parameters of stream formats for models produced by TC Electronic") Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210518012612.37268-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-tcelectronic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-tcelectronic.c b/sound/firewire/dice/dice-tcelectronic.c index a8875d24ba2a..43a3bcb15b3d 100644 --- a/sound/firewire/dice/dice-tcelectronic.c +++ b/sound/firewire/dice/dice-tcelectronic.c @@ -38,8 +38,8 @@ static const struct dice_tc_spec konnekt_24d = { }; static const struct dice_tc_spec konnekt_live = { - .tx_pcm_chs = {{16, 16, 16}, {0, 0, 0} }, - .rx_pcm_chs = {{16, 16, 16}, {0, 0, 0} }, + .tx_pcm_chs = {{16, 16, 6}, {0, 0, 0} }, + .rx_pcm_chs = {{16, 16, 6}, {0, 0, 0} }, .has_midi = true, }; -- cgit v1.2.3-58-ga151 From 05ca447630334c323c9e2b788b61133ab75d60d3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 May 2021 10:39:39 +0200 Subject: ALSA: line6: Fix racy initialization of LINE6 MIDI The initialization of MIDI devices that are found on some LINE6 drivers are currently done in a racy way; namely, the MIDI buffer instance is allocated and initialized in each private_init callback while the communication with the interface is already started via line6_init_cap_control() call before that point. This may lead to Oops in line6_data_received() when a spurious event is received, as reported by syzkaller. This patch moves the MIDI initialization to line6_init_cap_control() as well instead of the too-lately-called private_init for avoiding the race. Also this reduces slightly more lines, so it's a win-win change. Reported-by: syzbot+0d2b3feb0a2887862e06@syzkallerlkml..appspotmail.com Link: https://lore.kernel.org/r/000000000000a4be9405c28520de@google.com Link: https://lore.kernel.org/r/20210517132725.GA50495@hyeyoo Cc: Hyeonggon Yoo <42.hyeyoo@gmail.com> Cc: Link: https://lore.kernel.org/r/20210518083939.1927-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 4 ++++ sound/usb/line6/pod.c | 5 ----- sound/usb/line6/variax.c | 6 ------ 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index a030dd65eb28..9602929b7de9 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -699,6 +699,10 @@ static int line6_init_cap_control(struct usb_line6 *line6) line6->buffer_message = kmalloc(LINE6_MIDI_MESSAGE_MAXLEN, GFP_KERNEL); if (!line6->buffer_message) return -ENOMEM; + + ret = line6_init_midi(line6); + if (ret < 0) + return ret; } else { ret = line6_hwdep_init(line6); if (ret < 0) diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index cd44cb5f1310..16e644330c4d 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -376,11 +376,6 @@ static int pod_init(struct usb_line6 *line6, if (err < 0) return err; - /* initialize MIDI subsystem: */ - err = line6_init_midi(line6); - if (err < 0) - return err; - /* initialize PCM subsystem: */ err = line6_init_pcm(line6, &pod_pcm_properties); if (err < 0) diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c index ed158f04de80..c2245aa93b08 100644 --- a/sound/usb/line6/variax.c +++ b/sound/usb/line6/variax.c @@ -159,7 +159,6 @@ static int variax_init(struct usb_line6 *line6, const struct usb_device_id *id) { struct usb_line6_variax *variax = line6_to_variax(line6); - int err; line6->process_message = line6_variax_process_message; line6->disconnect = line6_variax_disconnect; @@ -172,11 +171,6 @@ static int variax_init(struct usb_line6 *line6, if (variax->buffer_activate == NULL) return -ENOMEM; - /* initialize MIDI subsystem: */ - err = line6_init_midi(&variax->line6); - if (err < 0) - return err; - /* initiate startup procedure: */ schedule_delayed_work(&line6->startup_work, msecs_to_jiffies(VARIAX_STARTUP_DELAY1)); -- cgit v1.2.3-58-ga151